From 2f24582978112bccc072c8d33b43050a4f554290 Mon Sep 17 00:00:00 2001 From: agc Date: Sun, 21 Jun 2009 21:20:30 +0000 Subject: [PATCH] Move the iSCSI target and initiator source across from dist/iscsi to external/bsd/iscsi --- external/bsd/iscsi/dist/doc/COMPATIBILITY | 42 + external/bsd/iscsi/dist/doc/FAQ | 224 + .../iscsi/dist/doc/HOWTO-iSCSI-encrypt.txt | 245 + .../bsd/iscsi/dist/doc/HOWTO-iSCSI-target.txt | 67 + external/bsd/iscsi/dist/doc/PERFORMANCE | 64 + external/bsd/iscsi/dist/doc/README | 188 + external/bsd/iscsi/dist/doc/README_OSD | 58 + external/bsd/iscsi/dist/doc/license | 31 + external/bsd/iscsi/dist/include/compat.h | 101 + external/bsd/iscsi/dist/include/conffile.h | 84 + external/bsd/iscsi/dist/include/config.h | 218 + external/bsd/iscsi/dist/include/config.h.in | 217 + external/bsd/iscsi/dist/include/defs.h | 94 + external/bsd/iscsi/dist/include/device.h | 52 + external/bsd/iscsi/dist/include/driver.h | 157 + external/bsd/iscsi/dist/include/initiator.h | 145 + external/bsd/iscsi/dist/include/iscsi-md5.h | 63 + external/bsd/iscsi/dist/include/iscsi.h | 536 ++ external/bsd/iscsi/dist/include/iscsiutil.h | 489 ++ external/bsd/iscsi/dist/include/osd.h | 149 + external/bsd/iscsi/dist/include/osd_ops.h | 61 + external/bsd/iscsi/dist/include/parameters.h | 170 + .../bsd/iscsi/dist/include/scsi_cmd_codes.h | 153 + external/bsd/iscsi/dist/include/so.h | 56 + external/bsd/iscsi/dist/include/storage.h | 96 + external/bsd/iscsi/dist/include/target.h | 121 + external/bsd/iscsi/dist/include/tests.h | 52 + external/bsd/iscsi/dist/src/Makefile.in | 85 + external/bsd/iscsi/dist/src/TODO | 49 + external/bsd/iscsi/dist/src/conffile.c | 281 + external/bsd/iscsi/dist/src/configure | 5870 +++++++++++++++++ external/bsd/iscsi/dist/src/configure.ac | 40 + external/bsd/iscsi/dist/src/disk.c | 1298 ++++ external/bsd/iscsi/dist/src/driver.c | 652 ++ external/bsd/iscsi/dist/src/initiator.c | 3246 +++++++++ external/bsd/iscsi/dist/src/install-sh | 238 + external/bsd/iscsi/dist/src/iscsi-harness.c | 219 + external/bsd/iscsi/dist/src/iscsi-target.8 | 124 + external/bsd/iscsi/dist/src/iscsi-target.c | 166 + external/bsd/iscsi/dist/src/iscsi.c | 1378 ++++ external/bsd/iscsi/dist/src/md5c.c | 368 ++ external/bsd/iscsi/dist/src/md5hl.c | 122 + external/bsd/iscsi/dist/src/netmask.c | 172 + external/bsd/iscsi/dist/src/osd-target.c | 181 + external/bsd/iscsi/dist/src/osd.c | 662 ++ external/bsd/iscsi/dist/src/osd_ops.c | 416 ++ external/bsd/iscsi/dist/src/osdfs.c | 1076 +++ external/bsd/iscsi/dist/src/parameters.c | 1291 ++++ external/bsd/iscsi/dist/src/snprintf.c | 665 ++ external/bsd/iscsi/dist/src/so.c | 1060 +++ external/bsd/iscsi/dist/src/start_osd | 5 + external/bsd/iscsi/dist/src/stop_osd | 5 + external/bsd/iscsi/dist/src/storage.c | 424 ++ external/bsd/iscsi/dist/src/strlcpy.c | 68 + external/bsd/iscsi/dist/src/strtoll.c | 60 + external/bsd/iscsi/dist/src/target.c | 1761 +++++ external/bsd/iscsi/dist/src/targets.5 | 179 + external/bsd/iscsi/dist/src/tests.c | 1229 ++++ external/bsd/iscsi/dist/src/usocktest.c | 378 ++ external/bsd/iscsi/dist/src/utest.c | 158 + external/bsd/iscsi/dist/src/util.c | 1296 ++++ external/bsd/iscsi/dist/src/uuid.c | 100 + 62 files changed, 29255 insertions(+) create mode 100644 external/bsd/iscsi/dist/doc/COMPATIBILITY create mode 100644 external/bsd/iscsi/dist/doc/FAQ create mode 100644 external/bsd/iscsi/dist/doc/HOWTO-iSCSI-encrypt.txt create mode 100644 external/bsd/iscsi/dist/doc/HOWTO-iSCSI-target.txt create mode 100644 external/bsd/iscsi/dist/doc/PERFORMANCE create mode 100644 external/bsd/iscsi/dist/doc/README create mode 100644 external/bsd/iscsi/dist/doc/README_OSD create mode 100644 external/bsd/iscsi/dist/doc/license create mode 100644 external/bsd/iscsi/dist/include/compat.h create mode 100644 external/bsd/iscsi/dist/include/conffile.h create mode 100644 external/bsd/iscsi/dist/include/config.h create mode 100644 external/bsd/iscsi/dist/include/config.h.in create mode 100644 external/bsd/iscsi/dist/include/defs.h create mode 100644 external/bsd/iscsi/dist/include/device.h create mode 100644 external/bsd/iscsi/dist/include/driver.h create mode 100644 external/bsd/iscsi/dist/include/initiator.h create mode 100644 external/bsd/iscsi/dist/include/iscsi-md5.h create mode 100644 external/bsd/iscsi/dist/include/iscsi.h create mode 100644 external/bsd/iscsi/dist/include/iscsiutil.h create mode 100644 external/bsd/iscsi/dist/include/osd.h create mode 100644 external/bsd/iscsi/dist/include/osd_ops.h create mode 100644 external/bsd/iscsi/dist/include/parameters.h create mode 100644 external/bsd/iscsi/dist/include/scsi_cmd_codes.h create mode 100644 external/bsd/iscsi/dist/include/so.h create mode 100644 external/bsd/iscsi/dist/include/storage.h create mode 100644 external/bsd/iscsi/dist/include/target.h create mode 100644 external/bsd/iscsi/dist/include/tests.h create mode 100644 external/bsd/iscsi/dist/src/Makefile.in create mode 100644 external/bsd/iscsi/dist/src/TODO create mode 100644 external/bsd/iscsi/dist/src/conffile.c create mode 100755 external/bsd/iscsi/dist/src/configure create mode 100644 external/bsd/iscsi/dist/src/configure.ac create mode 100644 external/bsd/iscsi/dist/src/disk.c create mode 100644 external/bsd/iscsi/dist/src/driver.c create mode 100644 external/bsd/iscsi/dist/src/initiator.c create mode 100755 external/bsd/iscsi/dist/src/install-sh create mode 100644 external/bsd/iscsi/dist/src/iscsi-harness.c create mode 100644 external/bsd/iscsi/dist/src/iscsi-target.8 create mode 100644 external/bsd/iscsi/dist/src/iscsi-target.c create mode 100644 external/bsd/iscsi/dist/src/iscsi.c create mode 100644 external/bsd/iscsi/dist/src/md5c.c create mode 100644 external/bsd/iscsi/dist/src/md5hl.c create mode 100644 external/bsd/iscsi/dist/src/netmask.c create mode 100644 external/bsd/iscsi/dist/src/osd-target.c create mode 100644 external/bsd/iscsi/dist/src/osd.c create mode 100644 external/bsd/iscsi/dist/src/osd_ops.c create mode 100644 external/bsd/iscsi/dist/src/osdfs.c create mode 100644 external/bsd/iscsi/dist/src/parameters.c create mode 100644 external/bsd/iscsi/dist/src/snprintf.c create mode 100644 external/bsd/iscsi/dist/src/so.c create mode 100644 external/bsd/iscsi/dist/src/start_osd create mode 100644 external/bsd/iscsi/dist/src/stop_osd create mode 100644 external/bsd/iscsi/dist/src/storage.c create mode 100644 external/bsd/iscsi/dist/src/strlcpy.c create mode 100644 external/bsd/iscsi/dist/src/strtoll.c create mode 100644 external/bsd/iscsi/dist/src/target.c create mode 100644 external/bsd/iscsi/dist/src/targets.5 create mode 100644 external/bsd/iscsi/dist/src/tests.c create mode 100644 external/bsd/iscsi/dist/src/usocktest.c create mode 100644 external/bsd/iscsi/dist/src/utest.c create mode 100644 external/bsd/iscsi/dist/src/util.c create mode 100644 external/bsd/iscsi/dist/src/uuid.c diff --git a/external/bsd/iscsi/dist/doc/COMPATIBILITY b/external/bsd/iscsi/dist/doc/COMPATIBILITY new file mode 100644 index 000000000000..6cd6e15c2da6 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/COMPATIBILITY @@ -0,0 +1,42 @@ +$NetBSD: COMPATIBILITY,v 1.1 2009/06/21 21:20:30 agc Exp $ + +The NetBSD iSCSI initiator has been tried with the following initiators: + +1. Microsoft iSCSI initiator, versions 1.xx and 2.03 +Tested by Alistair Crooks +Seems to work fine - instructions in place at +ftp://ftp.netbsd.org/pub/NetBSD/misc/agc/HOWTO-iSCSI-initiator.pdf +(This is the initiator that is used to test new releases) +Entry added: 26/10/2007 + +2. Solaris 10 Express 06/04 +Tested by Alistair Crooks +Only a small test case was tried +VPD83 functionality was added for this initiator +Entry added: 26/10/2007 + +3. IBM AIX 5.3 iSCSI initiator +Tested by Andreas +Information in +http://mail-index.netbsd.org/current-users/2007/10/12/0008.html +Entry added: 26/10/2007 + +4. Linux open-iscsi initiator +Tested by Mark Foster +No issues +http://mark.foster.cc/wiki/index.php/User:Fostermarkd/FreeBSD/iSCSI +Entry added: 24/12/2007 + +5. NetBSD iSCSI initiator +Tested by Alistair Crooks +Works fine - instructions in +http://mail-index.netbsd.org/netbsd-users/2007/11/10/0002.html +(This initiator receives the most testing with the NetBSD iSCSI target) +Entry added: 24/12/2007 + +Any information on other initiators tried (either positive or negative) +would be gratefully received. + +Alistair Crooks +agc@NetBSD.org +Last updated: 24/12/2007 diff --git a/external/bsd/iscsi/dist/doc/FAQ b/external/bsd/iscsi/dist/doc/FAQ new file mode 100644 index 000000000000..866e5ba8cc43 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/FAQ @@ -0,0 +1,224 @@ +iSCSI Frequently Asked Questions +================================ + +Q1. What is iSCSI? +================== + +A1. It's an IETF standard (RFC 3720) for remote access to block-level +storage. It can be thought of as similar to NFS, except that an NFS +server exports files; the iSCSI target exports blocks to the iSCSI +initiators, which are the clients. + + +Q2. What's the difference between an initiator and a target? +============================================================ + +A2. The target is the iSCSI server - it serves up blocks to the +clients, which are called initiators. Typically, initiators are part +of the operating system, since the operating system manages block +storage, presenting it to the user as file systems sitting on top of +the storage. + +Targets do not generally need to be part of the operating system, +indeed there is some flexibility to be gained by having targets as +part of the user-level daemons that are run. This means that +security credentials need not be buried in the kernel. + + +Q3. So how do I use it? +======================= + +A3. Firstly, you need to set up the iSCSI target. The target is +simply sitting there, waiting for requests for blocks. So we need to +configure the target with an area of storage for it to present to the +initiators. + +To set up the target, you need to edit the /etc/iscsi/targets file. +It has a certain layout, to provide a means of (a) mirroring and (b) +combining multiple areas to present one large contiguous area of +storage. This can be multiply-layered. + +The basic unit of storage is an extent. This can be either a file +or a device. The offset of the start of the extent to be presented +must be given, and also the length of the extent. + +A device is made up of one or more extents, and/or one or more +other devices. + +At the highest level, a target is what is presented to the initiator, +and is made up of one or more devices, and/or one or more extents. + +The simple example is as follows, consisting of one piece of storage +presented by one target: + + # extent file or device start length + extent0 /tmp/iscsi-target0 0 100MB + +will produce an extent of storage which is based on one file, +/tmp/iscsi-target0, which starts 0 bytes into the file, and is 100 MB +in length. The file will be created if it does not already exist. + + # target storage netmask + target0 extent0 0.0.0.0/0 + +That extent is then used in target0, and will be presented to an +initiator running on any host. + +Extents must be defined before they can be used, and extents cannot +be used more than once. + +Devices are used to combine extents or other devices. Device +definitions have the following format: + + # devices + device0 RAID1 extent0 extent1 + +A "RAID1" device behaves in much the same way that RAID1 devices work +in the storage arena - they mirror the original storage. There can be +any number of devices or extents in a RAID1 device, not just 2, but +each device or extent must be of the same size. + +A "RAID0" device combines the storage, to produce a larger area of +(virtually) "contiguous" storage. + +Devices must be defined before they can be used, and devices may not +be used more than once. + +A more detailed example would be as follows: + + # Complex file showing 3-way RAID1 (with RAID1 components), + # also using local and (NFS) remote components + + # extents + extent0 /iscsi/extents/0 0 100MB + extent1 /imports/remote1/iscsi/extents/0 0 100MB + extent2 /iscsi/extents/1 0 100MB + extent3 /imports/remote1/iscsi/extents/1 0 100MB + extent4 /iscsi/extents/2 0 100MB + extent5 /imports/remote1/iscsi/extents/2 0 100MB + extent6 /iscsi/extents/3 0 100GB + + # devices + device0 RAID1 extent0 extent1 + device1 RAID1 extent2 extent3 + device2 RAID1 extent4 extent5 + device3 RAID1 device0 device1 device2 + + # targets + target0 device3 10.4.0.0/16 + + # a target can be made from just an extent + target1 extent6 127.0.0.0/8 + +which will make 7 extents, 3 of them 100 MB in length and remote (via +NFS), and 3 of them 100 MB in length and local, and one of them large +(100 GB) and local. Three separate occurrences of a local and remote +100 MB extent are combined to make three RAID1 devices, and then those +three RAID1 devices are combined into another RAID1 device, and +presented as target0. + +The other extent is used to present a simple 100 GB of storage as +target1. + + +Q4. What about security? +========================= + +A4. A good question. RFC 3720 specifies CHAP, SRM and Kerberos as +methods of providing authentication and/or security. In practice, +it's whatever is provided by the initiator you are using which will +determine what authentication or security is used. + +If you want any form of security, it's probably best to use ssh port +forwarding for all your traffic if you're worried about security. +CHAP will only provide authentication, the other information will flow +across the network in clear. + + +Q5. Using the Microsoft initiator, I can't login with CHAP +=========================================================== + +A5. The 1.06 Microsoft initiator silently enforces a chap password +length of at least 12 characters. If you enter a password which is +less than that, your Discovery login will silently fail. + +Since CHAP provides very little authentication anyway, you are advised +not to use it - ssh port forwarding, and the use of tcp wrappers, +will do a much better job of protection. + + +Q6. What initiators work with the NetBSD iSCSI target? +====================================================== + +A6. The NetBSD target has been tested at various times with the Microsoft +iSCSI initiator, version 1.06 (which can be downloaded for free from +www.microsoft.com, but needs Windows XP Pro to work), and also with the +NetBSD test harness, which is provided, but not installed, in the same +place as the target. + + +Q7. What is the difference between Discovery and Normal login? +=============================================================== + +A7. On direct-attached storage, the kernel verifies what storage is +available, and assigns a device node to it. With iSCSI, storage can +come and go, and our proximity to the devices doesn't matter. So we +need to find a different method of finding out what iSCSI storage is +out there. + +This is done by a "Discovery" iSCSI session - the initiator logs in +to the target, finds out what storage is being presented, then logs +back out. This can be seen by the syslog entries: + + Feb 5 10:33:44 sys3 iscsi-target: > Discovery login from iqn.1991-05.com.microsoft:inspiron on 10.4.1.5 + Feb 5 10:33:44 sys3 iscsi-target: < Discovery logout from iqn.1991-05.com.microsoft:inspiron on 10.4.1.5 + +The initiator will then perform a "Normal" login session, which will +establish a session between the initiator and target. This is denoted +by the syslog entries: + + Feb 5 00:00:28 sys3 iscsi-target: > Discovery login from iqn.1993-03.org.NetBSD.iscsi-initiator:agc on 127.0.0.1 + Feb 5 00:00:28 sys3 iscsi-target: < Discovery logout from iqn.1993-03.org.NetBSD.iscsi-initiator:agc on 127.0.0.1 + Feb 5 00:00:28 sys3 iscsi-target: > Normal login from iqn.1993-03.org.NetBSD.iscsi-initiator:agc on 127.0.0.1 + Feb 5 00:05:32 sys3 iscsi-target: < Normal logout from iqn.1993-03.org.NetBSD.iscsi-initiator:agc on 127.0.0.1 + + +Q8. So what do I do to try it? +============================== + +A8. Perform the following steps: + +a) define the storage that you want to present in /etc/iscsi/targets +b) start the iSCSI target: /etc/rc.d/iscsi_target forcestart +c) use an initiator to point it at the machine you started it on + + +Q9. Why does the test harness not work properly? +================================================ + +A9. Firstly, you should be invoking the test harness as + + iscsi-harness -n 3 -h localhost + +where the 'n' option is the number of iterations to perform, and the +'h' parameter is the name or address of the machine where the +iscsi-target is running. + +If the harness was invoked properly, check any error messages which +the test harness sends: + +If one of them looks like: + + No matching user configuration entry for `agc' was found + Please add an entry for `agc' to `/etc/iscsi/auths' + +(where "agc" is substituted for the name of the user who was running +the test harness), then please do as suggested. The iSCSI test harness +tests, amongst other things, the CHAP authentication process, and so +CHAP credentials for that user are needed. + + + +Alistair Crooks +agc@NetBSD.org +Wed Feb 8 07:21:56 GMT 2006 diff --git a/external/bsd/iscsi/dist/doc/HOWTO-iSCSI-encrypt.txt b/external/bsd/iscsi/dist/doc/HOWTO-iSCSI-encrypt.txt new file mode 100644 index 000000000000..dd9b35454c42 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/HOWTO-iSCSI-encrypt.txt @@ -0,0 +1,245 @@ +Encrypted iSCSI Devices on NetBSD +================================= + +This document shows how to set up and run an encrypted iSCSI device on +NetBSD. Encryption of devices can be used for maintaining privacy on +devices located remotely, possibly on co-located hardware, for +instance, or on machines which could be stolen, or to which others +could gain access. + +To encrypt the iSCSI device, we use the NetBSD iSCSI initiator, +available in NetBSD-current, and the standard cgd device. In all, +setting up an encrypted device in this manner should take less than 15 +minutes, even for someone unfamiliar with iSCSI or cgd. + +The approach is to layer a vnd on top of the "storage" file presented +by the iSCSI target. This is exactly the same as normal. On top of that +vnd, we layer a cgd device, which ensures that all data is encrypted +on the iSCSI device. + + +1. Device Initialisation +======================== + +This first section shows how to initialise the device, a one-time +operation. + +Firstly, the initiator is started, pointing at the machine which is +presenting the iSCSI storage (i.e. the machine on which the iSCSI +target is running). In this example, the target is running on the +same machine as the initiator (a laptop called, in a moment of +inspiration, inspiron1300). A 50 MB iSCSI target is being presented +as target1. + + # obj/iscsifs -u agc -h inspiron1300.wherever.co.uk /mnt & + [1] 11196 + # + # df + Filesystem 1K-blocks Used Avail %Cap Mounted on + /dev/dk0 28101396 20862004 5834324 78% / + kernfs 1 1 0 100% /kern + procfs 4 4 0 100% /proc + ptyfs 1 1 0 100% /dev/pts + /dev/puffs 0 0 0 100% /mnt + # + +Looking at the last line, we can see that the initiator is running +via the puffs device. + +We now add a vnd device on top of the storage which the target is +presenting: + + # vnconfig vnd0 /mnt/inspiron1300.wherever.co.uk/target1/storage + # + +We now add a disklabel, which is offset 63 blocks into the iSCSI device. +This is so that the encrypted device which we shall put on top of the vnd +does not clash with the vnd's label. Chapter 14 of the NetBSD guide, on +setting up a cgd device, recommends that the cgd's type be "ccd". + + # disklabel -e vnd0 + + # /dev/rvnd0d: + type: vnd + disk: vnd + label: fictitious + flags: + bytes/sector: 512 + sectors/track: 32 + tracks/cylinder: 64 + sectors/cylinder: 2048 + cylinders: 50 + total sectors: 102400 + rpm: 3600 + interleave: 1 + trackskew: 0 + cylinderskew: 0 + headswitch: 0 # microseconds + track-to-track seek: 0 # microseconds + drivedata: 0 + + 4 partitions: + # size offset fstype [fsize bsize cpg/sgs] + a: 102336 63 ccd 2048 16384 28360 # (Cyl. 0 - 49) + d: 102400 0 unused 0 0 # (Cyl. 0 - 49) + ~ + === EdDk.a11098a [confmode] is /tmp/EdDk.a11098a ================(22,11) 95% == + # + +We now set up the cgd device, pointing it at the vnd device. + + # priv cgdconfig -s cgd0 /dev/vnd0a aes-cbc 128 < /dev/urandom + # + +and then zero the cgd device's storage. + + # dd if=/dev/zero of=/dev/rcgd0d bs=32k + dd: /dev/rcgd0d: Invalid argument + 1601+0 records in + 1600+0 records out + 52428800 bytes transferred in 16.633 secs (3152095 bytes/sec) + # + +We now unconfigure the cgd device. + + # cgdconfig -u cgd0 + # + +and then write using the disklabel verification method onto the cgd. Sometimes, +this process does not always complete properly, and so it has to be repeated. + + # cgdconfig -g -V disklabel -o /etc/cgd/vnd0a aes-cbc 256 + cgdconfig: could not calibrate pkcs5_pbkdf2 + cgdconfig: Failed to generate defaults for keygen + # cgdconfig -g -V disklabel -o /etc/cgd/vnd0a aes-cbc 256 + # + +Now we have to add the password to the cgd device + + # cgdconfig -V re-enter cgd0 /dev/vnd0a + /dev/vnd0a's passphrase: + re-enter device's passphrase: + # + +and disklabel inside the cgd itself: + + # disklabel -I -e cgd0 + + # /dev/rcgd0d: + type: cgd + disk: cgd + label: fictitious + flags: + bytes/sector: 512 + sectors/track: 2048 + tracks/cylinder: 1 + sectors/cylinder: 2048 + cylinders: 49 + total sectors: 102336 + rpm: 3600 + interleave: 1 + trackskew: 0 + cylinderskew: 0 + headswitch: 0 # microseconds + track-to-track seek: 0 # microseconds + drivedata: 0 + + 4 partitions: + # size offset fstype [fsize bsize cpg/sgs] + a: 102336 0 4.2BSD 2048 16384 28360 # (Cyl. 0 - 49*) + d: 102336 0 unused 0 0 # (Cyl. 0 - 49*) + ~ + ~ + === EdDk.a11253a [confmode] is /tmp/EdDk.a11253a =================(22,53) 95% == + # + +Having placed a disklabel inside the cgd, we can now make a filesystem on there: + + # newfs /dev/rcgd0a + /dev/rcgd0a: 50.0MB (102336 sectors) block size 8192, fragment size 1024 + using 4 cylinder groups of 12.49MB, 1599 blks, 3136 inodes. + super-block backups (for fsck_ffs -b #) at: + 32, 25616, 51200, 76784, + # + +we can then mount the new file system in the cgd on the /iscsi mount +point: + + # df + Filesystem 1K-blocks Used Avail %Cap Mounted on + /dev/dk0 28101396 20910216 5786112 78% / + kernfs 1 1 0 100% /kern + procfs 4 4 0 100% /proc + ptyfs 1 1 0 100% /dev/pts + /dev/puffs 0 0 0 100% /mnt + # mount /dev/cgd0a /iscsi + # df + Filesystem 1K-blocks Used Avail %Cap Mounted on + /dev/dk0 28101396 20910216 5786112 78% / + kernfs 1 1 0 100% /kern + procfs 4 4 0 100% /proc + ptyfs 1 1 0 100% /dev/pts + /dev/puffs 0 0 0 100% /mnt + /dev/cgd0a 49519 1 47043 0% /iscsi + # + +The new file system, mounted on /iscsi, can now be used as normal. + + +2. Unmounting the Encrypted Device +================================== + +The device can be freed up using the following commands: + + # umount /iscsi + # cgdconfig -u cgd0 + # vnconfig -u vnd0 + + +3. Normal Usage +=============== + +In normal usage, the device can be mounted. Firstly, the initiator +must be configured to connect to the device: + + # vnconfig vnd0 /mnt/inspiron1300.wherever.co.uk/target1/storage + # cgdconfig cgd0 /dev/vnd0a + /dev/vnd0a's passphrase: + # + +I'm using dk devices on this machine, so I now have to access the cgd +device using the dk that was assigned in the cgdconfig step. If I +wasn't using dk devices, then I'd use the cgd device. + +!!!SO PICK ONE OF THE FOLLOWING TWO COMMANDS!!! + + # mount /dev/cgd0a /iscsi OR + # mount /dev/dk3 /iscsi + # ls -al /iscsi + total 3 + drwxr-xr-x 2 root wheel 512 Jan 1 1970 . + drwxr-xr-x 35 root wheel 1536 Jan 5 08:59 .. + # df + Filesystem 1K-blocks Used Avail %Cap Mounted on + /dev/dk0 28101396 20910100 5786228 78% / + kernfs 1 1 0 100% /kern + procfs 4 4 0 100% /proc + ptyfs 1 1 0 100% /dev/pts + /dev/puffs 0 0 0 100% /mnt + /dev/dk3 49519 1 47043 0% /iscsi + # + + +4. Conclusion +============= + +An iSCSI disk can be in a location over which complete control +cannot be assured. In order to ensure privacy, the cgd device +can be used to encrypt the data on the iSCSI device. + +This document has shown how to set up a cgd device on top of the +iSCSI device, and how to mount and unmount on a regular basis. + + +Alistair Crooks +Sat Jan 5 22:08:32 GMT 2008 diff --git a/external/bsd/iscsi/dist/doc/HOWTO-iSCSI-target.txt b/external/bsd/iscsi/dist/doc/HOWTO-iSCSI-target.txt new file mode 100644 index 000000000000..74f9e428a451 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/HOWTO-iSCSI-target.txt @@ -0,0 +1,67 @@ +The NetBSD iSCSI HOWTO +====================== + +This document is intended to tell you how to set up an iSCSI target on +a NetBSD host, so that block storage can be presented to the network. +It then goes on to show how to connect to that storage using the +Microsoft iSCSI initiator (version 1.06, running on Windows XP). + + +1. Configuring the NetBSD iSCSI target +====================================== + +1.1. Decide what storage will be presented + +The iSCSI target serves up block storage to clients on the network. +These clients are called "initiators". Firstly, we must decide how +much storage we are going to serve up, and for this document, we +will serve up 100 MB. It will be in a file called /tmp/iscsi-target0. + +So we must first edit /etc/iscsi/targets, so that it contains the +following lines: + + # extent file or device start length + extent0 /tmp/iscsi-target0 0 100MB + + # target flags storage netmask + target0 rw extent0 0/0 + +The extent definition tells the file which is used as backing +store. It is persistent, so that the target can serve up the +same storage after reboot. Its length is 100 MB, and there is +no offset into the file for the start of the extent. (An offset +is useful if you need to skip over MBRs, or disklabels). + +The extent is mounted read-write by "target0", and is served up +to any host (the 0.0.0.0/0 netmask). + +1.2. Start the iscsi-target + +Issue the command: + + # /etc/rc.d/iscsi_target forcestart + +and you should see the messages from the iscsi-target: + + Starting iscsi_target. + Reading configuration from `/etc/iscsi/targets' + target0:rw:0/0 + extent0:/tmp/iscsi-target0:0:104857600 + DISK: 1 logical units (204800 blocks, 512 bytes/block), type iscsi fs + DISK: LU 0: 100 MB disk storage for "target0" + TARGET: TargetName is iqn.1994-04.org.netbsd.iscsi-target + +1.3 You're done! + +Congratulations - your iSCSI target is now up and running and +serving blocks to initiators. + + + +2. Configuring the Microsoft iSCSI initiator, version 1.06 +========================================================== + +Please see the relevant documentation on setting up iSCSI initiators. + +Alistair Crooks +Sun Jan 6 10:38:19 GMT 2008 diff --git a/external/bsd/iscsi/dist/doc/PERFORMANCE b/external/bsd/iscsi/dist/doc/PERFORMANCE new file mode 100644 index 000000000000..15d2705d6726 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/PERFORMANCE @@ -0,0 +1,64 @@ + +---------------------- +USER LEVEL PERFORMANCE +---------------------- + +If your system is correctly configured with GbE and a GHz processor, +you should expect user level iSCSI performance similar to the following. +This output was generated by running utest against a target running uramdisk. + +##BEGIN DEVICE-SPECIFIC TESTS[0:0]## +read_capacity PASSED +write_read_test PASSED +integrity_test PASSED +SCSI op 0x28: 1000 iters in 0.24 sec --> 244.38 usec +SCSI op 0x2a: 1000 iters in 0.25 sec --> 249.78 usec +SCSI op 0x25: 1000 iters in 0.25 sec --> 250.12 usec +8192 bytes/request: 8 MB written in 0.33 seconds --> 24.35 MB/sec +16384 bytes/request: 8 MB written in 0.30 seconds --> 26.74 MB/sec +32768 bytes/request: 8 MB written in 0.20 seconds --> 39.06 MB/sec +65536 bytes/request: 8 MB written in 0.15 seconds --> 52.95 MB/sec +131072 bytes/request: 8 MB written in 0.12 seconds --> 66.74 MB/sec +262144 bytes/request: 8 MB written in 0.10 seconds --> 77.76 MB/sec +8192 bytes/request: 8 MB read in 0.37 seconds --> 21.34 MB/sec +16384 bytes/request: 8 MB read in 0.19 seconds --> 41.47 MB/sec +32768 bytes/request: 8 MB read in 0.13 seconds --> 62.04 MB/sec +65536 bytes/request: 8 MB read in 0.11 seconds --> 70.99 MB/sec +131072 bytes/request: 8 MB read in 0.10 seconds --> 83.62 MB/sec +262144 bytes/request: 8 MB read in 0.09 seconds --> 92.38 MB/sec +##END DEVICE-SPECIFIC TESTS[0:0]## + +------------------------ +KERNEL LEVEL PERFORMANCE +------------------------ + +Kernel level performance (ktest to kramdisk.o) should be similar to the output +shown below. Note that this test does not go through the linux storage stack, +but is rather a kernel level iSCSI test with no attached filesystem or SCSI +midlayer. + +This output was generated by installing the module intel_iscsi.o and then +running "ktest " where is one of your iscsi devices (e.g, +/dev/sdb). Although you specify a single device on the command line, all +target devices are tested. + +##BEGIN DEVICE-SPECIFIC TESTS[0:0]## +read_capacity PASSED +write_read_test PASSED +integrity_test PASSED +SCSI op 0x28: 1000 iters in 25 jiffies --> 250 usec +SCSI op 0x2a: 1000 iters in 25 jiffies --> 250 usec +SCSI op 0x25: 1000 iters in 25 jiffies --> 250 usec +8192 bytes/request: 8388608 bytes written in 38 jiffies --> ~ 21 MB/second +16384 bytes/request: 8388608 bytes written in 38 jiffies --> ~ 21 MB/second +32768 bytes/request: 8388608 bytes written in 23 jiffies --> ~ 34 MB/second +65536 bytes/request: 8388608 bytes written in 16 jiffies --> ~ 50 MB/second +131072 bytes/request: 8388608 bytes written in 12 jiffies --> ~ 66 MB/second +262144 bytes/request: 8388608 bytes written in 10 jiffies --> ~ 79 MB/second +8192 bytes/request: 8388608 bytes read in 26 jiffies --> ~ 30 MB/second +16384 bytes/request: 8388608 bytes read in 20 jiffies --> ~ 39 MB/second +32768 bytes/request: 8388608 bytes read in 12 jiffies --> ~ 66 MB/second +65536 bytes/request: 8388608 bytes read in 12 jiffies --> ~ 66 MB/second +131072 bytes/request: 8388608 bytes read in 10 jiffies --> ~ 79 MB/second +262144 bytes/request: 8388608 bytes read in 9 jiffies --> ~ 88 MB/second +##END DEVICE-SPECIFIC TESTS[0:0]## diff --git a/external/bsd/iscsi/dist/doc/README b/external/bsd/iscsi/dist/doc/README new file mode 100644 index 000000000000..c1329bcff260 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/README @@ -0,0 +1,188 @@ + +--------------------------------------- +Intel iSCSI v20 Reference Implementation +--------------------------------------- + +This is a software implementation of iSCSI v20. Included in this distribution +are both host and target mode drivers with built in conformance and performance +tests, and sockets tests that can be used to simulate TCP traffic identical to +that generated between a real iSCSI host and target. + +See PERFORMANCE for information regarding the expected performance of this +distribution. + +This code has been successfully compiled and tested on Redhat 8.0 +(kernel version 2.4.18-14) and Redhat 9.0 (kernel version 2.4.20) +with UP and SMP configurations. + +------------------- +Starting the System +------------------- + +1a) Modify the array in initiator.c to contain your target ip addresses and port + numbers. If you specify a TargetName there will be no discovery process. For + example, targets 0 and 2 below will first be discovered. Target 1 will not. + ISCSI_PORT is the default port defined in iscsi.h and currently set to 3260. + + static INITIATOR_TARGET_T g_target[CONFIG_INITIATOR_NUM_TARGETS] = { + {"192.168.10.10", ISCSI_PORT, "", NULL, 0}, + {"192.168.10.11", ISCSI_PORT, "iqn.com.intel.abc123", NULL, 0}, + {"192.168.10.12", ISCSI_PORT, "", NULL, 0}}; + + The initiator currently only connects to one of the discovered targets. If + multiple TargetNames and TargetAddresses are returned, all but 1 are ignored. + +1b) Alternately for the kernel mode driver you may specify ip addresses + in a file in the local directory called "./intel_iscsi_targets". This + file will also be looked for in the /etc directory or you may specify + the file name as a module parameter to the insmod command using the + "gfilename" argument, (insmod intel_iscsi.o gfilename="./targets"). + The format for the contents of of the file is: + ip=192.168.10.10 + ip=192.168.10.11 name=iqn.com.intel.abc123 port=3260 + ip=192.168.10.12 + The name and port fields are optional. If name is not specified, there + will be a discovery process. If port is not specified, the default port + of 3260 will be used. + +1c) For the user mode intiator, if the first entry of the g_target array has ip + address "151.0.1.1", the initiator will prompt the user to enter the number + of targets and their ip addresses. + +2) Modify the following constant in initiator.h accordingly: + + #define CONFIG_INITIATOR_NUM_TARGETS 3 + +3) Run "make" to build each of: + + intel_iscsi.o - kernel mode iSCSI initiator + kramdisk.o - kernel mode iSCSI target ramdisk + ufsdisk - user mode iSCSI target (disk stored as file in /tmp) + ufsdisk_mmap - same as ufsdisk, but uses mmap + uramdisk - user mode iSCSI ramdisk + utest - user mode iSCSI test suite + ktest - invokes same tests as utest, but from within device driver + usocktest - user mode sockets test that simulates iSCSI traffic + +4) Start a user level target (uramdisk, ufsdisk, ufsdisk_mmap) on each target + machine: + + Usage: -t iSCSI TargetName (dflt "iqn.com.intel.abc123") + -p Port Number (dflt 3260) + -b Block Length (dflt 512) + -n Number of Blocks (dflt 204800) + + + Or start the kernel level target (kramdisk.o): + + Usage: insmod kramdisk.o port= + block_len= + num_blocks= + + + With ufsdisk and ufsdisk_mmap you can directly access a device in /dev by + creating a symbolic link in /tmp to point to the appropriate device. For + example: + + "ln -s /dev/sdd /tmp/iqn.com.intel.abc123_3260_iscsi_disk_lun_0" + + And kramdisk.o only operates in ramdisk mode. + +5) Run utest. If you did not successfully connect to each target machine you + specified in initiator.c, then there was a problem. Make sure initiator.h + and initiator.c were correctly edited and all your targets had been started. + +6) As root, run "insmod ./intel_iscsi.o." You should see output similar to the + following when either viewing /var/log/messages or running dmesg: + + ********************************************* + * PARAMETERS NEGOTIATED * + * * + * InitiatorName: Intel * + * InitiatorAlias: Intel * + * SessionType: normal * + * TargetName: iqn.com.intel.abc12 * + ********************************************* + ********************************************* + * LOGIN SUCCESSFUL * + * * + * CID: 0 * + * ISID: 0 * + * TSID: 1 * + * CmdSN: 0 * + * MaxCmdSN: 0 * + * ExpStatSN: 0 * + ********************************************* + Vendor: Intel Model: Intel Labs iSCSI Rev: 2 + Type: Direct-Access ANSI SCSI revision: 02 + Detected scsi disk sdb at scsi2, channel 0, id 0, lun 0 + SCSI device sdb: 204800 512-byte hdwr sectors (105 MB) + sdb: unknown partition table + + You can now use the device as you would any other SCSI device. You can also + view driver statistics by viewing the file in /proc/scsi/iscsi. Writing to + the file (e.g. echo reset > /proc/scsi/iscsi/1) will reset all counters. + +------------------ +Testing the System +------------------ + +Once your targets and host have been started, you can test the installation +using either a single target, or by creating a RAID volume over multiple +targets. + +To test a single target you can either directly read and write the device by +opening, for example, /dev/sdd. Or you can create a filesystem on the device: + + fdisk /dev/sdd + mkfs /dev/sdd1 + mount -t ext2 /dev/sdd1 /mnt/iscsi_fs + +To test a multiple target installation, you can create a RAID volume, +virtualizing multiple targets as one SCSI device. The Linux RAID modules +will either need to be installed or compiled into the kernel. The file +/etc/raidtab must be created to reflect your targets. For example, + + raiddev /dev/md0 + raid-level 0 + nr-raid-disks 5 + persistent-superblock 0 + chunk-size 64 + + device /dev/sdd + raid-disk 0 + device /dev/sde + raid-disk 1 + device /dev/sdf + raid-disk 2 + device /dev/sdg + raid-disk 3 + device /dev/sdh + raid-disk 4 + + +After initialized the raid device with "mkraid /dev/md0," you can use /dev/md0 +as though it were a normal SCSI device. For example, + + mkfs /dev/md0 + mount -t ext2 /dev/md0 /mnt/iscsi_fs + +-------------------- +When Things Go Wrong +-------------------- + +Check the kernel error messages /var/log/messages or run the dmesg command to +see any errors reported from the host driver. The targets will report target +errors to standard output. + +If you need more fine grained debugging, modify the Makefile to turn on the +compilation flag CONFIG_ISCSI_DEBUG. Then run "make clean," and then "make." +You can select which type of debugging statements get printed by modifying +iscsiutil.h + +------------------------------------- +Interoperability with Cisco Initiator +------------------------------------- + +The target is tested to be interoperable with Cisco Initiator release +3.4.1.1 diff --git a/external/bsd/iscsi/dist/doc/README_OSD b/external/bsd/iscsi/dist/doc/README_OSD new file mode 100644 index 000000000000..fb79468e63c3 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/README_OSD @@ -0,0 +1,58 @@ + +------------------------- +Installing the OSD System +------------------------- + + 1. Build kernel version 2.4 w/ SMP mode disabled and make sure the + directory /usr/src/linux points to this build. + 2. Modify initiator.h and initiator.c (as per the README) to point to + your intended target. + 3. Run 'make osd' to build all the OSD executables. In particular, + you need uosd, so.o, intel_iscsi.o and osdfs.o. + 4. Run 'make all' to build the remaining executables. + 5. Select a machine as the target and run "uosd -f" as root on this + machine. This will create files and directories in /tmp. + +---------------------- +Testing the OSD System +---------------------- + + 6. Run utest to make sure the target is working OK. + 7. Do an "insmod ./so.o" to install the Linux SCSI upper layer driver for OSD. + 8. Do an "insmod ./intel_iscsi.o" to install the kernel mode iSCSI initiator. + 9. Do an "insmod ./osdfs.o" to install the file system. +10. Make the OSD device with "mknod /dev/so0 b 232 0". +11. Do a "mount -t osdfs /dev/so0 /mnt" to mount the filesystem. +12. Go to /mnt and run "echo Hello, World! > foo" to create an object + on the OSD. +13. Do a "cat foo" to read the object. you should see "Hello, world!" + +From here you should be able to use /mnt as you would any filesystem. + +-------------------- +2.4.18 Modifications +-------------------- + +include/scsi/scsi.h:143 + #define TYPE_OSD 0x0e + +drivers/scsi/scsi.h:92: + #define MAX_SCSI_DEVICE_CODE 15 + +drivers/scsi/scsi.h:354: + #define MAX_COMMAND_SIZE 256 + +drivers/scsi/scsi.c:145: + "OSD ", + +drivers/scsi/scsi_dma.c:248: + SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD || SDpnt->type == TYPE_OSD) { + +drivers/scsi/scsi_scan.c:644: + case TYPE_OSD: + +---------- +Hints/Tips +---------- + +-Field testing on some workstations resulted in compiling errors if highmem support in the kernel as enabled diff --git a/external/bsd/iscsi/dist/doc/license b/external/bsd/iscsi/dist/doc/license new file mode 100644 index 000000000000..de32676fbb96 --- /dev/null +++ b/external/bsd/iscsi/dist/doc/license @@ -0,0 +1,31 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2004, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ diff --git a/external/bsd/iscsi/dist/include/compat.h b/external/bsd/iscsi/dist/include/compat.h new file mode 100644 index 000000000000..ead322a17498 --- /dev/null +++ b/external/bsd/iscsi/dist/include/compat.h @@ -0,0 +1,101 @@ +#ifndef COMPAT_H_ +#define COMPAT_H_ + +#include "config.h" + +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_ASM_BYTEORDER_H +#include +#endif + +#ifdef HAVE_SYS_BYTEORDER_H +# include +# if defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) +# undef _BIG_ENDIAN +# define _BIG_ENDIAN 4321 +# define _BYTE_ORDER _BIG_ENDIAN +# elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) +# undef _LITTLE_ENDIAN +# define _LITTLE_ENDIAN 1234 +# define _BYTE_ORDER _LITTLE_ENDIAN +# endif +#endif + +#ifdef HAVE_BYTESWAP_H +#include +#endif + +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#endif + +#ifdef HAVE_LIBKERN_OSBYTEORDER_H +#include +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif + +#ifndef __UNCONST +#define __UNCONST(a) ((void *)(unsigned long)(const void *)(a)) +#endif + +#ifdef HAVE_HTOBE64 +# define ISCSI_HTOBE64(x) htobe64(x) +# define ISCSI_BE64TOH(x) be64toh(x) +#else +# if defined(HAVE_LIBKERN_OSBYTEORDER_H) +# define ISCSI_HTOBE64(x) (x) = OSSwapBigToHostInt64((u_int64_t)(x)) +# elif _BYTE_ORDER == _BIG_ENDIAN +# define ISCSI_HTOBE64(x) (x) +# elif defined(HAVE___BSWAP64) +# define ISCSI_HTOBE64(x) (x) = __bswap64((u_int64_t)(x)) +# else /* LITTLE_ENDIAN */ +# define ISCSI_HTOBE64(x) (((uint64_t)(ISCSI_NTOHL((uint32_t)(((x) << 32) >> 32))) << 32) | (uint32_t)ISCSI_NTOHL(((uint32_t)((x) >> 32)))) +# endif /* LITTLE_ENDIAN */ +# define ISCSI_BE64TOH(x) ISCSI_HTOBE64(x) +#endif + +#ifndef _DIAGASSERT +# ifndef __static_cast +# define __static_cast(x,y) (x)y +# endif +#define _DIAGASSERT(e) (__static_cast(void,0)) +#endif + +/* Added for busybox, which doesn't define INFTIM */ +#ifndef INFTIM +#define INFTIM -1 +#endif + +#ifndef HAVE_UUID_H +/* Length of a node address (an IEEE 802 address). */ +#define _UUID_NODE_LEN 6 + +/* + * See also: + * http://www.opengroup.org/dce/info/draft-leach-uuids-guids-01.txt + * http://www.opengroup.org/onlinepubs/009629399/apdxa.htm + * + * A DCE 1.1 compatible source representation of UUIDs. + */ +typedef struct uuid_t { + uint32_t time_low; + uint16_t time_mid; + uint16_t time_hi_and_version; + uint8_t clock_seq_hi_and_reserved; + uint8_t clock_seq_low; + uint8_t node[_UUID_NODE_LEN]; +} uuid_t; + +void uuid_create(uuid_t *, uint32_t *); +void uuid_to_string(uuid_t *, char **, uint32_t *); +#endif + +#endif /* COMPAT_H_ */ diff --git a/external/bsd/iscsi/dist/include/conffile.h b/external/bsd/iscsi/dist/include/conffile.h new file mode 100644 index 000000000000..b4c6c0012b3f --- /dev/null +++ b/external/bsd/iscsi/dist/include/conffile.h @@ -0,0 +1,84 @@ +/* $NetBSD: conffile.h,v 1.1 2009/06/21 21:20:30 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#ifndef CONFFILE_H_ +#define CONFFILE_H_ 1 + +/* split routines */ + +#include + +#include +#include + +#include "defs.h" + +DEFINE_ARRAY(strv_t, char *); + +/* this struct describes a configuration file */ +typedef struct conffile_t { + FILE *fp; /* in-core file pointer */ + char name[MAXPATHLEN]; /* name of file */ + int lineno; /* current line number */ + int readonly; /* nonzero if file is readonly */ + const char *sep; /* set of separators */ + const char *comment; /* set of comment characters */ +} conffile_t; + +/* this struct describes an entry in the configuration file */ +typedef struct ent_t { + char buf[BUFSIZ]; /* buffer with entry contents */ + strv_t sv; /* split up string dynamic array */ +} ent_t; + +int conffile_open(conffile_t *, const char *, const char *, const char *, const char *); +int conffile_split(conffile_t *, ent_t *, char *); +int conffile_getent(conffile_t *, ent_t *); +int conffile_get_by_field(conffile_t *, ent_t *, int, char *); +int conffile_putent(conffile_t *, int, char *, char *); +int conffile_get_lineno(conffile_t *); +char *conffile_get_name(conffile_t *); +void conffile_printent(ent_t *); +void conffile_close(conffile_t *); + +#ifndef PREFIX +#define PREFIX "" +#endif + +#ifndef SYSCONFDIR +#define SYSCONFDIR "/etc" +#endif + +#define _PATH_ISCSI_ETC SYSCONFDIR "/iscsi/" + +#define _PATH_ISCSI_PASSWD PREFIX _PATH_ISCSI_ETC "auths" +#define _PATH_ISCSI_TARGETS PREFIX _PATH_ISCSI_ETC "targets" +#define _PATH_ISCSI_PID_FILE "/var/run/iscsi-target.pid" + +#endif diff --git a/external/bsd/iscsi/dist/include/config.h b/external/bsd/iscsi/dist/include/config.h new file mode 100644 index 000000000000..0d9653153775 --- /dev/null +++ b/external/bsd/iscsi/dist/include/config.h @@ -0,0 +1,218 @@ +/* ../include/config.h. Generated from config.h.in by configure. */ +/* ../include/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#define HAVE_ARPA_INET_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_ASM_BYTEORDER_H */ + +/* Define to 1 if you have the `asnprintf' function. */ +/* #undef HAVE_ASNPRINTF */ + +/* Define to 1 if you have the `asprintf' function. */ +#define HAVE_ASPRINTF 1 + +/* Define to 1 if you have the `bcopy' function. */ +#define HAVE_BCOPY 1 + +/* Define to 1 if you have the `bswap64' function. */ +#define HAVE_BSWAP64 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_BYTESWAP_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_CTYPE_H 1 + +/* Define to 1 if you have the `daemon' function. */ +#define HAVE_DAEMON 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_ERRNO_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_FCNTL_H 1 + +/* Define to 1 if you have the `fsync_range' function. */ +#define HAVE_FSYNC_RANGE 1 + +/* Define to 1 if you have the `getaddrinfo' function. */ +#define HAVE_GETADDRINFO 1 + +/* Define to 1 if you have the `getnameinfo' function. */ +#define HAVE_GETNAMEINFO 1 + +/* Define to 1 if you have the `htobe64' function. */ +/* #undef HAVE_HTOBE64 */ + +/* Define to 1 if you have the header file. */ +#define HAVE_INTTYPES_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_LIBKERN_OSBYTEORDER_H */ + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +/* #undef HAVE_LIBNSL */ + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#define HAVE_LIBRESOLV 1 + +/* Define to 1 if you have the `socket' library (-lsocket). */ +/* #undef HAVE_LIBSOCKET */ + +/* Define to 1 if the system has the type `long long'. */ +#define HAVE_LONG_LONG yes + +/* Define to 1 if you have the header file. */ +#define HAVE_MACHINE_ENDIAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_MEMORY_H 1 + +/* Define to 1 if you have the `memset' function. */ +#define HAVE_MEMSET 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETDB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_IN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_NETINET_TCP_H 1 + +/* Define to 1 if you have the `poll' function. */ +#define HAVE_POLL 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_POLL_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PTHREAD_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_PWD_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SIGNAL_H 1 + +/* Define to 1 if you have the `snprintf' function. */ +#define HAVE_SNPRINTF 1 + +/* Define to 1 if the system has the type `socklen_t'. */ +#define HAVE_SOCKLEN_T yes + +/* Define to 1 if you have the header file. */ +#define HAVE_STDARG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDINT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRINGS_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 + +/* Define to 1 if you have the `strlcpy' function. */ +#define HAVE_STRLCPY 1 + +/* Define to 1 if you have the `strtoll' function. */ +#define HAVE_STRTOLL 1 + +/* Define to 1 if you have the `syslog' function. */ +#define HAVE_SYSLOG 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYSLOG_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_BSWAP_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_BYTEORDER_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_MMAN_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_PARAM_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SELECT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_SOCKET_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_STAT_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TIME_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_TYPES_H 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_SYS_UIO_H 1 + +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_VFS_H */ + +/* Define to 1 if you have the header file. */ +#define HAVE_UNISTD_H 1 + +/* Define to 1 if the system has the type `unsigned long long'. */ +#define HAVE_UNSIGNED_LONG_LONG yes + +/* Define to 1 if you have the header file. */ +#define HAVE_UTIME_H 1 + +/* Define to 1 if you have the `uuid_create' function. */ +#define HAVE_UUID_CREATE 1 + +/* Define to 1 if you have the header file. */ +#define HAVE_UUID_H 1 + +/* Define to 1 if you have the `uuid_to_string' function. */ +#define HAVE_UUID_TO_STRING 1 + +/* Define to 1 if you have the `vasnprintf' function. */ +/* #undef HAVE_VASNPRINTF */ + +/* Define to 1 if you have the `vasprintf' function. */ +#define HAVE_VASPRINTF 1 + +/* Define to 1 if you have the `vsnprintf' function. */ +#define HAVE_VSNPRINTF 1 + +/* Define to 1 if you have the `__bswap64' function. */ +/* #undef HAVE___BSWAP64 */ + +/* Define to the address where bug reports for this package should be sent. */ +#define PACKAGE_BUGREPORT "Alistair Crooks " + +/* Define to the full name of this package. */ +#define PACKAGE_NAME "netbsd-iscsi" + +/* Define to the full name and version of this package. */ +#define PACKAGE_STRING "netbsd-iscsi 20071221" + +/* Define to the one symbol short name of this package. */ +#define PACKAGE_TARNAME "netbsd-iscsi" + +/* Define to the version of this package. */ +#define PACKAGE_VERSION "20071221" + +/* Define to 1 if you have the ANSI C header files. */ +#define STDC_HEADERS 1 + +/* Define to empty if `const' does not conform to ANSI C. */ +/* #undef const */ + +/* Define to `unsigned int' if does not define. */ +/* #undef size_t */ diff --git a/external/bsd/iscsi/dist/include/config.h.in b/external/bsd/iscsi/dist/include/config.h.in new file mode 100644 index 000000000000..826d5d7e26f3 --- /dev/null +++ b/external/bsd/iscsi/dist/include/config.h.in @@ -0,0 +1,217 @@ +/* ../include/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if you have the header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_ASM_BYTEORDER_H + +/* Define to 1 if you have the `asnprintf' function. */ +#undef HAVE_ASNPRINTF + +/* Define to 1 if you have the `asprintf' function. */ +#undef HAVE_ASPRINTF + +/* Define to 1 if you have the `bcopy' function. */ +#undef HAVE_BCOPY + +/* Define to 1 if you have the `bswap64' function. */ +#undef HAVE_BSWAP64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_BYTESWAP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_CTYPE_H + +/* Define to 1 if you have the `daemon' function. */ +#undef HAVE_DAEMON + +/* Define to 1 if you have the header file. */ +#undef HAVE_ERRNO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fsync_range' function. */ +#undef HAVE_FSYNC_RANGE + +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + +/* Define to 1 if you have the `getnameinfo' function. */ +#undef HAVE_GETNAMEINFO + +/* Define to 1 if you have the `htobe64' function. */ +#undef HAVE_HTOBE64 + +/* Define to 1 if you have the header file. */ +#undef HAVE_INTTYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_LIBKERN_OSBYTEORDER_H + +/* Define to 1 if you have the `nsl' library (-lnsl). */ +#undef HAVE_LIBNSL + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have the `socket' library (-lsocket). */ +#undef HAVE_LIBSOCKET + +/* Define to 1 if the system has the type `long long'. */ +#undef HAVE_LONG_LONG + +/* Define to 1 if you have the header file. */ +#undef HAVE_MACHINE_ENDIAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_IN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_NETINET_TCP_H + +/* Define to 1 if you have the `poll' function. */ +#undef HAVE_POLL + +/* Define to 1 if you have the header file. */ +#undef HAVE_POLL_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_PWD_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SIGNAL_H + +/* Define to 1 if you have the `snprintf' function. */ +#undef HAVE_SNPRINTF + +/* Define to 1 if the system has the type `socklen_t'. */ +#undef HAVE_SOCKLEN_T + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDARG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strlcpy' function. */ +#undef HAVE_STRLCPY + +/* Define to 1 if you have the `strtoll' function. */ +#undef HAVE_STRTOLL + +/* Define to 1 if you have the `syslog' function. */ +#undef HAVE_SYSLOG + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BSWAP_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_BYTEORDER_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_MMAN_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_UIO_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_SYS_VFS_H + +/* Define to 1 if you have the header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if the system has the type `unsigned long long'. */ +#undef HAVE_UNSIGNED_LONG_LONG + +/* Define to 1 if you have the header file. */ +#undef HAVE_UTIME_H + +/* Define to 1 if you have the `uuid_create' function. */ +#undef HAVE_UUID_CREATE + +/* Define to 1 if you have the header file. */ +#undef HAVE_UUID_H + +/* Define to 1 if you have the `uuid_to_string' function. */ +#undef HAVE_UUID_TO_STRING + +/* Define to 1 if you have the `vasnprintf' function. */ +#undef HAVE_VASNPRINTF + +/* Define to 1 if you have the `vasprintf' function. */ +#undef HAVE_VASPRINTF + +/* Define to 1 if you have the `vsnprintf' function. */ +#undef HAVE_VSNPRINTF + +/* Define to 1 if you have the `__bswap64' function. */ +#undef HAVE___BSWAP64 + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define to 1 if you have the ANSI C header files. */ +#undef STDC_HEADERS + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `unsigned int' if does not define. */ +#undef size_t diff --git a/external/bsd/iscsi/dist/include/defs.h b/external/bsd/iscsi/dist/include/defs.h new file mode 100644 index 000000000000..f447a49a3951 --- /dev/null +++ b/external/bsd/iscsi/dist/include/defs.h @@ -0,0 +1,94 @@ +/* $NetBSD: defs.h,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright (c) 1999-2005 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#ifndef DEFS_H_ +#define DEFS_H_ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include +#include +#include + +#define NEWARRAY(type,ptr,size,where,action) do { \ + if ((ptr = (type *) calloc(sizeof(type), (unsigned)(size))) == NULL) { \ + (void) fprintf(stderr, "%s: can't allocate %lu bytes\n", \ + where, (unsigned long)(size * sizeof(type))); \ + action; \ + } \ +} while( /* CONSTCOND */ 0) + +#define RENEW(type,ptr,size,where,action) do { \ + type *_newptr; \ + if ((_newptr = (type *) realloc(ptr, sizeof(type) * (size))) == NULL) { \ + (void) fprintf(stderr, "%s: can't realloc %lu bytes\n", \ + where, (unsigned long)(size * sizeof(type))); \ + action; \ + } else { \ + ptr = _newptr; \ + } \ +} while( /* CONSTCOND */ 0) + +#define NEW(type, ptr, where, action) NEWARRAY(type, ptr, 1, where, action) + +#define FREE(ptr) (void) free(ptr) + +#define ALLOC(type, v, size, c, init, incr, where, action) do { \ + uint32_t _newsize = size; \ + if (size == 0) { \ + _newsize = init; \ + NEWARRAY(type, v, _newsize, where ": new", action); \ + } else if (c == size) { \ + _newsize = size + incr; \ + RENEW(type, v, _newsize, where ": renew", action); \ + } \ + size = _newsize; \ +} while( /* CONSTCOND */ 0) + +/* (void) memset(&v[size], 0x0, sizeof(type) * incr); \*/ + +#define DEFINE_ARRAY(name, type) \ +typedef struct name { \ + uint32_t c; \ + uint32_t size; \ + type *v; \ +} name + +#ifndef ABS +#define ABS(a) (((a) < 0) ? -(a) : (a)) +#endif + +#endif /* !DEFS_H_ */ diff --git a/external/bsd/iscsi/dist/include/device.h b/external/bsd/iscsi/dist/include/device.h new file mode 100644 index 000000000000..b81362563c8f --- /dev/null +++ b/external/bsd/iscsi/dist/include/device.h @@ -0,0 +1,52 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _DEVICE_H +#define _DEVICE_H + +#include "iscsi.h" +#include "target.h" + +/* + * Interface from target to device: + * + * device_init() initializes the device + * device_command() sends a SCSI command to one of the logical units in the device. + * device_shutdown() shuts down the device. + */ + +int device_init(globals_t *, targv_t *, disc_target_t *); +int device_command(target_session_t *, target_cmd_t *); +int device_shutdown(target_session_t *); +void device_set_var(const char *, char *); + +#endif /* _DEVICE_H */ diff --git a/external/bsd/iscsi/dist/include/driver.h b/external/bsd/iscsi/dist/include/driver.h new file mode 100644 index 000000000000..4d125d8d7b48 --- /dev/null +++ b/external/bsd/iscsi/dist/include/driver.h @@ -0,0 +1,157 @@ + +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Intel iSCSI Driver + */ + +#ifndef _DRIVER_H_ +#define _DRIVER_H_ +#include "iscsi.h" +#include "iscsiutil.h" +#include "initiator.h" + +/* + * Driver configuration + */ + +#define CONFIG_DRIVER_MAX_LUNS 1024 + +/* + * Internal + */ + +static int driver_init(void); +static int driver_shutdown(void); + +typedef struct iscsi_driver_stats_t { + unsigned num_tx, num_tx_queued; + unsigned num_rx, num_rx_queued; + unsigned avg_tx, avg_rx; + unsigned tx_queued, tx, tx_error, tx_overflow; + unsigned rx_queued, rx, rx_error, rx_overflow; + unsigned aborts_success, aborts_failed; + unsigned device_resets, bus_resets, host_resets; + iscsi_spin_t lock; +} iscsi_driver_stats_t; + +/* + * Kernel Interface + */ + +int iscsi_proc_info (char *, char **, off_t, int, int, int); +int iscsi_detect(Scsi_Host_Template *); +int iscsi_release(struct Scsi_Host *); +int iscsi_ioctl(Scsi_Device *dev, int cmd, void *arg); +int iscsi_command(Scsi_Cmnd *SCpnt); +int iscsi_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int iscsi_bios_param(Disk *, kdev_t, int *); +int iscsi_abort_handler (Scsi_Cmnd *SCpnt); +int iscsi_device_reset_handler (Scsi_Cmnd *); +int iscsi_bus_reset_handler (Scsi_Cmnd *); +int iscsi_host_reset_handler(Scsi_Cmnd *); + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,3,0) +int iscsi_revoke (Scsi_Device *ptr); +void iscsi_select_queue_depths(struct Scsi_Host *, Scsi_Device *); +#endif + +#if LINUX_VERSION_CODE < LinuxVersionCode(2,4,0) +extern struct proc_dir_entry iscsi_proc_dir; +#endif + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) +#define ISCSI { \ + name: "Intel iSCSI Driver", \ + proc_dir: NULL, \ + proc_info: iscsi_proc_info, \ + detect: iscsi_detect, \ + bios_param: iscsi_bios_param, \ + release: iscsi_release, \ + revoke: NULL, \ + ioctl: iscsi_ioctl, \ + command: iscsi_command, \ + queuecommand: iscsi_queuecommand, \ + select_queue_depths: iscsi_select_queue_depths, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: iscsi_abort_handler, \ + eh_device_reset_handler: iscsi_device_reset_handler, \ + eh_bus_reset_handler: iscsi_bus_reset_handler, \ + eh_host_reset_handler: iscsi_host_reset_handler, \ + slave_attach: NULL, \ + can_queue: CONFIG_INITIATOR_QUEUE_DEPTH, \ + this_id: -1, \ + sg_tablesize: 128, \ + cmd_per_lun: 1, /* linked commands not supported */ \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: 0, \ + use_new_eh_code: 1, \ + emulated: 0, \ + next: NULL, \ + module: NULL, \ + info: NULL, \ + proc_name: "iscsi" \ +} +#elif LINUX_VERSION_CODE >= LinuxVersionCode(2,2,0) +#define ISCSI { \ + name: "Intel iSCSI Driver", \ + proc_dir: &iscsi_proc_dir, \ + proc_info: iscsi_proc_info, \ + detect: iscsi_detect, \ + bios_param: iscsi_bios_param, \ + release: iscsi_release, \ + ioctl: iscsi_ioctl, \ + command: iscsi_command, \ + queuecommand: iscsi_queuecommand, \ + eh_strategy_handler: NULL, \ + eh_abort_handler: iscsi_abort_handler, \ + eh_device_reset_handler: iscsi_device_reset_handler, \ + eh_bus_reset_handler: iscsi_bus_reset_handler, \ + eh_host_reset_handler: iscsi_host_reset_handler, \ + use_new_eh_code: 1, \ + can_queue: CONFIG_INITIATOR_QUEUE_DEPTH, \ + sg_tablesize: SG_ALL, \ + cmd_per_lun: 1, /* linked commands not supported */ \ + this_id: -1, \ + present: 0, \ + unchecked_isa_dma: 0, \ + use_clustering: 0, \ + slave_attach: NULL, \ + next: NULL, \ + module: NULL, \ + info: NULL, \ + emulated: 0 \ +} +#endif /* LINUX_VERSION_CODE */ +#endif /* _DRIVER_H_ */ diff --git a/external/bsd/iscsi/dist/include/initiator.h b/external/bsd/iscsi/dist/include/initiator.h new file mode 100644 index 000000000000..a840ac405a0c --- /dev/null +++ b/external/bsd/iscsi/dist/include/initiator.h @@ -0,0 +1,145 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _INITIATOR_H_ +#define _INITIATOR_H_ + +#include "iscsi.h" +#include "parameters.h" +#include "defs.h" + +#define CONFIG_INITIATOR_NUM_TARGETS 16 + +/*********** + * Private * + ***********/ + +#define CONFIG_INITIATOR_QUEUE_DEPTH CONFIG_INITIATOR_NUM_TARGETS +#define CONFIG_INITIATOR_MAX_SESSIONS CONFIG_INITIATOR_NUM_TARGETS + +enum { + INITIATOR_SESSION_STATE_INITIALIZING = 0x001, + INITIATOR_SESSION_STATE_INITIALIZED = 0x002, + INITIATOR_SESSION_STATE_CONNECTING = 0x004, + INITIATOR_SESSION_STATE_CONNECTED = 0x008, + INITIATOR_SESSION_STATE_LOGGING_IN = 0x010, + INITIATOR_SESSION_STATE_AUTHENTICATED = 0x020, + INITIATOR_SESSION_STATE_LOGGED_IN_NORMAL = 0x040, + INITIATOR_SESSION_STATE_LOGGED_IN_DISCOVERY = 0x080, + INITIATOR_SESSION_STATE_LOGGING_OUT = 0x100, + INITIATOR_SESSION_STATE_LOGGED_OUT = 0x200, + INITIATOR_SESSION_STATE_DESTROYING = 0x400 +}; + +enum { + TARGET_HOSTNAME_SIZE = 1024, + TARGET_IP_SIZE = 16, + TARGET_NAME_SIZE = 256 +}; + +#define INITIATOR_STATE_SHUTDOWN 1 + +typedef struct { + iscsi_mutex_t mutex; + iscsi_cond_t cond; +} initiator_wait_t; + +typedef struct initiator_session_t { + iscsi_socket_t sock; + uint32_t CmdSN; + uint32_t ExpStatSN; + uint32_t MaxCmdSN; + iscsi_queue_t tx_queue; + iscsi_worker_t tx_worker; + iscsi_worker_t rx_worker; + uint64_t isid; + int tsih; + int cid; + uint32_t state; + iscsi_parameter_t *params; + struct initiator_cmd_t *cmds; + iscsi_spin_t cmds_spin; + iscsi_sess_param_t sess_params; +} initiator_session_t; + +typedef struct initiator_cmd_t { + void *ptr; + int type; + int (*callback) (void *); + void *callback_arg; + uint64_t isid; + int tx_done; + int status; + struct initiator_cmd_t *next; + struct initiator_cmd_t *hash_next; + uint32_t key; + char targetname[TARGET_HOSTNAME_SIZE]; +} initiator_cmd_t; + +typedef struct initiator_target_t { + char name[TARGET_HOSTNAME_SIZE]; + char ip[TARGET_IP_SIZE]; + int port; + char TargetName[TARGET_NAME_SIZE]; + initiator_session_t *sess; + int has_session; + char iqnwanted[TARGET_NAME_SIZE]; +} initiator_target_t; + +DEFINE_ARRAY(strv_t, char *); + +enum { + ISCSI_IPv4 = AF_INET, + ISCSI_IPv6 = AF_INET6, + ISCSI_UNSPEC = PF_UNSPEC +}; + +/********** + * Public * + **********/ + +int initiator_init(const char *, int, int, const char *, int, int, int); +int initiator_info(char *, int, int); +int initiator_command(initiator_cmd_t *); +int initiator_enqueue(initiator_cmd_t *); +int initiator_abort(initiator_cmd_t *); +int initiator_shutdown(void); +int initiator_discover(char *, uint64_t, int); + +void get_target_info(uint64_t, initiator_target_t *); + +int ii_initiator_init(const char *, int, int, const char *, char *, int, int, int); + +int initiator_get_targets(int, strv_t *); +int initiator_set_target_name(int, char *); + +#endif /* _INITIATOR_H_ */ diff --git a/external/bsd/iscsi/dist/include/iscsi-md5.h b/external/bsd/iscsi/dist/include/iscsi-md5.h new file mode 100644 index 000000000000..6047bb761113 --- /dev/null +++ b/external/bsd/iscsi/dist/include/iscsi-md5.h @@ -0,0 +1,63 @@ +/* $NetBSD: iscsi-md5.h,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * This file is derived from the RSA Data Security, Inc. MD5 Message-Digest + * Algorithm and has been modified by Jason R. Thorpe + * for portability and formatting. + */ + +/* + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#ifndef _SYS_MD5_H_ +#define _SYS_MD5_H_ + +#include + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include +#endif + +/* iSCSI_MD5 context. */ +typedef struct iSCSI_MD5Context { + uint32_t state[4]; /* state (ABCD) */ + uint32_t count[2]; /* number of bits, modulo 2^64 (lsb first) */ + unsigned char buffer[64]; /* input buffer */ +} iSCSI_MD5_CTX; + +__BEGIN_DECLS +void iSCSI_MD5Init(iSCSI_MD5_CTX *); +void iSCSI_MD5Update(iSCSI_MD5_CTX *, const uint8_t *, size_t); +void iSCSI_MD5Final(unsigned char[16], iSCSI_MD5_CTX *); +#ifndef _KERNEL +char *iSCSI_MD5End(iSCSI_MD5_CTX *, char *); +char *iSCSI_MD5File(const char *, char *); +char *iSCSI_MD5Data(const uint8_t *, size_t, char *); +#endif /* _KERNEL */ +__END_DECLS + +#endif /* _SYS_MD5_H_ */ diff --git a/external/bsd/iscsi/dist/include/iscsi.h b/external/bsd/iscsi/dist/include/iscsi.h new file mode 100644 index 000000000000..c671166a8bd9 --- /dev/null +++ b/external/bsd/iscsi/dist/include/iscsi.h @@ -0,0 +1,536 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ISCSI_H +#define ISCSI_H + +#include "iscsiutil.h" + +/* + * iSCSI Version 18 + */ + +#define ISCSI_VENDOR "NetBSD" +#define ISCSI_PRODUCT "NetBSD iSCSI" +#define ISCSI_VERSION 0 + +/* + * Parameters + */ + +#define ISCSI_IMMEDIATE_DATA_DFLT 1 +#define ISCSI_INITIAL_R2T_DFLT 1 +#define ISCSI_USE_PHASE_COLLAPSED_READ_DFLT 0 +#define ISCSI_HEADER_LEN 48 +#define ISCSI_PORT 3260 /* Default port */ +#define ISCSI_OPCODE(HEADER) (HEADER[0] & 0x3f) + +#define ISCSI_FIRST_BURST (ISCSI_FIRST_BURST_DFLT) +#define ISCSI_DATA_PDU_LENGTH (ISCSI_DATA_PDU_LENGTH_DFLT) + +/* + * Opcodes + */ +enum { + ISCSI_NOP_OUT = 0x00, + ISCSI_SCSI_CMD = 0x01, + ISCSI_TASK_CMD = 0x02, + ISCSI_LOGIN_CMD = 0x03, + ISCSI_TEXT_CMD = 0x04, + ISCSI_WRITE_DATA = 0x05, + ISCSI_LOGOUT_CMD = 0x06, + ISCSI_SNACK = 0x10, /* not implemented */ + ISCSI_NOP_IN = 0x20, + ISCSI_SCSI_RSP = 0x21, + ISCSI_TASK_RSP = 0x22, + ISCSI_LOGIN_RSP = 0x23, + ISCSI_TEXT_RSP = 0x24, + ISCSI_READ_DATA = 0x25, + ISCSI_LOGOUT_RSP = 0x26, + ISCSI_R2T = 0x31, + ISCSI_ASYNC = 0x32, + ISCSI_REJECT = 0x3f +}; + +enum { + ISCSI_AHS_EXTENDED_CDB = 0x01, + ISCSI_AHS_BIDI_READ = 0x02 +}; + +/* + * Login Phase + */ +enum { + ISCSI_LOGIN_STATUS_SUCCESS = 0, + ISCSI_LOGIN_STATUS_REDIRECTION = 1, + ISCSI_LOGIN_STATUS_INITIATOR_ERROR = 2, + ISCSI_LOGIN_STATUS_TARGET_ERROR = 3, + + ISCSI_LOGIN_STAGE_SECURITY = 0, + ISCSI_LOGIN_STAGE_NEGOTIATE = 1, + ISCSI_LOGIN_STAGE_FULL_FEATURE = 3 +}; + +/* detailed return codes for login phase */ +enum { + ISCSI_LOGIN_DETAIL_SUCCESS = 0x0, + ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE = 0x01, + ISCSI_LOGIN_DETAIL_VERSION_NOT_SUPPORTED = 0x05, + ISCSI_LOGIN_DETAIL_NOT_LOGGED_IN = 0x0b +}; + + +/* + * Logout Phase + */ +enum { + ISCSI_LOGOUT_CLOSE_SESSION = 0, + ISCSI_LOGOUT_CLOSE_CONNECTION = 1, + ISCSI_LOGOUT_CLOSE_RECOVERY = 2, + + ISCSI_LOGOUT_STATUS_SUCCESS = 0, + ISCSI_LOGOUT_STATUS_NO_CID = 1, + ISCSI_LOGOUT_STATUS_NO_RECOVERY = 2, + ISCSI_LOGOUT_STATUS_FAILURE = 3 +}; + + +/* + * Task Command + */ +enum { + ISCSI_TASK_CMD_ABORT_TASK = 1, + ISCSI_TASK_CMD_ABORT_TASK_SET = 2, + ISCSI_TASK_CMD_CLEAR_ACA = 3, + ISCSI_TASK_CMD_CLEAR_TASK_SET = 4, + ISCSI_TASK_CMD_LOGICAL_UNIT_RESET = 5, + ISCSI_TASK_CMD_TARGET_WARM_RESET = 6, + ISCSI_TASK_CMD_TARGET_COLD_RESET = 7, + ISCSI_TASK_CMD_TARGET_REASSIGN = 8 +}; + +typedef struct iscsi_task_cmd_t { + int32_t immediate; + uint8_t function; + uint64_t lun; + uint32_t tag; + uint32_t ref_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + uint32_t RefCmdSN; + uint32_t ExpDataSN; +} iscsi_task_cmd_t; + +int iscsi_task_cmd_encap(uint8_t *header, iscsi_task_cmd_t * cmd); +int iscsi_task_cmd_decap(uint8_t *header, iscsi_task_cmd_t * cmd); + + +/* + * Task Response + */ +enum { + ISCSI_TASK_RSP_FUNCTION_COMPLETE = 0, + ISCSI_TASK_RSP_NO_SUCH_TASK = 1, + ISCSI_TASK_RSP_NO_SUCH_LUN = 2, + ISCSI_TASK_RSP_STILL_ALLEGIANT = 3, + ISCSI_TASK_RSP_NO_FAILOVER = 4, + ISCSI_TASK_RSP_NO_SUPPORT = 5, + ISCSI_TASK_RSP_AUTHORIZED_FAILED = 6, + + ISCSI_TASK_RSP_REJECTED = 255, + + ISCSI_TASK_QUAL_FUNCTION_EXECUTED = 0, + ISCSI_TASK_QUAL_NOT_AUTHORIZED = 1 +}; + +typedef struct iscsi_task_rsp_t { + uint8_t response; + uint32_t length; + uint32_t tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; +} iscsi_task_rsp_t; + +int iscsi_task_rsp_encap(uint8_t *header, iscsi_task_rsp_t * rsp); +int iscsi_task_rsp_decap(uint8_t *header, iscsi_task_rsp_t * rsp); + + +/* + * NOP-Out + */ + + +typedef struct iscsi_nop_out_args_t { + int32_t immediate; + uint32_t length; + uint64_t lun; + uint32_t tag; + uint32_t transfer_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + const uint8_t *data; +} iscsi_nop_out_args_t; + +int iscsi_nop_out_encap(uint8_t *header, iscsi_nop_out_args_t * cmd); +int iscsi_nop_out_decap(uint8_t *header, iscsi_nop_out_args_t * cmd); + + +/* + * NOP-In + */ + + +typedef struct iscsi_nop_in_args_t { + uint32_t length; + uint64_t lun; + uint32_t tag; + uint32_t transfer_tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; +} iscsi_nop_in_args_t; + +int iscsi_nop_in_encap(uint8_t *header, iscsi_nop_in_args_t * cmd); +int iscsi_nop_in_decap(uint8_t *header, iscsi_nop_in_args_t * cmd); + + +/* + * Text Command + */ + + +typedef struct iscsi_text_cmd_args_t { + int32_t immediate; + int32_t final; + int32_t cont; + uint32_t length; + uint64_t lun; + uint32_t tag; + uint32_t transfer_tag; + uint32_t CmdSN; + uint32_t ExpStatSN; + char *text; +} iscsi_text_cmd_args_t; + +int iscsi_text_cmd_encap(uint8_t *header, iscsi_text_cmd_args_t * cmd); +int iscsi_text_cmd_decap(uint8_t *header, iscsi_text_cmd_args_t * cmd); + + +/* + * Text Response + */ + + +typedef struct iscsi_text_rsp_args_t { + int32_t final; + int32_t cont; + uint32_t length; + uint64_t lun; + uint32_t tag; + uint32_t transfer_tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; +} iscsi_text_rsp_args_t; + +int iscsi_text_rsp_encap(uint8_t *header, iscsi_text_rsp_args_t * rsp); +int iscsi_text_rsp_decap(uint8_t *header, iscsi_text_rsp_args_t * rsp); + + +/* + * Login Command + */ + + +typedef struct iscsi_login_cmd_args_t { + int32_t transit; + int32_t cont; + uint8_t csg; + uint8_t nsg; + int8_t version_max; + int8_t version_min; + uint8_t AHSlength; + uint32_t length; + uint64_t isid; + uint16_t tsih; + uint32_t tag; + uint16_t cid; + uint32_t CmdSN; + uint32_t ExpStatSN; + char *text; +} iscsi_login_cmd_args_t; + +int iscsi_login_cmd_encap(uint8_t *header, iscsi_login_cmd_args_t * cmd); +int iscsi_login_cmd_decap(uint8_t *header, iscsi_login_cmd_args_t * cmd); + + +/* + * Login Response + */ + + +typedef struct iscsi_login_rsp_args_t { + int32_t transit; + int32_t cont; + uint8_t csg; + uint8_t nsg; + int8_t version_max; + int8_t version_active; + uint8_t AHSlength; + uint32_t length; + uint64_t isid; + uint16_t tsih; + uint32_t tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint8_t status_class; + uint8_t status_detail; +} iscsi_login_rsp_args_t; + +int iscsi_login_rsp_encap(uint8_t *header, iscsi_login_rsp_args_t * rsp); +int iscsi_login_rsp_decap(uint8_t *header, iscsi_login_rsp_args_t * rsp); + + +/* + * Logout Command + */ + + +typedef struct iscsi_logout_cmd_args_t { + int32_t immediate; + uint8_t reason; + uint32_t tag; + uint16_t cid; + uint32_t CmdSN; + uint32_t ExpStatSN; +} iscsi_logout_cmd_args_t; + +int iscsi_logout_cmd_encap(uint8_t *header, iscsi_logout_cmd_args_t * cmd); +int iscsi_logout_cmd_decap(uint8_t *header, iscsi_logout_cmd_args_t * cmd); + + +/* + * Logout Response + */ + + +typedef struct iscsi_logout_rsp_args_t { + uint8_t response; + uint32_t length; + uint32_t tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint16_t Time2Wait; + uint16_t Time2Retain; +} iscsi_logout_rsp_args_t; + +int iscsi_logout_rsp_encap(uint8_t *header, iscsi_logout_rsp_args_t * rsp); +int iscsi_logout_rsp_decap(uint8_t *header, iscsi_logout_rsp_args_t * rsp); + + +/* + * SCSI Command + */ + + +typedef struct iscsi_scsi_cmd_args_t { + int32_t immediate; + int32_t final; + int32_t input; + int32_t output; + uint8_t attr; + uint32_t length; + uint64_t lun; + uint32_t tag; + uint32_t trans_len; + uint32_t bidi_trans_len; + uint32_t CmdSN; + uint32_t ExpStatSN; + uint8_t *cdb; + uint8_t *ext_cdb; + uint8_t *ahs; + uint8_t ahs_len; + uint8_t *send_data; + int32_t send_sg_len; + uint8_t *recv_data; + int32_t recv_sg_len; + uint8_t status; + uint32_t bytes_sent; + uint32_t bytes_recv; +} iscsi_scsi_cmd_args_t; + +int iscsi_scsi_cmd_encap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd); +int iscsi_scsi_cmd_decap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd); + + +/* + * SCSI Response + */ + + +typedef struct iscsi_scsi_rsp_args_t { + int32_t bidi_overflow; + int32_t bidi_underflow; + int32_t overflow; + int32_t underflow; + + + uint8_t response; + uint8_t status; + uint32_t ahs_len; + uint32_t length; + uint32_t tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint32_t ExpDataSN; + uint32_t bidi_res_cnt; + uint32_t basic_res_cnt; +} iscsi_scsi_rsp_t; + +int iscsi_scsi_rsp_encap(uint8_t *header, iscsi_scsi_rsp_t * rsp); +int iscsi_scsi_rsp_decap(uint8_t *header, iscsi_scsi_rsp_t * rsp); + + +/* + * Ready To Transfer (R2T) + */ + + +typedef struct iscsi_r2t_args_t { + uint32_t AHSlength; + uint64_t lun; + uint32_t tag; + uint32_t transfer_tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint32_t R2TSN; + uint32_t offset; + uint32_t length; +} iscsi_r2t_t; + +int iscsi_r2t_encap(uint8_t *header, iscsi_r2t_t * cmd); +int iscsi_r2t_decap(uint8_t *header, iscsi_r2t_t * cmd); + + +/* + * SCSI Write Data + */ + + +typedef struct iscsi_write_data_args_t { + int32_t final; + uint32_t length; + uint64_t lun; + uint32_t tag; + uint32_t transfer_tag; + uint32_t ExpStatSN; + uint32_t DataSN; + uint32_t offset; +} iscsi_write_data_t; + +int iscsi_write_data_encap(uint8_t *header, iscsi_write_data_t * cmd); +int iscsi_write_data_decap(uint8_t *header, iscsi_write_data_t * cmd); + + +/* + * SCSI Read Data + */ + + +typedef struct iscsi_read_data_args_t { + int32_t final; + int32_t ack; + int32_t overflow; + int32_t underflow; + int32_t S_bit; + uint8_t status; + uint32_t length; + uint64_t lun; + uint32_t task_tag; + uint32_t transfer_tag; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint32_t DataSN; + uint32_t offset; + uint32_t res_count; +} iscsi_read_data_t; + +int iscsi_read_data_encap(uint8_t *header, iscsi_read_data_t * cmd); +int iscsi_read_data_decap(uint8_t *header, iscsi_read_data_t * cmd); + + +/* + * Reject + */ + +typedef struct iscsi_reject_args_t { + uint8_t reason; + uint32_t length; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint32_t DataSN; + char *header; + +} iscsi_reject_t; + +int iscsi_reject_encap(uint8_t *header, iscsi_reject_t * cmd); +int iscsi_reject_decap(uint8_t *header, iscsi_reject_t * cmd); + +/* + * Async Message + */ + +typedef struct iscsi_async_msg_args_t { + uint8_t AHSlength; + uint64_t lun; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint32_t length; + uint8_t AsyncEvent; + uint8_t AsyncVCode; +} iscsi_async_msg_t; + +int iscsi_amsg_decap(uint8_t *header, iscsi_async_msg_t * msg); + +#ifndef SOL_TCP +#define SOL_TCP IPPROTO_TCP +#endif + +#endif /* ISCSI_H */ diff --git a/external/bsd/iscsi/dist/include/iscsiutil.h b/external/bsd/iscsi/dist/include/iscsiutil.h new file mode 100644 index 000000000000..b7058c19d88f --- /dev/null +++ b/external/bsd/iscsi/dist/include/iscsiutil.h @@ -0,0 +1,489 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _ISCSIUTIL_H_ +#define _ISCSIUTIL_H_ + +#include "config.h" + +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_PTHREAD_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SYSLOG_H +#include +#endif + +/* + * + */ + +#define ISCSI_HTONLL6(x) (uint64_t) \ + ( ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000ff0000000000uLL) >> 40)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000ff00000000uLL) >> 24)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000ff000000uLL) >> 8)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000000000ff0000uLL) << 8)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000000000ff00uLL) << 24)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000000000ffuLL) << 40))) + +#define ISCSI_NTOHLL6(x) (uint64_t) \ + ( ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000ff0000000000uLL) >> 40)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000ff00000000uLL) >> 24)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000ff000000uLL) >> 8)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x0000000000ff0000uLL) << 8)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x000000000000ff00uLL) << 24)) \ + | ((uint64_t)( ((uint64_t)(x) & (uint64_t)0x00000000000000ffuLL) << 40))) + +/* + * Debugging Levels + */ + +#define TRACE_NET_DEBUG 0x00000001 +#define TRACE_NET_BUFF 0x00000002 +#define TRACE_NET_IOV 0x00000004 +#define TRACE_NET_ALL (TRACE_NET_DEBUG|TRACE_NET_BUFF|TRACE_NET_IOV) + +#define TRACE_ISCSI_DEBUG 0x00000010 +#define TRACE_ISCSI_CMD 0x00000020 +#define TRACE_ISCSI_ARGS 0x00000040 +#define TRACE_ISCSI_PARAM 0x00000080 +#define TRACE_ISCSI_ALL (TRACE_ISCSI_DEBUG|TRACE_ISCSI_ARGS|TRACE_ISCSI_PARAM|TRACE_ISCSI_CMD) + +#define TRACE_SCSI_DEBUG 0x00000100 +#define TRACE_SCSI_CMD 0x00000200 +#define TRACE_SCSI_DATA 0x00000400 +#define TRACE_SCSI_ARGS 0x00000800 +#define TRACE_SCSI_ALL (TRACE_SCSI_DEBUG|TRACE_SCSI_CMD|TRACE_SCSI_DATA|TRACE_SCSI_ARGS) + +#define TRACE_DEBUG 0x00001000 +#define TRACE_HASH 0x00002000 +#define TRACE_SYNC 0x00004000 +#define TRACE_QUEUE 0x00008000 +#define TRACE_WARN 0x00010000 +#define TRACE_MEM 0x00020000 + +#define TRACE_OSD 0x00040000 +#define TRACE_OSDFS 0x00080000 +#define TRACE_OSDSO 0x00100000 +#define TRACE_ALL 0xffffffff + +/* + * Set debugging level here. Turn on debugging in Makefile. + */ +#ifndef EXTERN +#define EXTERN extern +#endif + +EXTERN uint32_t iscsi_debug_level; + +/* + * Debugging Functions + */ +void set_debug(const char *); +void iscsi_trace(const int, const char *, const int, const char *, ...); +void iscsi_trace_warning(const char *, const int, const char *, ...); +void iscsi_trace_error(const char *, const int, const char *, ...); +void iscsi_print_buffer(const char *, const size_t); + + +/* + * Byte Order + */ + +#ifdef HAVE_ASM_BYTEORDER_H +#include +#endif + +#ifdef HAVE_SYS_BYTEORDER_H +#include +#endif + +#ifdef HAVE_BYTESWAP_H +#include +#endif + +#ifdef HAVE_MACHINE_ENDIAN_H +#include +#endif + +#define __BYTE_ORDER _BYTE_ORDER +#define __BIG_ENDIAN _BIG_ENDIAN +#define __LITTLE_ENDIAN _LITTLE_ENDIAN + +#define ISCSI_NTOHLL(a) ISCSI_BE64TOH(a) +#define ISCSI_HTONLL(a) ISCSI_HTOBE64(a) +#define ISCSI_NTOHL(a) ntohl(a) +#define ISCSI_HTONL(a) htonl(a) +#define ISCSI_NTOHS(a) ntohs(a) +#define ISCSI_HTONS(a) htons(a) + +#define ISCSI_GETPID getpid() + +#ifndef HAVE_SOCKLEN_T +typedef int socklen_t; +#endif + +/* + * Sleeping + */ + +#define ISCSI_SLEEP(N) sleep(N) + +/* + * Memory + */ + +void *iscsi_malloc(unsigned); +void iscsi_free(void *); +void *iscsi_malloc_atomic(unsigned); +void iscsi_free_atomic(void *); + +/* + * Comparison + */ + +#ifndef MIN +#define MIN(A,B) (((A)<(B))?(A):(B)) +#endif + +#define MIN_3(A,B,C) (((A)<(B))?(((A)<(C))?(A):(C)):(((B)<(C))?(B):(C))) + +/* Spin locks */ + +typedef pthread_mutex_t iscsi_spin_t; + +int iscsi_spin_init(iscsi_spin_t * ); +int iscsi_spin_lock(iscsi_spin_t * ); +int iscsi_spin_unlock(iscsi_spin_t * ); +int iscsi_spin_lock_irqsave(iscsi_spin_t * , uint32_t *); +int iscsi_spin_unlock_irqrestore(iscsi_spin_t * , uint32_t *); +int iscsi_spin_destroy(iscsi_spin_t * ); + +/* + * End of ISCSI spin routines + */ + +/* + * Tags + */ + +#define ISCSI_SET_TAG(tag) do { \ + iscsi_spin_lock(&g_tag_spin); \ + *tag = g_tag++; \ + iscsi_spin_unlock(&g_tag_spin); \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_SET_TAG_IN_INTR(tag) do { \ + uint32_t flags; \ + iscsi_spin_lock_irqsave(&g_tag_spin, &flags); \ + *tag = g_tag++; \ + iscsi_spin_unlock_irqrestore(&g_tag_spin, &flags); \ +} while (/* CONSTCOND */ 0) + + + +/* + * Hashing + */ + + +typedef struct hash_t { + struct initiator_cmd_t **bucket; + int collisions; + int insertions; + int n; + iscsi_spin_t lock; +} hash_t; + +int hash_init(hash_t * , int ); +int hash_insert(hash_t * , struct initiator_cmd_t * , uint32_t ); +struct initiator_cmd_t *hash_remove(hash_t * , uint32_t ); +int hash_destroy(hash_t * ); + +/* + * Queuing + */ + +typedef struct iscsi_queue_t { + int head; + int tail; + int count; + void **elem; + int depth; + iscsi_spin_t lock; +} iscsi_queue_t; + +int iscsi_queue_init(iscsi_queue_t * , int ); +void iscsi_queue_destroy(iscsi_queue_t * ); +int iscsi_queue_insert(iscsi_queue_t * , void *); +void *iscsi_queue_remove(iscsi_queue_t * ); +int iscsi_queue_depth(iscsi_queue_t * ); +int iscsi_queue_full(iscsi_queue_t * ); + +/* + * Socket Abstraction + */ + +typedef int iscsi_socket_t; + +/* Turning off Nagle's Algorithm doesn't always seem to work, */ +/* so we combine two messages into one when the second's size */ +/* is less than or equal to ISCSI_SOCK_HACK_CROSSOVER. */ + +#define ISCSI_SOCK_HACK_CROSSOVER 1024 +#define ISCSI_SOCK_CONNECT_NONBLOCK 0 +#define ISCSI_SOCK_CONNECT_TIMEOUT 1 +#define ISCSI_SOCK_MSG_BYTE_ALIGN 4 + +int iscsi_sock_create(iscsi_socket_t * ); +int iscsi_socks_establish(iscsi_socket_t *, int *, int *, int, int); +int iscsi_waitfor_connection(iscsi_socket_t *, int, const char *cf, iscsi_socket_t *); +const char *iscsi_address_family(int); +int iscsi_sock_setsockopt(iscsi_socket_t * , int , int , void *, unsigned ); +int iscsi_sock_getsockopt(iscsi_socket_t * , int , int , void *, unsigned *); +int iscsi_sock_bind(iscsi_socket_t , int ); +int iscsi_sock_listen(iscsi_socket_t ); +int iscsi_sock_connect(iscsi_socket_t , char *, int ); +int iscsi_sock_accept(iscsi_socket_t , iscsi_socket_t * ); +int iscsi_sock_shutdown(iscsi_socket_t , int ); +int iscsi_sock_close(iscsi_socket_t ); +int iscsi_sock_msg(iscsi_socket_t , int , unsigned , void *, int ); +int iscsi_sock_send_header_and_data(iscsi_socket_t , + void *, unsigned , + const void *, unsigned , int ); +int iscsi_sock_getsockname(iscsi_socket_t , struct sockaddr * , unsigned *); +int iscsi_sock_getpeername(iscsi_socket_t , struct sockaddr * , unsigned *); +int modify_iov(struct iovec ** , int *, uint32_t , uint32_t ); + + +void cdb2lba(uint32_t *, uint16_t *, uint8_t *); +void lba2cdb(uint8_t *, uint32_t *, uint16_t *); + +/* + * Mutexes + */ + +typedef pthread_mutex_t iscsi_mutex_t; + +int iscsi_mutex_init(iscsi_mutex_t * ); +int iscsi_mutex_lock(iscsi_mutex_t * ); +int iscsi_mutex_unlock(iscsi_mutex_t * ); +int iscsi_mutex_destroy(iscsi_mutex_t * ); + +#define ISCSI_LOCK(M, ELSE) do { \ + if (iscsi_mutex_lock(M) != 0) { \ + iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_lock() failed\n"); \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_UNLOCK(M, ELSE) do { \ + if (iscsi_mutex_unlock(M) != 0) { \ + iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_unlock() failed\n"); \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_MUTEX_INIT(M, ELSE) do { \ + if (iscsi_mutex_init(M) != 0) { \ + iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_init() failed\n"); \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_MUTEX_DESTROY(M, ELSE) do { \ + if (iscsi_mutex_destroy(M) != 0) { \ + iscsi_trace_error(__FILE__, __LINE__, "iscsi_mutex_destroy() failed\n"); \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +/* + * Condition Variable + */ + +typedef pthread_cond_t iscsi_cond_t; + +int iscsi_cond_init(iscsi_cond_t * ); +int iscsi_cond_wait(iscsi_cond_t * , iscsi_mutex_t * ); +int iscsi_cond_signal(iscsi_cond_t * ); +int iscsi_cond_destroy(iscsi_cond_t * ); + +#define ISCSI_COND_INIT(C, ELSE) do { \ + if (iscsi_cond_init(C) != 0) { \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_WAIT(C, M, ELSE) do { \ + if (iscsi_cond_wait(C, M) != 0) { \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_SIGNAL(C, ELSE) do { \ + if (iscsi_cond_signal(C) != 0) { \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +#define ISCSI_COND_DESTROY(C, ELSE) do { \ + if (iscsi_cond_destroy(C) != 0) { \ + ELSE; \ + } \ +} while (/* CONSTCOND */ 0) + +/* + * Threading Routines + */ + +typedef struct iscsi_thread_t { + pthread_t pthread; +} iscsi_thread_t; + +int iscsi_thread_create(iscsi_thread_t * , void *(*proc) (void *), void *); + +#define ISCSI_SET_THREAD(ME) /* for user pthread id set by pthread_create + * in iscsi_thread_create */ +#define ISCSI_THREAD_START(NAME) + +/* + * Worker Thread + */ + +#define ISCSI_WORKER_STATE_STARTED 1 +#define ISCSI_WORKER_STATE_ERROR 2 +#define ISCSI_WORKER_STATE_EXITING 4 + +typedef struct { + iscsi_thread_t thread; + iscsi_mutex_t work_mutex; + iscsi_cond_t work_cond; + iscsi_mutex_t exit_mutex; + iscsi_cond_t exit_cond; + int id; + int pid; + volatile uint32_t state; +} iscsi_worker_t; + +#define ISCSI_WORKER_EXIT(ME) do { \ + iscsi_trace(TRACE_ISCSI_DEBUG ,__FILE__, __LINE__, "exiting\n"); \ + (ME)->state |= ISCSI_WORKER_STATE_EXITING; \ + return 0; \ +} while (/* CONSTCOND */ 0) + +/* + * Spin Lock + */ +#define ISCSI_SPIN + +/* + * Pre/Post condition checking + */ + +#define NO_CLEANUP {} +#define RETURN_GREATER(NAME, V1, V2, CU, RC) \ +if ((V1)>(V2)) { \ + iscsi_trace_error(__FILE__, __LINE__, "Bad \"%s\": %u > %u.\n", NAME, (unsigned)V1, (unsigned)V2); \ + CU; \ + return RC; \ +} + +#define RETURN_NOT_EQUAL(NAME, V1, V2, CU, RC) \ +if ((V1)!=(V2)) { \ + iscsi_trace_error(__FILE__, __LINE__, "Bad \"%s\": Got %u expected %u.\n", NAME, V1, V2); \ + CU; \ + return RC; \ +} + +#define WARN_NOT_EQUAL(NAME, V1, V2) \ +if ((V1)!=(V2)) { \ + iscsi_trace_warning(__FILE__, __LINE__, "Bad \"%s\": Got %u expected %u.\n", NAME, V1, V2); \ +} + +#define RETURN_EQUAL(NAME, V1, V2, CU, RC) \ +if ((V1)==(V2)) { \ + iscsi_trace_error(__FILE__, __LINE__, "Bad \"%s\": %u == %u.\n", NAME, V1, V2); \ + CU; \ + return RC; \ +} + +/* + * Misc. Functions + */ + +uint32_t iscsi_atoi(char *); +int HexTextToData(const char *, uint32_t , uint8_t *, uint32_t ); +int HexDataToText(uint8_t *, uint32_t , char *, uint32_t ); +void GenRandomData(uint8_t *, uint32_t ); + +/* this is the maximum number of iovecs which we can use in iscsi_sock_send_header_and_data */ +#ifndef ISCSI_MAX_IOVECS +#define ISCSI_MAX_IOVECS 32 +#endif + +enum { + /* used in iscsi_sock_msg() */ + Receive = 0, + Transmit = 1 +}; + +int allow_netmask(const char *, const char *); + +#endif /* _ISCSIUTIL_H_ */ diff --git a/external/bsd/iscsi/dist/include/osd.h b/external/bsd/iscsi/dist/include/osd.h new file mode 100644 index 000000000000..689a54bece22 --- /dev/null +++ b/external/bsd/iscsi/dist/include/osd.h @@ -0,0 +1,149 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef OSD_H +#define OSD_H + +#include "config.h" + +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "iscsiutil.h" + +#define OSD_VENDOR "NetBSD" +#define OSD_PRODUCT "NetBSD/Intel OSD" +#define OSD_VERSION 0 + +/* + * OSD Configuration + */ + +#define CONFIG_OSD_CAPACITY_DFLT 1024 +#define CONFIG_OSD_LUNS_DFLT 1 +#define CONFIG_OSD_BASEDIR_DFLT "/tmp/iscsi_osd" +#define CONFIG_OSD_CDB_LEN 128 + +/* + * OSD Service Actions + */ + +#define OSD_CREATE_GROUP 0x880B +#define OSD_REMOVE_GROUP 0x880C +#define OSD_CREATE 0x8802 +#define OSD_REMOVE 0x880A +#define OSD_READ 0x8805 +#define OSD_WRITE 0x8806 +#define OSD_GET_ATTR 0x880E +#define OSD_SET_ATTR 0x880F + +/* + * OSD Arguments + */ + +typedef struct osd_args_t { + uint8_t opcode; + uint8_t control; + uint8_t security; + uint8_t add_cdb_len; + uint16_t service_action; + uint8_t options_byte; + uint8_t second_options_byte; + uint32_t GroupID; + uint64_t UserID; + uint32_t SessionID; + uint64_t length; + uint64_t offset; + uint32_t set_attributes_list_length; + uint32_t get_attributes_page; + uint32_t get_attributes_list_length; + uint32_t get_attributes_allocation_length; +} osd_args_t; + +#define OSD_ENCAP_CDB(ARGS, CDB) \ +(CDB)[0] = (ARGS)->opcode; \ +(CDB)[1] = (ARGS)->control; \ +(CDB)[6] = (ARGS)->security; \ +(CDB)[7] = (ARGS)->add_cdb_len; \ +*((uint16_t *)((CDB)+8)) = ISCSI_HTONS((ARGS)->service_action); \ +(CDB)[10] = (ARGS)->options_byte; \ +(CDB)[11] = (ARGS)->second_options_byte; \ +*((uint32_t *)((CDB)+12)) = ISCSI_HTONL((ARGS)->GroupID); \ +*((uint64_t *)((CDB)+16)) = ISCSI_HTONLL((ARGS)->UserID); \ +*((uint32_t *)((CDB)+24)) = ISCSI_HTONL((ARGS)->SessionID); \ +*((uint64_t *)((CDB)+28)) = ISCSI_HTONLL((ARGS)->length); \ +*((uint64_t *)((CDB)+36)) = ISCSI_HTONLL((ARGS)->offset); \ +*((uint32_t *)((CDB)+44)) = ISCSI_HTONL((ARGS)->get_attributes_page); \ +*((uint32_t *)((CDB)+48)) = ISCSI_HTONL((ARGS)->get_attributes_list_length); \ +*((uint32_t *)((CDB)+52)) = ISCSI_HTONL((ARGS)->get_attributes_allocation_length); \ +*((uint32_t *)((CDB)+72)) = ISCSI_HTONL((ARGS)->set_attributes_list_length); + +#define OSD_DECAP_CDB(CDB, EXT_CDB, ARGS) \ +(ARGS)->opcode = (CDB)[0]; \ +(ARGS)->control = (CDB)[1]; \ +(ARGS)->security = (CDB)[6]; \ +(ARGS)->add_cdb_len = (CDB)[7]; \ +(ARGS)->service_action = ISCSI_NTOHS(*((uint16_t *)((CDB)+8))); \ +(ARGS)->options_byte = (CDB)[10]; \ +(ARGS)->second_options_byte = (CDB)[11]; \ +(ARGS)->GroupID = ISCSI_NTOHL(*((uint32_t *)((CDB)+12))); \ +(ARGS)->UserID = ISCSI_NTOHLL(*((uint64_t *)((EXT_CDB)-16+16))); \ +(ARGS)->SessionID = ISCSI_NTOHL(*((uint32_t *)((EXT_CDB)-16+24))); \ +(ARGS)->length = ISCSI_NTOHLL(*((uint64_t *)((EXT_CDB)-16+28))); \ +(ARGS)->offset = ISCSI_NTOHLL(*((uint64_t *)((EXT_CDB)-16+36))); \ +(ARGS)->get_attributes_page = ISCSI_NTOHL(*((uint32_t *)((EXT_CDB)-16+44))); \ +(ARGS)->get_attributes_list_length = ISCSI_NTOHL(*((uint32_t *)((EXT_CDB)-16+48))); \ +(ARGS)->get_attributes_allocation_length = ISCSI_NTOHL(*((uint32_t *)((EXT_CDB)-16+52))); \ +(ARGS)->set_attributes_list_length = ISCSI_NTOHL(*((uint32_t *)((EXT_CDB)-16+72))); + +#define OSD_PRINT_CDB(CDB, EXT_CDB) \ +PRINT("opcode = 0x%x\n", CDB[0]); \ +PRINT("control = 0x%x\n", CDB[1]); \ +PRINT("security = 0x%x\n", CDB[6]); \ +PRINT("add_cdb_len = %u\n", CDB[7]); \ +PRINT("service_action = 0x%x\n", ISCSI_NTOHS(*(uint16_t*)(CDB+8))); \ +PRINT("options byte 1 = 0x%x\n", CDB[10]); \ +PRINT("options byte 2 = 0x%x\n", CDB[11]); \ +PRINT("group id = 0x%x\n", ISCSI_NTOHL(*(uint32_t*)(CDB+12))); \ +PRINT("user id = 0x%llx\n", ISCSI_NTOHLL(*(uint64_t*)(EXT_CDB-16+16))); \ +PRINT("session id = 0x%x\n", ISCSI_NTOHL(*(uint32_t*)(EXT_CDB-16+24))); \ +PRINT("length = %llu\n", ISCSI_NTOHLL(*(uint64_t*)(EXT_CDB-16+28))); \ +PRINT("offset = %llu\n", ISCSI_NTOHLL(*(uint64_t*)(EXT_CDB-16+36))); \ +PRINT("get attr page = %u\n", ISCSI_NTOHL(*(uint32_t*)(EXT_CDB-16+44))); \ +PRINT("get list len = %u\n", ISCSI_NTOHL(*(uint32_t*)(EXT_CDB-16+48))); \ +PRINT("get alloc len = %u\n", ISCSI_NTOHL(*(uint32_t*)(EXT_CDB-16+52))); \ +PRINT("set list len = %u\n", ISCSI_NTOHL(*(uint32_t*)(EXT_CDB-16+72))); + +#endif /* OSD_H */ diff --git a/external/bsd/iscsi/dist/include/osd_ops.h b/external/bsd/iscsi/dist/include/osd_ops.h new file mode 100644 index 000000000000..c9a754c94fb9 --- /dev/null +++ b/external/bsd/iscsi/dist/include/osd_ops.h @@ -0,0 +1,61 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2002, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Transport-independent Methods + */ + + +#ifndef _OSD_OPS_H_ +#define _OSD_OPS_H_ + +#include "osd.h" + +typedef struct osd_ops_mem { + const void *send_data; + uint64_t send_len; + int send_sg; + void *recv_data; + uint64_t recv_len; + int recv_sg; +} OSD_OPS_MEM; + +int osd_create_group(void *, int (*)(void *, osd_args_t *, OSD_OPS_MEM *), uint32_t *); +int osd_remove_group(void *, uint32_t , int (*)(void *, osd_args_t *, OSD_OPS_MEM *)); +int osd_create(void *, uint32_t , int (*)(void *, osd_args_t *, OSD_OPS_MEM *), uint64_t *); +int osd_remove(void *, uint32_t , uint64_t , int (*)(void *, osd_args_t *, OSD_OPS_MEM *)); +int osd_write(void *, uint32_t , uint64_t , uint64_t , uint64_t , const void *, int , int (*)(void *, osd_args_t *, OSD_OPS_MEM *)); +int osd_read(void *, uint32_t , uint64_t , uint64_t , uint64_t , void *, int , int (*)(void *, osd_args_t *, OSD_OPS_MEM *)); +int osd_set_one_attr(void *, uint32_t , uint64_t , uint32_t , uint32_t , uint32_t , void *, int (*)(void *, osd_args_t *, OSD_OPS_MEM *)); +int osd_get_one_attr(void *, uint32_t , uint64_t , uint32_t , uint32_t , uint32_t , int (*)(void *, osd_args_t *, OSD_OPS_MEM *), uint16_t *, void *); + +#endif diff --git a/external/bsd/iscsi/dist/include/parameters.h b/external/bsd/iscsi/dist/include/parameters.h new file mode 100644 index 000000000000..efb6c4573091 --- /dev/null +++ b/external/bsd/iscsi/dist/include/parameters.h @@ -0,0 +1,170 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _PARAMETERS_H_ +#define _PARAMETERS_H_ + +typedef struct MD5Context MD5Context_t; + + +#define ISCSI_PARAM_MAX_LEN 256 +#define ISCSI_PARAM_KEY_LEN 64 + +/* Parameter Type */ + +#define ISCSI_PARAM_TYPE_DECLARATIVE 1 +#define ISCSI_PARAM_TYPE_DECLARE_MULTI 2 /* for TargetName and + * TargetAddress */ +#define ISCSI_PARAM_TYPE_NUMERICAL 3 +#define ISCSI_PARAM_TYPE_NUMERICAL_Z 4 /* zero represents no limit */ +#define ISCSI_PARAM_TYPE_BINARY_OR 5 +#define ISCSI_PARAM_TYPE_BINARY_AND 6 +#define ISCSI_PARAM_TYPE_LIST 7 + +#define ISCSI_CHAP_DATA_LENGTH 16 +#define ISCSI_CHAP_STRING_LENGTH 256 + +#define ISCSI_PARAM_STATUS_AUTH_FAILED -2 +#define ISCSI_PARAM_STATUS_FAILED -1 + +/* types of authentication which the initiator can select */ +enum { + AuthNone, + AuthCHAP, + AuthKerberos, + AuthSRP +}; + +/* types of digest which the initiator can select */ +enum { + DigestNone = 0x0, + DigestHeader = 0x01, + DigestData = 0x02 + /* these are bit masks, extend accordingly */ +}; + +typedef struct iscsi_parameter_item_t { + char value[ISCSI_PARAM_MAX_LEN]; + struct iscsi_parameter_item_t *next; +} iscsi_parameter_value_t; + +/* this struct defines the credentials a user has */ +typedef struct iscsi_cred_t { + char *user; /* user's name */ + char *auth_type; /* preferred authentication type */ + char *shared_secret; /* the shared secret which will be used */ +} iscsi_cred_t; + +/* + * Structure for storing negotiated parameters that are frequently accessed + * on an active session + */ +typedef struct iscsi_sess_param_t { + uint32_t max_burst_length; + uint32_t first_burst_length; + uint32_t max_data_seg_length; + iscsi_cred_t cred; + uint8_t initial_r2t; + uint8_t immediate_data; + uint8_t header_digest; + uint8_t data_digest; + uint8_t auth_type; + uint8_t mutual_auth; + uint8_t digest_wanted; +} iscsi_sess_param_t; + +typedef struct iscsi_parameter_t { + char key[ISCSI_PARAM_KEY_LEN]; /* key */ + int type; /* type of parameter */ + char valid[ISCSI_PARAM_MAX_LEN]; /* list of valid values */ + char dflt[ISCSI_PARAM_MAX_LEN]; /* default value */ + iscsi_parameter_value_t *value_l; /* value list */ + char offer_rx[ISCSI_PARAM_MAX_LEN]; /* outgoing offer */ + char offer_tx[ISCSI_PARAM_MAX_LEN]; /* incoming offer */ + char answer_tx[ISCSI_PARAM_MAX_LEN]; /* outgoing answer */ + char answer_rx[ISCSI_PARAM_MAX_LEN]; /* incoming answer */ + char negotiated[ISCSI_PARAM_MAX_LEN]; /* negotiated value */ + int tx_offer; /* sent offer */ + int rx_offer; /* received offer */ + int tx_answer; /* sent answer */ + int rx_answer; /* received answer */ + int reset; /* reset value_l */ + struct iscsi_parameter_t *next; +} iscsi_parameter_t; + +int param_list_add(iscsi_parameter_t ** , int , const char *, const char *, const char *); +int param_list_print(iscsi_parameter_t * ); +int param_list_destroy(iscsi_parameter_t * ); +int param_text_add(iscsi_parameter_t *, const char *, const char *, char *, int *, int, int ); +int param_text_parse(iscsi_parameter_t *, iscsi_cred_t *, char *, int , char *, int *, int, int); +int param_text_print(char *, uint32_t ); +int param_num_vals(iscsi_parameter_t * , char *); +int param_val_reset(iscsi_parameter_t * , const char *); +char *param_val(iscsi_parameter_t * , const char *); +char *param_val_which(iscsi_parameter_t * , const char *, int ); +char *param_offer(iscsi_parameter_t * , char *); +char *param_answer(iscsi_parameter_t * , char *); +iscsi_parameter_t *param_get(iscsi_parameter_t * , const char *); +int driver_atoi(const char *); +int param_atoi(iscsi_parameter_t * , const char *); +int param_equiv(iscsi_parameter_t * , const char *, const char *); +int param_commit(iscsi_parameter_t * ); +void set_session_parameters(iscsi_parameter_t * , iscsi_sess_param_t * ); + +/* + * Macros + */ + +#define PARAM_LIST_DESTROY(LIST, ELSE) \ +if (param_list_destroy(LIST)!=0) { \ + iscsi_trace_error(__FILE__, __LINE__, "param_list_destroy() failed\n"); \ + ELSE; \ +} + +#define PARAM_LIST_ADD(LIST, TYPE, KEY, DFLT, VALID, ELSE) \ +if (param_list_add(LIST, TYPE, KEY, DFLT, VALID)!=0) { \ + iscsi_trace_error(__FILE__, __LINE__, "param_list_add() failed\n"); \ + ELSE; \ +} + +#define PARAM_TEXT_ADD(LIST, KEY, VAL, TEXT, LEN, SIZE, OFFER, ELSE ) \ +if (param_text_add(LIST, KEY, VAL, TEXT, LEN, SIZE, OFFER)!=0) { \ + iscsi_trace_error(__FILE__, __LINE__, "param_text_add() failed\n"); \ + ELSE; \ +} + +#define PARAM_TEXT_PARSE(LIST, CRED, TEXT, LEN, TEXT_OUT, LEN_OUT, SIZE, OFFER, ELSE ) \ +if (param_text_parse(LIST, CRED, TEXT, LEN, TEXT_OUT, LEN_OUT, SIZE, OFFER)!=0) { \ + iscsi_trace_error(__FILE__, __LINE__, "param_text_parse_offer() failed\n"); \ + ELSE; \ +} +#endif diff --git a/external/bsd/iscsi/dist/include/scsi_cmd_codes.h b/external/bsd/iscsi/dist/include/scsi_cmd_codes.h new file mode 100644 index 000000000000..82ce1ce10881 --- /dev/null +++ b/external/bsd/iscsi/dist/include/scsi_cmd_codes.h @@ -0,0 +1,153 @@ +/* $NetBSD: scsi_cmd_codes.h,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#ifndef SCSI_CMD_CODES_H_ +#define SCSI_CMD_CODES_H_ + +/* information taken from SPC3, T10/1416-D Revision 23, from www.t10.org */ + +enum { + TEST_UNIT_READY = 0x00, + READ_6 = 0x08, + WRITE_6 = 0x0a, + INQUIRY = 0x12, + MODE_SELECT_6 = 0x15, + RESERVE_6 = 0x16, + RELEASE_6 = 0x17, + MODE_SENSE_6 = 0x1a, + STOP_START_UNIT = 0x1b, + READ_CAPACITY = 0x25, + READ_10 = 0x28, + WRITE_10 = 0x2a, + WRITE_VERIFY = 0x2e, + VERIFY = 0x2f, + SYNC_CACHE = 0x35, + LOG_SENSE = 0x4d, + MODE_SELECT_10 = 0x55, + RESERVE_10 = 0x56, + RELEASE_10 = 0x57, + MODE_SENSE_10 = 0x5a, + PERSISTENT_RESERVE_IN = 0x5e, + PERSISTENT_RESERVE_OUT = 0x5f, + REPORT_LUNS = 0xa0 +}; + +#define SIX_BYTE_COMMAND(op) ((op) <= 0x1f) +#define TEN_BYTE_COMMAND(op) ((op) > 0x1f && (op) <= 0x5f) + +enum { + ISCSI_MODE_SENSE_LEN = 11 +}; + +/* miscellaneous definitions */ +enum { + DISK_PERIPHERAL_DEVICE = 0x0, + + INQUIRY_EVPD_BIT = 0x01, + + INQUIRY_UNIT_SERIAL_NUMBER_VPD = 0x80, + INQUIRY_DEVICE_IDENTIFICATION_VPD = 0x83, + INQUIRY_SUPPORTED_VPD_PAGES = 0x0, + INQUIRY_DEVICE_PIV = 0x1, + + INQUIRY_IDENTIFIER_TYPE_T10 = 0x1, + INQUIRY_IDENTIFIER_TYPE_EUI64 = 0x2, + INQUIRY_IDENTIFIER_TYPE_NAA = 0x3, + + INQUIRY_DEVICE_ASSOCIATION_LOGICAL_UNIT = 0x0, + INQUIRY_DEVICE_ASSOCIATION_TARGET_PORT = 0x1, + INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE = 0x2, + + INQUIRY_DEVICE_CODESET_UTF8 = 0x3, + INQUIRY_DEVICE_ISCSI_PROTOCOL = 0x5, + INQUIRY_DEVICE_T10_VENDOR = 0x1, + INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME = 0x8, + + EXTENDED_INQUIRY_DATA_VPD = 0x86, + EXTENDED_INQUIRY_REF_TAG_OWNER = 0x08, + EXTENDED_INQUIRY_GUARD_CHECK = 0x04, + EXTENDED_INQUIRY_APPLICATION_CHECK = 0x02, + EXTENDED_INQUIRY_REFERENCE_CHECK = 0x01, + + EXTENDED_INQUIRY_GROUP_SUPPORT = 0x10, + EXTENDED_INQUIRY_PRIORITY_SUPPORT = 0x8, + EXTENDED_INQUIRY_QUEUE_HEAD_SUPPORT = 0x4, + EXTENDED_INQUIRY_ORDERED_SUPPORT = 0x2, + EXTENDED_INQUIRY_SIMPLE_SUPPORT = 0x1, + + PERSISTENT_RESERVE_IN_SERVICE_ACTION_MASK = 0x1f, + PERSISTENT_RESERVE_IN_READ_KEYS = 0x0, + PERSISTENT_RESERVE_IN_READ_RESERVATION = 0x1, + PERSISTENT_RESERVE_IN_REPORT_CAPABILITIES = 0x2, + PERSISTENT_RESERVE_IN_READ_FULL_STATUS = 0x3, + + PERSISTENT_RESERVE_IN_CRH = 0x10, + PERSISTENT_RESERVE_IN_SIP_C = 0x8, + PERSISTENT_RESERVE_IN_ATP_C = 0x4, + PERSISTENT_RESERVE_IN_PTPL_C = 0x1, /* persistence through power loss */ + PERSISTENT_RESERVE_IN_TMV = 0x80, /* Type Mask Valid */ + PERSISTENT_RESERVE_IN_PTPL_A = 0x01, /* persistence through power loss activated */ + + PERSISTENT_RESERVE_IN_WR_EX_AR = 0x80, + PERSISTENT_RESERVE_IN_EX_AC_RD = 0x40, + PERSISTENT_RESERVE_IN_WR_AC_RD = 0x20, + PERSISTENT_RESERVE_IN_EX_AC = 0x08, + PERSISTENT_RESERVE_IN_WR_EX = 0x02, + PERSISTENT_RESERVE_IN_EX_AC_AR = 0x01, + + WIDE_BUS_16 = 0x20, + WIDE_BUS_32 = 0x40, + + SCSI_VERSION_SPC = 0x03, + SCSI_VERSION_SPC2 = 0x04, + SCSI_VERSION_SPC3 = 0x05, + + /* used in MODE_SENSE_10 */ + DISABLE_BLOCK_DESCRIPTORS = 0x08, + LONG_LBA_ACCEPTED = 0x10, + PAGE_CONTROL_MASK = 0xc0, + PAGE_CONTROL_CURRENT_VALUES = 0x0, + PAGE_CONTROL_CHANGEABLE_VALUES = 0x40, + PAGE_CONTROL_DEFAULT_VALUES = 0x80, + PAGE_CONTROL_SAVAED_VALUES = 0xc0, + PAGE_CODE_MASK = 0x3f, + + ASC_LUN_UNSUPPORTED = 0x25, + ASCQ_LUN_UNSUPPORTED = 0x0, + + SCSI_SKEY_ILLEGAL_REQUEST = 0x05 +}; + +/* device return codes */ +enum { + SCSI_SUCCESS = 0x0, + SCSI_CHECK_CONDITION = 0x02 +}; + +#endif /* !SCSI_CMD_CODES_H_ */ diff --git a/external/bsd/iscsi/dist/include/so.h b/external/bsd/iscsi/dist/include/so.h new file mode 100644 index 000000000000..e1e6b8ea4638 --- /dev/null +++ b/external/bsd/iscsi/dist/include/so.h @@ -0,0 +1,56 @@ + +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2002, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _SO_H +#define _SO_H + +#ifndef _SCSI_H +#include "scsi.h" +#endif + +#ifndef _GENDISK_H +#include +#endif + +typedef struct scsi_osd { + Scsi_Device *device; + unsigned capacity; /* size in blocks */ + unsigned char ready; /* flag ready for FLOPTICAL */ + unsigned char write_prot; /* flag write_protect for rmvable dev */ + unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ + unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ + unsigned has_part_table:1; /* has partition table */ +} Scsi_Osd; + +#endif diff --git a/external/bsd/iscsi/dist/include/storage.h b/external/bsd/iscsi/dist/include/storage.h new file mode 100644 index 000000000000..efd2e6393a5b --- /dev/null +++ b/external/bsd/iscsi/dist/include/storage.h @@ -0,0 +1,96 @@ +/* $NetBSD: storage.h,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#ifndef STORAGE_H_ +#define STORAGE_H_ + +#include "defs.h" + +enum { + DE_EXTENT, + DE_DEVICE +}; + +/* a device can be made up of an extent or another device */ +typedef struct disc_de_t { + int32_t type; /* device or extent */ + uint64_t size; /* size of underlying extent or device */ + union { + struct disc_extent_t *xp; /* pointer to extent */ + struct disc_device_t *dp; /* pointer to device */ + } u; +} disc_de_t; + +/* this struct describes an extent of storage */ +typedef struct disc_extent_t { + char *extent; /* extent name */ + char *dev; /* device associated with it */ + uint64_t sacred; /* offset of extent from start of device */ + uint64_t len; /* size of extent */ + int fd; /* in-core file descriptor */ + int used; /* extent has been used in a device */ +} disc_extent_t; + +DEFINE_ARRAY(extv_t, disc_extent_t); + +/* this struct describes a device */ +typedef struct disc_device_t { + char *dev; /* device name */ + int raid; /* RAID level */ + uint64_t off; /* current offset in device */ + uint64_t len; /* size of device */ + uint32_t size; /* size of device/extent array */ + uint32_t c; /* # of entries in device/extents */ + disc_de_t *xv; /* device/extent array */ + int used; /* device has been used in a device/target */ +} disc_device_t; + +DEFINE_ARRAY(devv_t, disc_device_t); + +enum { + TARGET_READONLY = 0x01 +}; + +/* this struct describes an iscsi target's associated features */ +typedef struct disc_target_t { + char *target; /* target name */ + disc_de_t de; /* pointer to its device */ + uint16_t port; /* port to listen on */ + char *mask; /* mask to export it to */ + uint32_t flags; /* any flags */ + uint16_t tsih; /* target session identifying handle */ + char *iqn; /* assigned iqn - can be NULL */ +} disc_target_t; + +DEFINE_ARRAY(targv_t, disc_target_t); + +int read_conf_file(const char *, targv_t *, devv_t *, extv_t *); +void write_pid_file(const char *); + +#endif /* !STORAGE_H_ */ diff --git a/external/bsd/iscsi/dist/include/target.h b/external/bsd/iscsi/dist/include/target.h new file mode 100644 index 000000000000..b81b582590c7 --- /dev/null +++ b/external/bsd/iscsi/dist/include/target.h @@ -0,0 +1,121 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _TARGET_H_ +#define _TARGET_H_ + +#include "iscsi.h" +#include "iscsiutil.h" +#include "parameters.h" +#include "storage.h" + +/* Default configuration */ + +#define DEFAULT_TARGET_MAX_SESSIONS 16 /* n+1 */ +#define DEFAULT_TARGET_NUM_LUNS 1 +#define DEFAULT_TARGET_BLOCK_LEN 512 +#define DEFAULT_TARGET_NUM_BLOCKS 204800 +#define DEFAULT_TARGET_NAME "iqn.1994-04.org.netbsd.iscsi-target" +#define DEFAULT_TARGET_QUEUE_DEPTH 8 +#define DEFAULT_TARGET_TCQ 0 + +enum { + MAX_TGT_NAME_SIZE = 512, + MAX_INITIATOR_ADDRESS_SIZE = 256, + MAX_CONFIG_FILE_NAME = 512, + + ISCSI_IPv4 = AF_INET, + ISCSI_IPv6 = AF_INET6, + ISCSI_UNSPEC = PF_UNSPEC, + + MAXSOCK = 8 +}; + +/* global variables, moved from target.c */ +typedef struct globals_t { + char targetname[MAX_TGT_NAME_SIZE]; /* name of target */ + uint16_t port; /* target port */ + iscsi_socket_t sock; /* socket on which it's listening */ + int sockc; /* # of live sockets on which it's listening */ + iscsi_socket_t sockv[MAXSOCK]; /* sockets on which it's listening */ + int famv[MAXSOCK]; /* address families */ + int state; /* current state of target */ + int listener_pid; /* PID on which it's listening */ + volatile int listener_listening; /* whether a listener is listening */ + char targetaddress[MAX_TGT_NAME_SIZE]; /* iSCSI TargetAddress set after iscsi_sock_accept() */ + targv_t *tv; /* array of target devices */ + int address_family; /* global default IP address family */ + int max_sessions; /* maximum number of sessions */ + char config_file[MAX_CONFIG_FILE_NAME]; /* config file name */ + uint32_t last_tsih; /* the last TSIH that was used */ +} globals_t; + +/* session parameters */ +typedef struct target_session_t { + int id; + int d; + iscsi_socket_t sock; + uint16_t cid; + uint32_t StatSN; + uint32_t ExpCmdSN; + uint32_t MaxCmdSN; + uint8_t *buff; + int UsePhaseCollapsedRead; + int IsFullFeature; + int IsLoggedIn; + int LoginStarted; + uint64_t isid; + int tsih; + globals_t *globals; + iscsi_worker_t worker; + iscsi_parameter_t *params; + iscsi_sess_param_t sess_params; + char initiator[MAX_INITIATOR_ADDRESS_SIZE]; + int address_family; + int32_t last_tsih; +} target_session_t; + +typedef struct target_cmd_t { + iscsi_scsi_cmd_args_t *scsi_cmd; + int (*callback) (void *); + void *callback_arg; +} target_cmd_t; + +int target_init(globals_t *, targv_t *, char *); +int target_shutdown(globals_t *); +int target_listen(globals_t *); +int target_transfer_data(target_session_t *, iscsi_scsi_cmd_args_t *, struct iovec *, int); + +int find_target_tsih(globals_t *, int); +int find_target_iqn(target_session_t *); + +#endif /* _TARGET_H_ */ diff --git a/external/bsd/iscsi/dist/include/tests.h b/external/bsd/iscsi/dist/include/tests.h new file mode 100644 index 000000000000..ddd26283b28d --- /dev/null +++ b/external/bsd/iscsi/dist/include/tests.h @@ -0,0 +1,52 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + + +#ifndef _SCSI_TEST_H +#define _SCSI_TEST_H + +#include "initiator.h" + +int test_all(int , int ); +int integrity_test(uint32_t , uint32_t , uint32_t , int ); +int nop_test(uint32_t , uint32_t , uint32_t ); +int latency_test(uint64_t , uint32_t , uint8_t , uint32_t ); +int throughput_test(uint32_t , uint32_t , uint32_t , uint32_t , uint32_t , int , int ); +int read_or_write(uint64_t , uint32_t , uint32_t , uint32_t , uint32_t , uint8_t *, int , int ); +int nop_out(uint64_t , int , int , int , const char *); +int read_capacity(uint64_t , uint32_t , uint32_t *, uint32_t *); +int write_read_test(uint64_t , uint32_t , int ); +int scatter_gather_test(uint64_t , uint32_t , uint8_t ); + +int ii_test_all(void); + +#endif diff --git a/external/bsd/iscsi/dist/src/Makefile.in b/external/bsd/iscsi/dist/src/Makefile.in new file mode 100644 index 000000000000..11db60d9bc6e --- /dev/null +++ b/external/bsd/iscsi/dist/src/Makefile.in @@ -0,0 +1,85 @@ +# +# Compiler Flags. Warning: -O causes problems w/ pthread +# + +SHELL= /bin/sh + +srcdir=@srcdir@ +VPATH=@srcdir@ + +prefix=@prefix@ +exec_prefix=@exec_prefix@ +BINDIR=$(exec_prefix)/bin +LIBDIR=$(exec_prefix)/lib +INCDIR=$(prefix)/include +MANDIR=$(prefix)/man +SYSCONFDIR=@sysconfdir@ + +CC= @CC@ +PTHREAD_FLAGS= -pthread +PTHREAD_LDFLAGS= -pthread +PTHREAD_LIBS= -lpthread +GCC_CFLAGS= -Wall -Wstrict-prototypes -fno-strict-aliasing -fno-common -Wno-trigraphs +COMMON_CFLAGS += -DCONFIG_ISCSI_DEBUG -D_FILE_OFFSET_BITS=64 -D_GNU_SOURCE +COMMON_CFLAGS += -DHAVE_CONFIG_H +COMMON_CFLAGS += -I${INCDIR} +CFLAGS= @CFLAGS@ ${GCC_CFLAGS} ${COMMON_CFLAGS} -I${INCLUDE} ${PTHREAD_FLAGS} +LIBS= @LIBS@ + +INSTALL= @INSTALL@ +PREFIX= @prefix@ + +INCLUDE = ../include + +# +# Compilation Targets +# + +TARGETS = iscsi-target # osd +INITIATORS= iscsifs + +all: $(TARGETS) + +all-initiator: ${INITIATORS} + +# +# User-level Targets +# +COMPATOBJS= strlcpy.o snprintf.o strtoll.o uuid.o + +USER_TARGET_OBJS = target.o iscsi.o util.o parameters.o netmask.o conffile.o storage.o md5c.o md5hl.c ${COMPATOBJS} +iscsi-target: iscsi-target.c disk.c $(USER_TARGET_OBJS) + $(CC) $(CFLAGS) iscsi-target.c disk.c $(USER_TARGET_OBJS) ${PTHREAD_LDFLAGS} ${PTHREAD_LIBS} ${LIBS} -o iscsi-target +osd: osd-target.c osd.c $(USER_TARGET_OBJS) + $(CC) $(CFLAGS) osd-target.c osd.c $(USER_TARGET_OBJS) ${PTHREAD_LDFLAGS} ${PTHREAD_LIBS} ${LIBS} -o osd + +# +# Test harness (initiators) +# + +iscsifs: iscsifs.o iscsi.o util.o initiator.o parameters.o conffile.o virtdir.o md5c.o md5hl.o + $(CC) iscsifs.o iscsi.o util.o initiator.o parameters.o md5c.o md5hl.o conffile.o virtdir.o -o iscsifs ${PTHREAD_LDFLAGS} ${PTHREAD_LIBS} -L${LIBDIR} -Wl,-R${LIBDIR} ${LIBS} -lfuse + +# +# Dependencies +# + +osd_ops.o: $(INCLUDE)/iscsiutil.h $(INCLUDE)/osd.h $(INCLUDE)/osd_ops.h osd_ops.c +util.o: util.c $(INCLUDE)/iscsiutil.h +parameters.o: parameters.c $(INCLUDE)/parameters.h $(INCLUDE)/iscsiutil.h md5c.o md5hl.o +usocktest.o: usocktest.c $(INCLUDE)/iscsiutil.h +disk.o: disk.c $(INCLUDE)/device.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/iscsi.h +osd.o: osd.c $(INCLUDE)/osd.h $(INCLUDE)/device.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/iscsi.h +iscsi.o: iscsi.c $(INCLUDE)/iscsi.h $(INCLUDE)/iscsiutil.h +iscsi-harness.o: iscsi-harness.c $(INCLUDE)/iscsi.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/osd.h $(INCLUDE)/initiator.h $(INCLUDE)/tests.h $(INCLUDE)/parameters.h $(INCLUDE)/osd_ops.h +utarget.o: utarget.c $(INCLUDE)/iscsi.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/target.h $(INCLUDE)/device.h +tests.o: tests.c $(INCLUDE)/iscsi.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/initiator.h $(INCLUDE)/tests.h +target.o: target.c $(INCLUDE)/iscsi.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/target.h $(INCLUDE)/parameters.h +initiator.o: initiator.c $(INCLUDE)/iscsi.h $(INCLUDE)/iscsiutil.h $(INCLUDE)/initiator.h $(INCLUDE)/parameters.h + +# +# Util +# + +clean: + rm -f $(INITIATORS) $(TARGETS) *.o *.core diff --git a/external/bsd/iscsi/dist/src/TODO b/external/bsd/iscsi/dist/src/TODO new file mode 100644 index 000000000000..a4f776688e41 --- /dev/null +++ b/external/bsd/iscsi/dist/src/TODO @@ -0,0 +1,49 @@ +To do +===== +add kevent +add HUP support to read sig and targets file +CRC/digests +finish reservations +RAID 1 rebuilding, breaking etc +proper allow_netmask support for IPv6 +add ability to add a target in, take one out (if !busy) +proper IPv6 support in harness + +Done +==== +fix debug to be command-line driven +unsigned char -> uint8_t +make target guess method to use depending on size of file/device +sprintf -> snprintf +strcpy -> strlcpy +autoconf +fix lint +Implement name-based stuff - no more inet_addr stuff +split into separate targets +rc.d scripts +move to globals_t in target.c +configuration +Make it so that target can take an iqn as its address +Manual page for iscsi-target +manual page for targets config file +get rid of hardcoded CHAP stuff +use syslog to log info +use syslog to log errors +fix memory leak of user name +error if no config file +mmap & munmap +get port from cmd line +raid0 +add discovery masking +clean up IPv6 +add socklen_t awareness +add uuid +Solaris initiator compatibility +fix 64-byte swapping macros +add reservations - RESERVE_6 and RELEASE_6 done +pass addr family in sess structure +add poll configure glue +use poll if we have it +proper IPv6 support in target +VPD 80 handling +bind to cmdline port properly now too diff --git a/external/bsd/iscsi/dist/src/conffile.c b/external/bsd/iscsi/dist/src/conffile.c new file mode 100644 index 000000000000..39255ffc3b1f --- /dev/null +++ b/external/bsd/iscsi/dist/src/conffile.c @@ -0,0 +1,281 @@ +/* $NetBSD: conffile.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "conffile.h" + +/* start of split routines */ + +/* open a file */ +int +conffile_open(conffile_t *sp, const char *f, const char *mode, const char *sep, const char *comment) +{ + (void) memset(sp, 0x0, sizeof(*sp)); + if ((sp->fp = fopen(f, mode)) == NULL) { + (void) fprintf(stderr, "can't open `%s' `%s' (%s)\n", f, mode, strerror(errno)); + return 0; + } + (void) strlcpy(sp->name, f, sizeof(sp->name)); + sp->sep = sep; + sp->comment = comment; + sp->readonly = (strcmp(mode, "r") == 0); + return 1; +} + +/* close a file */ +void +conffile_close(conffile_t *sp) +{ + (void) fclose(sp->fp); +} + +/* read the next line from the file */ +static char * +read_line(conffile_t *sp, ent_t *ep) +{ + char *from; + + if (fgets(ep->buf, sizeof(ep->buf), sp->fp) == NULL) { + return NULL; + } + sp->lineno += 1; + for (from = ep->buf ; *from && isspace((unsigned int)*from) ; from++) { + } + return from; +} + +/* return 1 if this line contains no entry */ +static int +iscomment(conffile_t *sp, char *from) +{ + return (*from == 0x0 || *from == '\n' || strchr(sp->comment, *from) != NULL); +} + +/* split the entry up into fields */ +int +conffile_split(conffile_t *sp, ent_t *ep, char *from) +{ + FILE *fp; + const char *seps; + char *to; + char was; + int sepseen; + int cc; + + seps = (sp == NULL) ? " \t" : sp->sep; + fp = (sp == NULL) ? stdin : sp->fp; + for (ep->sv.c = 0 ; *from && *from != '\n' ; ) { + for (to = from, sepseen = 0 ; *to && *to != '\n' && strchr(seps, *to) == NULL ; to++) { + if (*to == '\\') { + if (*(to + 1) == '\n') { + cc = (int)(to - ep->buf); + if (fgets(&ep->buf[cc], (int)(sizeof(ep->buf) - cc), fp) != NULL) { + if (sp != NULL) { + sp->lineno += 1; + } + } + } else { + sepseen = 1; + to++; + } + } + } + ALLOC(char *, ep->sv.v, ep->sv.size, ep->sv.c, 14, 14, "conffile_getent", exit(EXIT_FAILURE)); + ep->sv.v[ep->sv.c++] = from; + was = *to; + *to = 0x0; + if (sepseen) { + char *cp; + + for (cp = from ; *cp ; cp++) { + if (strchr(seps, *cp) != NULL) { + (void) strcpy(cp - 1, cp); + } + } + } + if (was == 0x0 || was == '\n') { + break; + } + for (from = to + 1 ; *from && *from != '\n' && strchr(seps, *from) != NULL ; from++) { + } + } + return 1; +} + +/* get the next entry */ +int +conffile_getent(conffile_t *sp, ent_t *ep) +{ + char *from; + + for (;;) { + if ((from = read_line(sp, ep)) == NULL) { + return 0; + } + if (iscomment(sp, from)) { + continue; + } + return conffile_split(sp, ep, from); + } +} + +/* return the line number */ +int +conffile_get_lineno(conffile_t *sp) +{ + return sp->lineno; +} + +/* return the name */ +char * +conffile_get_name(conffile_t *sp) +{ + return sp->name; +} + +/* return the entry based upon the contents of field `f' */ +int +conffile_get_by_field(conffile_t *sp, ent_t *ep, int f, char *val) +{ + while (conffile_getent(sp, ep)) { + if (ep->sv.c > (uint32_t)f && strcmp(ep->sv.v[f], val) == 0) { + return 1; + } + } + return 0; +} + +/* check that we wrote `cc' chars of `buf' to `fp' */ +static int +safe_write(FILE *fp, char *buf, unsigned cc) +{ + return fwrite(buf, sizeof(char), cc, fp) == cc; +} + +#if 0 +/* check that we wrote the entry correctly */ +static int +safe_write_ent(FILE *fp, conffile_t *sp, ent_t *ep) +{ + char buf[BUFSIZ]; + int cc; + int i; + + for (cc = i = 0 ; i < ep->sv.c ; i++) { + cc += snprintf(&buf[cc], sizeof(buf) - cc, "%s%1.1s", ep->sv.v[i], (i == ep->sv.c - 1) ? "\n" : sp->sep); + } + return safe_write(fp, buf, cc); +} +#endif + +/* report an error and clear up */ +static int +report_error(FILE *fp, char *name, const char *fmt, ...) +{ + va_list vp; + + va_start(vp, fmt); + (void) vfprintf(stderr, fmt, vp); + va_end(vp); + if (fp) + (void) fclose(fp); + (void) unlink(name); + return 0; +} + +/* put the new entry (in place of ent[f] == val, if val is non-NULL) */ +int +conffile_putent(conffile_t *sp, int f, char *val, char *newent) +{ + ent_t e; + FILE *fp; + char name[MAXPATHLEN]; + char *from; + int fd; + + (void) strlcpy(name, "/tmp/split.XXXXXX", sizeof(name)); + if ((fd = mkstemp(name)) < 0) { + (void) fprintf(stderr, "can't mkstemp `%s' (%s)\n", name, strerror(errno)); + return 0; + } + fp = fdopen(fd, "w"); + (void) memset(&e, 0x0, sizeof(e)); + for (;;) { + if ((from = read_line(sp, &e)) == NULL) { + break; + } + if (iscomment(sp, from)) { + if (!safe_write(fp, e.buf, strlen(e.buf))) { + return report_error(fp, name, "Short write 1 to `%s' (%s)\n", name, strerror(errno)); + } + } + (void) conffile_split(sp, &e, from); + if (val != NULL && (uint32_t)f < e.sv.c && strcmp(val, e.sv.v[f]) == 0) { + /* replace it */ + if (!safe_write(fp, newent, strlen(newent))) { + return report_error(fp, name, "Short write 2 to `%s' (%s)\n", name, strerror(errno)); + } + } else { + if (!safe_write(fp, e.buf, strlen(e.buf))) { + return report_error(fp, name, "Short write 3 to `%s' (%s)\n", name, strerror(errno)); + } + } + } + if (val == NULL && !safe_write(fp, newent, strlen(newent))) { + return report_error(fp, name, "Short write 4 to `%s' (%s)\n", name, strerror(errno)); + } + (void) fclose(fp); + if (rename(name, sp->name) < 0) { + return report_error(NULL, name, "can't rename %s to %s (%s)\n", name, sp->name, strerror(errno)); + } + return 1; +} + +/* print the entry on stdout */ +void +conffile_printent(ent_t *ep) +{ + uint32_t i; + + for (i = 0 ; i < ep->sv.c ; i++) { + printf("(%d `%s') ", i, ep->sv.v[i]); + } + printf("\n"); +} diff --git a/external/bsd/iscsi/dist/src/configure b/external/bsd/iscsi/dist/src/configure new file mode 100755 index 000000000000..f294e98477c8 --- /dev/null +++ b/external/bsd/iscsi/dist/src/configure @@ -0,0 +1,5870 @@ +#! /bin/sh +# Guess values for system-dependent variables and create Makefiles. +# Generated by GNU Autoconf 2.61 for netbsd-iscsi 20080207. +# +# Report bugs to >. +# +# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +# 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +# This configure script is free software; the Free Software Foundation +# gives unlimited permission to copy, distribute and modify it. +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + +if test "x$CONFIG_SHELL" = x; then + if (eval ":") 2>/dev/null; then + as_have_required=yes +else + as_have_required=no +fi + + if test $as_have_required = yes && (eval ": +(as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=\$LINENO + as_lineno_2=\$LINENO + test \"x\$as_lineno_1\" != \"x\$as_lineno_2\" && + test \"x\`expr \$as_lineno_1 + 1\`\" = \"x\$as_lineno_2\") || { (exit 1); exit 1; } +") 2> /dev/null; then + : +else + as_candidate_shells= + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + case $as_dir in + /*) + for as_base in sh bash ksh sh5; do + as_candidate_shells="$as_candidate_shells $as_dir/$as_base" + done;; + esac +done +IFS=$as_save_IFS + + + for as_shell in $as_candidate_shells $SHELL; do + # Try only shells that exist, to save several forks. + if { test -f "$as_shell" || test -f "$as_shell.exe"; } && + { ("$as_shell") 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +_ASEOF +}; then + CONFIG_SHELL=$as_shell + as_have_required=yes + if { "$as_shell" 2> /dev/null <<\_ASEOF +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + +: +(as_func_return () { + (exit $1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = "$1" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test $exitcode = 0) || { (exit 1); exit 1; } + +( + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2") || { (exit 1); exit 1; } + +_ASEOF +}; then + break +fi + +fi + + done + + if test "x$CONFIG_SHELL" != x; then + for as_var in BASH_ENV ENV + do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + done + export CONFIG_SHELL + exec "$CONFIG_SHELL" "$as_myself" ${1+"$@"} +fi + + + if test $as_have_required = no; then + echo This script requires a shell more modern than all the + echo shells that I found on your system. Please install a + echo modern shell, or manually run the script under such a + echo shell if you do have one. + { (exit 1); exit 1; } +fi + + +fi + +fi + + + +(eval "as_func_return () { + (exit \$1) +} +as_func_success () { + as_func_return 0 +} +as_func_failure () { + as_func_return 1 +} +as_func_ret_success () { + return 0 +} +as_func_ret_failure () { + return 1 +} + +exitcode=0 +if as_func_success; then + : +else + exitcode=1 + echo as_func_success failed. +fi + +if as_func_failure; then + exitcode=1 + echo as_func_failure succeeded. +fi + +if as_func_ret_success; then + : +else + exitcode=1 + echo as_func_ret_success failed. +fi + +if as_func_ret_failure; then + exitcode=1 + echo as_func_ret_failure succeeded. +fi + +if ( set x; as_func_ret_success y && test x = \"\$1\" ); then + : +else + exitcode=1 + echo positional parameters were not saved. +fi + +test \$exitcode = 0") || { + echo No shell found that supports shell functions. + echo Please tell autoconf@gnu.org about your system, + echo including any error possibly output before this + echo message +} + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + + +exec 7<&0 &1 + +# Name of the host. +# hostname on some systems (SVR3.2, Linux) returns a bogus exit status, +# so uname gets run too. +ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q` + +# +# Initializations. +# +ac_default_prefix=/usr/local +ac_clean_files= +ac_config_libobj_dir=. +LIBOBJS= +cross_compiling=no +subdirs= +MFLAGS= +MAKEFLAGS= +SHELL=${CONFIG_SHELL-/bin/sh} + +# Identity of this package. +PACKAGE_NAME='netbsd-iscsi' +PACKAGE_TARNAME='netbsd-iscsi' +PACKAGE_VERSION='20080207' +PACKAGE_STRING='netbsd-iscsi 20080207' +PACKAGE_BUGREPORT='Alistair Crooks ' + +ac_unique_file="iscsi.c" +# Factoring default headers for most tests. +ac_includes_default="\ +#include +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef STDC_HEADERS +# include +# include +#else +# ifdef HAVE_STDLIB_H +# include +# endif +#endif +#ifdef HAVE_STRING_H +# if !defined STDC_HEADERS && defined HAVE_MEMORY_H +# include +# endif +# include +#endif +#ifdef HAVE_STRINGS_H +# include +#endif +#ifdef HAVE_INTTYPES_H +# include +#endif +#ifdef HAVE_STDINT_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif" + +ac_subst_vars='SHELL +PATH_SEPARATOR +PACKAGE_NAME +PACKAGE_TARNAME +PACKAGE_VERSION +PACKAGE_STRING +PACKAGE_BUGREPORT +exec_prefix +prefix +program_transform_name +bindir +sbindir +libexecdir +datarootdir +datadir +sysconfdir +sharedstatedir +localstatedir +includedir +oldincludedir +docdir +infodir +htmldir +dvidir +pdfdir +psdir +libdir +localedir +mandir +DEFS +ECHO_C +ECHO_N +ECHO_T +LIBS +build_alias +host_alias +target_alias +INSTALL_PROGRAM +INSTALL_SCRIPT +INSTALL_DATA +CC +CFLAGS +LDFLAGS +CPPFLAGS +ac_ct_CC +EXEEXT +OBJEXT +RANLIB +CPP +GREP +EGREP +LIBOBJS +LTLIBOBJS' +ac_subst_files='' + ac_precious_vars='build_alias +host_alias +target_alias +CC +CFLAGS +LDFLAGS +LIBS +CPPFLAGS +CPP' + + +# Initialize some variables set by options. +ac_init_help= +ac_init_version=false +# The variables have the same names as the options, with +# dashes changed to underlines. +cache_file=/dev/null +exec_prefix=NONE +no_create= +no_recursion= +prefix=NONE +program_prefix=NONE +program_suffix=NONE +program_transform_name=s,x,x, +silent= +site= +srcdir= +verbose= +x_includes=NONE +x_libraries=NONE + +# Installation directory options. +# These are left unexpanded so users can "make install exec_prefix=/foo" +# and all the variables that are supposed to be based on exec_prefix +# by default will actually change. +# Use braces instead of parens because sh, perl, etc. also accept them. +# (The list follows the same order as the GNU Coding Standards.) +bindir='${exec_prefix}/bin' +sbindir='${exec_prefix}/sbin' +libexecdir='${exec_prefix}/libexec' +datarootdir='${prefix}/share' +datadir='${datarootdir}' +sysconfdir='${prefix}/etc' +sharedstatedir='${prefix}/com' +localstatedir='${prefix}/var' +includedir='${prefix}/include' +oldincludedir='/usr/include' +docdir='${datarootdir}/doc/${PACKAGE_TARNAME}' +infodir='${datarootdir}/info' +htmldir='${docdir}' +dvidir='${docdir}' +pdfdir='${docdir}' +psdir='${docdir}' +libdir='${exec_prefix}/lib' +localedir='${datarootdir}/locale' +mandir='${datarootdir}/man' + +ac_prev= +ac_dashdash= +for ac_option +do + # If the previous option needs an argument, assign it. + if test -n "$ac_prev"; then + eval $ac_prev=\$ac_option + ac_prev= + continue + fi + + case $ac_option in + *=*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;; + *) ac_optarg=yes ;; + esac + + # Accept the important Cygnus configure options, so we can diagnose typos. + + case $ac_dashdash$ac_option in + --) + ac_dashdash=yes ;; + + -bindir | --bindir | --bindi | --bind | --bin | --bi) + ac_prev=bindir ;; + -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*) + bindir=$ac_optarg ;; + + -build | --build | --buil | --bui | --bu) + ac_prev=build_alias ;; + -build=* | --build=* | --buil=* | --bui=* | --bu=*) + build_alias=$ac_optarg ;; + + -cache-file | --cache-file | --cache-fil | --cache-fi \ + | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c) + ac_prev=cache_file ;; + -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \ + | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*) + cache_file=$ac_optarg ;; + + --config-cache | -C) + cache_file=config.cache ;; + + -datadir | --datadir | --datadi | --datad) + ac_prev=datadir ;; + -datadir=* | --datadir=* | --datadi=* | --datad=*) + datadir=$ac_optarg ;; + + -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \ + | --dataroo | --dataro | --datar) + ac_prev=datarootdir ;; + -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \ + | --dataroot=* | --dataroo=* | --dataro=* | --datar=*) + datarootdir=$ac_optarg ;; + + -disable-* | --disable-*) + ac_feature=`expr "x$ac_option" : 'x-*disable-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=no ;; + + -docdir | --docdir | --docdi | --doc | --do) + ac_prev=docdir ;; + -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*) + docdir=$ac_optarg ;; + + -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv) + ac_prev=dvidir ;; + -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*) + dvidir=$ac_optarg ;; + + -enable-* | --enable-*) + ac_feature=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_feature" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid feature name: $ac_feature" >&2 + { (exit 1); exit 1; }; } + ac_feature=`echo $ac_feature | sed 's/[-.]/_/g'` + eval enable_$ac_feature=\$ac_optarg ;; + + -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \ + | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \ + | --exec | --exe | --ex) + ac_prev=exec_prefix ;; + -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \ + | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \ + | --exec=* | --exe=* | --ex=*) + exec_prefix=$ac_optarg ;; + + -gas | --gas | --ga | --g) + # Obsolete; use --with-gas. + with_gas=yes ;; + + -help | --help | --hel | --he | -h) + ac_init_help=long ;; + -help=r* | --help=r* | --hel=r* | --he=r* | -hr*) + ac_init_help=recursive ;; + -help=s* | --help=s* | --hel=s* | --he=s* | -hs*) + ac_init_help=short ;; + + -host | --host | --hos | --ho) + ac_prev=host_alias ;; + -host=* | --host=* | --hos=* | --ho=*) + host_alias=$ac_optarg ;; + + -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht) + ac_prev=htmldir ;; + -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \ + | --ht=*) + htmldir=$ac_optarg ;; + + -includedir | --includedir | --includedi | --included | --include \ + | --includ | --inclu | --incl | --inc) + ac_prev=includedir ;; + -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \ + | --includ=* | --inclu=* | --incl=* | --inc=*) + includedir=$ac_optarg ;; + + -infodir | --infodir | --infodi | --infod | --info | --inf) + ac_prev=infodir ;; + -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*) + infodir=$ac_optarg ;; + + -libdir | --libdir | --libdi | --libd) + ac_prev=libdir ;; + -libdir=* | --libdir=* | --libdi=* | --libd=*) + libdir=$ac_optarg ;; + + -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \ + | --libexe | --libex | --libe) + ac_prev=libexecdir ;; + -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \ + | --libexe=* | --libex=* | --libe=*) + libexecdir=$ac_optarg ;; + + -localedir | --localedir | --localedi | --localed | --locale) + ac_prev=localedir ;; + -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*) + localedir=$ac_optarg ;; + + -localstatedir | --localstatedir | --localstatedi | --localstated \ + | --localstate | --localstat | --localsta | --localst | --locals) + ac_prev=localstatedir ;; + -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \ + | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*) + localstatedir=$ac_optarg ;; + + -mandir | --mandir | --mandi | --mand | --man | --ma | --m) + ac_prev=mandir ;; + -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*) + mandir=$ac_optarg ;; + + -nfp | --nfp | --nf) + # Obsolete; use --without-fp. + with_fp=no ;; + + -no-create | --no-create | --no-creat | --no-crea | --no-cre \ + | --no-cr | --no-c | -n) + no_create=yes ;; + + -no-recursion | --no-recursion | --no-recursio | --no-recursi \ + | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) + no_recursion=yes ;; + + -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \ + | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \ + | --oldin | --oldi | --old | --ol | --o) + ac_prev=oldincludedir ;; + -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \ + | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \ + | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*) + oldincludedir=$ac_optarg ;; + + -prefix | --prefix | --prefi | --pref | --pre | --pr | --p) + ac_prev=prefix ;; + -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*) + prefix=$ac_optarg ;; + + -program-prefix | --program-prefix | --program-prefi | --program-pref \ + | --program-pre | --program-pr | --program-p) + ac_prev=program_prefix ;; + -program-prefix=* | --program-prefix=* | --program-prefi=* \ + | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*) + program_prefix=$ac_optarg ;; + + -program-suffix | --program-suffix | --program-suffi | --program-suff \ + | --program-suf | --program-su | --program-s) + ac_prev=program_suffix ;; + -program-suffix=* | --program-suffix=* | --program-suffi=* \ + | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*) + program_suffix=$ac_optarg ;; + + -program-transform-name | --program-transform-name \ + | --program-transform-nam | --program-transform-na \ + | --program-transform-n | --program-transform- \ + | --program-transform | --program-transfor \ + | --program-transfo | --program-transf \ + | --program-trans | --program-tran \ + | --progr-tra | --program-tr | --program-t) + ac_prev=program_transform_name ;; + -program-transform-name=* | --program-transform-name=* \ + | --program-transform-nam=* | --program-transform-na=* \ + | --program-transform-n=* | --program-transform-=* \ + | --program-transform=* | --program-transfor=* \ + | --program-transfo=* | --program-transf=* \ + | --program-trans=* | --program-tran=* \ + | --progr-tra=* | --program-tr=* | --program-t=*) + program_transform_name=$ac_optarg ;; + + -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd) + ac_prev=pdfdir ;; + -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*) + pdfdir=$ac_optarg ;; + + -psdir | --psdir | --psdi | --psd | --ps) + ac_prev=psdir ;; + -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*) + psdir=$ac_optarg ;; + + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + silent=yes ;; + + -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb) + ac_prev=sbindir ;; + -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \ + | --sbi=* | --sb=*) + sbindir=$ac_optarg ;; + + -sharedstatedir | --sharedstatedir | --sharedstatedi \ + | --sharedstated | --sharedstate | --sharedstat | --sharedsta \ + | --sharedst | --shareds | --shared | --share | --shar \ + | --sha | --sh) + ac_prev=sharedstatedir ;; + -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \ + | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \ + | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \ + | --sha=* | --sh=*) + sharedstatedir=$ac_optarg ;; + + -site | --site | --sit) + ac_prev=site ;; + -site=* | --site=* | --sit=*) + site=$ac_optarg ;; + + -srcdir | --srcdir | --srcdi | --srcd | --src | --sr) + ac_prev=srcdir ;; + -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*) + srcdir=$ac_optarg ;; + + -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \ + | --syscon | --sysco | --sysc | --sys | --sy) + ac_prev=sysconfdir ;; + -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \ + | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*) + sysconfdir=$ac_optarg ;; + + -target | --target | --targe | --targ | --tar | --ta | --t) + ac_prev=target_alias ;; + -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*) + target_alias=$ac_optarg ;; + + -v | -verbose | --verbose | --verbos | --verbo | --verb) + verbose=yes ;; + + -version | --version | --versio | --versi | --vers | -V) + ac_init_version=: ;; + + -with-* | --with-*) + ac_package=`expr "x$ac_option" : 'x-*with-\([^=]*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=\$ac_optarg ;; + + -without-* | --without-*) + ac_package=`expr "x$ac_option" : 'x-*without-\(.*\)'` + # Reject names that are not valid shell variable names. + expr "x$ac_package" : ".*[^-._$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid package name: $ac_package" >&2 + { (exit 1); exit 1; }; } + ac_package=`echo $ac_package | sed 's/[-.]/_/g'` + eval with_$ac_package=no ;; + + --x) + # Obsolete; use --with-x. + with_x=yes ;; + + -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \ + | --x-incl | --x-inc | --x-in | --x-i) + ac_prev=x_includes ;; + -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \ + | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*) + x_includes=$ac_optarg ;; + + -x-libraries | --x-libraries | --x-librarie | --x-librari \ + | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l) + ac_prev=x_libraries ;; + -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \ + | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*) + x_libraries=$ac_optarg ;; + + -*) { echo "$as_me: error: unrecognized option: $ac_option +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } + ;; + + *=*) + ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='` + # Reject names that are not valid shell variable names. + expr "x$ac_envvar" : ".*[^_$as_cr_alnum]" >/dev/null && + { echo "$as_me: error: invalid variable name: $ac_envvar" >&2 + { (exit 1); exit 1; }; } + eval $ac_envvar=\$ac_optarg + export $ac_envvar ;; + + *) + # FIXME: should be removed in autoconf 3.0. + echo "$as_me: WARNING: you should use --build, --host, --target" >&2 + expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null && + echo "$as_me: WARNING: invalid host type: $ac_option" >&2 + : ${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option} + ;; + + esac +done + +if test -n "$ac_prev"; then + ac_option=--`echo $ac_prev | sed 's/_/-/g'` + { echo "$as_me: error: missing argument to $ac_option" >&2 + { (exit 1); exit 1; }; } +fi + +# Be sure to have absolute directory names. +for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \ + datadir sysconfdir sharedstatedir localstatedir includedir \ + oldincludedir docdir infodir htmldir dvidir pdfdir psdir \ + libdir localedir mandir +do + eval ac_val=\$$ac_var + case $ac_val in + [\\/$]* | ?:[\\/]* ) continue;; + NONE | '' ) case $ac_var in *prefix ) continue;; esac;; + esac + { echo "$as_me: error: expected an absolute directory name for --$ac_var: $ac_val" >&2 + { (exit 1); exit 1; }; } +done + +# There might be people who depend on the old broken behavior: `$host' +# used to hold the argument of --host etc. +# FIXME: To remove some day. +build=$build_alias +host=$host_alias +target=$target_alias + +# FIXME: To remove some day. +if test "x$host_alias" != x; then + if test "x$build_alias" = x; then + cross_compiling=maybe + echo "$as_me: WARNING: If you wanted to set the --build type, don't use --host. + If a cross compiler is detected then cross compile mode will be used." >&2 + elif test "x$build_alias" != "x$host_alias"; then + cross_compiling=yes + fi +fi + +ac_tool_prefix= +test -n "$host_alias" && ac_tool_prefix=$host_alias- + +test "$silent" = yes && exec 6>/dev/null + + +ac_pwd=`pwd` && test -n "$ac_pwd" && +ac_ls_di=`ls -di .` && +ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` || + { echo "$as_me: error: Working directory cannot be determined" >&2 + { (exit 1); exit 1; }; } +test "X$ac_ls_di" = "X$ac_pwd_ls_di" || + { echo "$as_me: error: pwd does not report name of working directory" >&2 + { (exit 1); exit 1; }; } + + +# Find the source files, if location was not specified. +if test -z "$srcdir"; then + ac_srcdir_defaulted=yes + # Try the directory containing this script, then the parent directory. + ac_confdir=`$as_dirname -- "$0" || +$as_expr X"$0" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$0" : 'X\(//\)[^/]' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X"$0" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + srcdir=$ac_confdir + if test ! -r "$srcdir/$ac_unique_file"; then + srcdir=.. + fi +else + ac_srcdir_defaulted=no +fi +if test ! -r "$srcdir/$ac_unique_file"; then + test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .." + { echo "$as_me: error: cannot find sources ($ac_unique_file) in $srcdir" >&2 + { (exit 1); exit 1; }; } +fi +ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work" +ac_abs_confdir=`( + cd "$srcdir" && test -r "./$ac_unique_file" || { echo "$as_me: error: $ac_msg" >&2 + { (exit 1); exit 1; }; } + pwd)` +# When building in place, set srcdir=. +if test "$ac_abs_confdir" = "$ac_pwd"; then + srcdir=. +fi +# Remove unnecessary trailing slashes from srcdir. +# Double slashes in file names in object file debugging info +# mess up M-x gdb in Emacs. +case $srcdir in +*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;; +esac +for ac_var in $ac_precious_vars; do + eval ac_env_${ac_var}_set=\${${ac_var}+set} + eval ac_env_${ac_var}_value=\$${ac_var} + eval ac_cv_env_${ac_var}_set=\${${ac_var}+set} + eval ac_cv_env_${ac_var}_value=\$${ac_var} +done + +# +# Report the --help message. +# +if test "$ac_init_help" = "long"; then + # Omit some internal or obsolete options to make the list less imposing. + # This message is too long to be a string in the A/UX 3.1 sh. + cat <<_ACEOF +\`configure' configures netbsd-iscsi 20080207 to adapt to many kinds of systems. + +Usage: $0 [OPTION]... [VAR=VALUE]... + +To assign environment variables (e.g., CC, CFLAGS...), specify them as +VAR=VALUE. See below for descriptions of some of the useful variables. + +Defaults for the options are specified in brackets. + +Configuration: + -h, --help display this help and exit + --help=short display options specific to this package + --help=recursive display the short help of all the included packages + -V, --version display version information and exit + -q, --quiet, --silent do not print \`checking...' messages + --cache-file=FILE cache test results in FILE [disabled] + -C, --config-cache alias for \`--cache-file=config.cache' + -n, --no-create do not create output files + --srcdir=DIR find the sources in DIR [configure dir or \`..'] + +Installation directories: + --prefix=PREFIX install architecture-independent files in PREFIX + [$ac_default_prefix] + --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX + [PREFIX] + +By default, \`make install' will install all the files in +\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify +an installation prefix other than \`$ac_default_prefix' using \`--prefix', +for instance \`--prefix=\$HOME'. + +For better control, use the options below. + +Fine tuning of the installation directories: + --bindir=DIR user executables [EPREFIX/bin] + --sbindir=DIR system admin executables [EPREFIX/sbin] + --libexecdir=DIR program executables [EPREFIX/libexec] + --sysconfdir=DIR read-only single-machine data [PREFIX/etc] + --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com] + --localstatedir=DIR modifiable single-machine data [PREFIX/var] + --libdir=DIR object code libraries [EPREFIX/lib] + --includedir=DIR C header files [PREFIX/include] + --oldincludedir=DIR C header files for non-gcc [/usr/include] + --datarootdir=DIR read-only arch.-independent data root [PREFIX/share] + --datadir=DIR read-only architecture-independent data [DATAROOTDIR] + --infodir=DIR info documentation [DATAROOTDIR/info] + --localedir=DIR locale-dependent data [DATAROOTDIR/locale] + --mandir=DIR man documentation [DATAROOTDIR/man] + --docdir=DIR documentation root [DATAROOTDIR/doc/netbsd-iscsi] + --htmldir=DIR html documentation [DOCDIR] + --dvidir=DIR dvi documentation [DOCDIR] + --pdfdir=DIR pdf documentation [DOCDIR] + --psdir=DIR ps documentation [DOCDIR] +_ACEOF + + cat <<\_ACEOF +_ACEOF +fi + +if test -n "$ac_init_help"; then + case $ac_init_help in + short | recursive ) echo "Configuration of netbsd-iscsi 20080207:";; + esac + cat <<\_ACEOF + +Some influential environment variables: + CC C compiler command + CFLAGS C compiler flags + LDFLAGS linker flags, e.g. -L if you have libraries in a + nonstandard directory + LIBS libraries to pass to the linker, e.g. -l + CPPFLAGS C/C++/Objective C preprocessor flags, e.g. -I if + you have headers in a nonstandard directory + CPP C preprocessor + +Use these variables to override the choices made by `configure' or to help +it to find libraries and programs with nonstandard names/locations. + +Report bugs to >. +_ACEOF +ac_status=$? +fi + +if test "$ac_init_help" = "recursive"; then + # If there are subdirs, report their specific --help. + for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue + test -d "$ac_dir" || continue + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + cd "$ac_dir" || { ac_status=$?; continue; } + # Check for guested configure. + if test -f "$ac_srcdir/configure.gnu"; then + echo && + $SHELL "$ac_srcdir/configure.gnu" --help=recursive + elif test -f "$ac_srcdir/configure"; then + echo && + $SHELL "$ac_srcdir/configure" --help=recursive + else + echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2 + fi || ac_status=$? + cd "$ac_pwd" || { ac_status=$?; break; } + done +fi + +test -n "$ac_init_help" && exit $ac_status +if $ac_init_version; then + cat <<\_ACEOF +netbsd-iscsi configure 20080207 +generated by GNU Autoconf 2.61 + +Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001, +2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc. +This configure script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it. +_ACEOF + exit +fi +cat >config.log <<_ACEOF +This file contains any messages produced by compilers while +running configure, to aid debugging if configure makes a mistake. + +It was created by netbsd-iscsi $as_me 20080207, which was +generated by GNU Autoconf 2.61. Invocation command line was + + $ $0 $@ + +_ACEOF +exec 5>>config.log +{ +cat <<_ASUNAME +## --------- ## +## Platform. ## +## --------- ## + +hostname = `(hostname || uname -n) 2>/dev/null | sed 1q` +uname -m = `(uname -m) 2>/dev/null || echo unknown` +uname -r = `(uname -r) 2>/dev/null || echo unknown` +uname -s = `(uname -s) 2>/dev/null || echo unknown` +uname -v = `(uname -v) 2>/dev/null || echo unknown` + +/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown` +/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown` + +/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown` +/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown` +/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown` +/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown` +/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown` +/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown` +/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown` + +_ASUNAME + +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + echo "PATH: $as_dir" +done +IFS=$as_save_IFS + +} >&5 + +cat >&5 <<_ACEOF + + +## ----------- ## +## Core tests. ## +## ----------- ## + +_ACEOF + + +# Keep a trace of the command line. +# Strip out --no-create and --no-recursion so they do not pile up. +# Strip out --silent because we don't want to record it for future runs. +# Also quote any args containing shell meta-characters. +# Make two passes to allow for proper duplicate-argument suppression. +ac_configure_args= +ac_configure_args0= +ac_configure_args1= +ac_must_keep_next=false +for ac_pass in 1 2 +do + for ac_arg + do + case $ac_arg in + -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil) + continue ;; + *\'*) + ac_arg=`echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;; + esac + case $ac_pass in + 1) ac_configure_args0="$ac_configure_args0 '$ac_arg'" ;; + 2) + ac_configure_args1="$ac_configure_args1 '$ac_arg'" + if test $ac_must_keep_next = true; then + ac_must_keep_next=false # Got value, back to normal. + else + case $ac_arg in + *=* | --config-cache | -C | -disable-* | --disable-* \ + | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \ + | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \ + | -with-* | --with-* | -without-* | --without-* | --x) + case "$ac_configure_args0 " in + "$ac_configure_args1"*" '$ac_arg' "* ) continue ;; + esac + ;; + -* ) ac_must_keep_next=true ;; + esac + fi + ac_configure_args="$ac_configure_args '$ac_arg'" + ;; + esac + done +done +$as_unset ac_configure_args0 || test "${ac_configure_args0+set}" != set || { ac_configure_args0=; export ac_configure_args0; } +$as_unset ac_configure_args1 || test "${ac_configure_args1+set}" != set || { ac_configure_args1=; export ac_configure_args1; } + +# When interrupted or exit'd, cleanup temporary files, and complete +# config.log. We remove comments because anyway the quotes in there +# would cause problems or look ugly. +# WARNING: Use '\'' to represent an apostrophe within the trap. +# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug. +trap 'exit_status=$? + # Save into config.log some information that might help in debugging. + { + echo + + cat <<\_ASBOX +## ---------------- ## +## Cache variables. ## +## ---------------- ## +_ASBOX + echo + # The following way of writing the cache mishandles newlines in values, +( + for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + (set) 2>&1 | + case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + sed -n \ + "s/'\''/'\''\\\\'\'''\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p" + ;; #( + *) + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) + echo + + cat <<\_ASBOX +## ----------------- ## +## Output variables. ## +## ----------------- ## +_ASBOX + echo + for ac_var in $ac_subst_vars + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + + if test -n "$ac_subst_files"; then + cat <<\_ASBOX +## ------------------- ## +## File substitutions. ## +## ------------------- ## +_ASBOX + echo + for ac_var in $ac_subst_files + do + eval ac_val=\$$ac_var + case $ac_val in + *\'\''*) ac_val=`echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;; + esac + echo "$ac_var='\''$ac_val'\''" + done | sort + echo + fi + + if test -s confdefs.h; then + cat <<\_ASBOX +## ----------- ## +## confdefs.h. ## +## ----------- ## +_ASBOX + echo + cat confdefs.h + echo + fi + test "$ac_signal" != 0 && + echo "$as_me: caught signal $ac_signal" + echo "$as_me: exit $exit_status" + } >&5 + rm -f core *.core core.conftest.* && + rm -f -r conftest* confdefs* conf$$* $ac_clean_files && + exit $exit_status +' 0 +for ac_signal in 1 2 13 15; do + trap 'ac_signal='$ac_signal'; { (exit 1); exit 1; }' $ac_signal +done +ac_signal=0 + +# confdefs.h avoids OS command line length limits that DEFS can exceed. +rm -f -r conftest* confdefs.h + +# Predefined preprocessor variables. + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_NAME "$PACKAGE_NAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_TARNAME "$PACKAGE_TARNAME" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_VERSION "$PACKAGE_VERSION" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_STRING "$PACKAGE_STRING" +_ACEOF + + +cat >>confdefs.h <<_ACEOF +#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT" +_ACEOF + + +# Let the site file select an alternate cache file if it wants to. +# Prefer explicitly selected file to automatically selected ones. +if test -n "$CONFIG_SITE"; then + set x "$CONFIG_SITE" +elif test "x$prefix" != xNONE; then + set x "$prefix/share/config.site" "$prefix/etc/config.site" +else + set x "$ac_default_prefix/share/config.site" \ + "$ac_default_prefix/etc/config.site" +fi +shift +for ac_site_file +do + if test -r "$ac_site_file"; then + { echo "$as_me:$LINENO: loading site script $ac_site_file" >&5 +echo "$as_me: loading site script $ac_site_file" >&6;} + sed 's/^/| /' "$ac_site_file" >&5 + . "$ac_site_file" + fi +done + +if test -r "$cache_file"; then + # Some versions of bash will fail to source /dev/null (special + # files actually), so we avoid doing that. + if test -f "$cache_file"; then + { echo "$as_me:$LINENO: loading cache $cache_file" >&5 +echo "$as_me: loading cache $cache_file" >&6;} + case $cache_file in + [\\/]* | ?:[\\/]* ) . "$cache_file";; + *) . "./$cache_file";; + esac + fi +else + { echo "$as_me:$LINENO: creating cache $cache_file" >&5 +echo "$as_me: creating cache $cache_file" >&6;} + >$cache_file +fi + +# Check that the precious variables saved in the cache have kept the same +# value. +ac_cache_corrupted=false +for ac_var in $ac_precious_vars; do + eval ac_old_set=\$ac_cv_env_${ac_var}_set + eval ac_new_set=\$ac_env_${ac_var}_set + eval ac_old_val=\$ac_cv_env_${ac_var}_value + eval ac_new_val=\$ac_env_${ac_var}_value + case $ac_old_set,$ac_new_set in + set,) + { echo "$as_me:$LINENO: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,set) + { echo "$as_me:$LINENO: error: \`$ac_var' was not set in the previous run" >&5 +echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;} + ac_cache_corrupted=: ;; + ,);; + *) + if test "x$ac_old_val" != "x$ac_new_val"; then + { echo "$as_me:$LINENO: error: \`$ac_var' has changed since the previous run:" >&5 +echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;} + { echo "$as_me:$LINENO: former value: $ac_old_val" >&5 +echo "$as_me: former value: $ac_old_val" >&2;} + { echo "$as_me:$LINENO: current value: $ac_new_val" >&5 +echo "$as_me: current value: $ac_new_val" >&2;} + ac_cache_corrupted=: + fi;; + esac + # Pass precious variables to config.status. + if test "$ac_new_set" = set; then + case $ac_new_val in + *\'*) ac_arg=$ac_var=`echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;; + *) ac_arg=$ac_var=$ac_new_val ;; + esac + case " $ac_configure_args " in + *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy. + *) ac_configure_args="$ac_configure_args '$ac_arg'" ;; + esac + fi +done +if $ac_cache_corrupted; then + { echo "$as_me:$LINENO: error: changes in the environment can compromise the build" >&5 +echo "$as_me: error: changes in the environment can compromise the build" >&2;} + { { echo "$as_me:$LINENO: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&5 +echo "$as_me: error: run \`make distclean' and/or \`rm $cache_file' and start over" >&2;} + { (exit 1); exit 1; }; } +fi + + + + + + + + + + + + + + + + + + + + + + + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + + +ac_config_headers="$ac_config_headers ../include/config.h" + + +ac_aux_dir= +for ac_dir in "$srcdir" "$srcdir/.." "$srcdir/../.."; do + if test -f "$ac_dir/install-sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install-sh -c" + break + elif test -f "$ac_dir/install.sh"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/install.sh -c" + break + elif test -f "$ac_dir/shtool"; then + ac_aux_dir=$ac_dir + ac_install_sh="$ac_aux_dir/shtool install -c" + break + fi +done +if test -z "$ac_aux_dir"; then + { { echo "$as_me:$LINENO: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&5 +echo "$as_me: error: cannot find install-sh or install.sh in \"$srcdir\" \"$srcdir/..\" \"$srcdir/../..\"" >&2;} + { (exit 1); exit 1; }; } +fi + +# These three variables are undocumented and unsupported, +# and are intended to be withdrawn in a future Autoconf release. +# They can cause serious problems if a builder's source tree is in a directory +# whose full name contains unusual characters. +ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var. +ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var. +ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var. + + +# Find a good install program. We prefer a C program (faster), +# so one script is as good as another. But avoid the broken or +# incompatible versions: +# SysV /etc/install, /usr/sbin/install +# SunOS /usr/etc/install +# IRIX /sbin/install +# AIX /bin/install +# AmigaOS /C/install, which installs bootblocks on floppy discs +# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag +# AFS /usr/afsws/bin/install, which mishandles nonexistent args +# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff" +# OS/2's system install, which has a completely different semantic +# ./install, which can be erroneously created by make from ./install.sh. +{ echo "$as_me:$LINENO: checking for a BSD-compatible install" >&5 +echo $ECHO_N "checking for a BSD-compatible install... $ECHO_C" >&6; } +if test -z "$INSTALL"; then +if test "${ac_cv_path_install+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + # Account for people who put trailing slashes in PATH elements. +case $as_dir/ in + ./ | .// | /cC/* | \ + /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \ + ?:\\/os2\\/install\\/* | ?:\\/OS2\\/INSTALL\\/* | \ + /usr/ucb/* ) ;; + *) + # OSF1 and SCO ODT 3.0 have their own names for install. + # Don't use installbsd from OSF since it installs stuff as root + # by default. + for ac_prog in ginstall scoinst install; do + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_prog$ac_exec_ext" && $as_test_x "$as_dir/$ac_prog$ac_exec_ext"; }; then + if test $ac_prog = install && + grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # AIX install. It has an incompatible calling convention. + : + elif test $ac_prog = install && + grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then + # program-specific install script used by HP pwplus--don't use. + : + else + ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c" + break 3 + fi + fi + done + done + ;; +esac +done +IFS=$as_save_IFS + + +fi + if test "${ac_cv_path_install+set}" = set; then + INSTALL=$ac_cv_path_install + else + # As a last resort, use the slow shell script. Don't cache a + # value for INSTALL within a source directory, because that will + # break other packages using the cache if that directory is + # removed, or if the value is a relative name. + INSTALL=$ac_install_sh + fi +fi +{ echo "$as_me:$LINENO: result: $INSTALL" >&5 +echo "${ECHO_T}$INSTALL" >&6; } + +# Use test -z because SunOS4 sh mishandles braces in ${var-val}. +# It thinks the first close brace ends the variable substitution. +test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}' + +test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}' + +test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644' + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args. +set dummy ${ac_tool_prefix}gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_CC"; then + ac_ct_CC=$CC + # Extract the first word of "gcc", so it can be a program name with args. +set dummy gcc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="gcc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +else + CC="$ac_cv_prog_CC" +fi + +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args. +set dummy ${ac_tool_prefix}cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="${ac_tool_prefix}cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + fi +fi +if test -z "$CC"; then + # Extract the first word of "cc", so it can be a program name with args. +set dummy cc; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else + ac_prog_rejected=no +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then + ac_prog_rejected=yes + continue + fi + ac_cv_prog_CC="cc" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +if test $ac_prog_rejected = yes; then + # We found a bogon in the path, so make sure we never use it. + set dummy $ac_cv_prog_CC + shift + if test $# != 0; then + # We chose a different compiler from the bogus one. + # However, it has the same basename, so the bogon will be chosen + # first if we set CC to just the basename; use the full file name. + shift + ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@" + fi +fi +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$CC"; then + if test -n "$ac_tool_prefix"; then + for ac_prog in cl.exe + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CC"; then + ac_cv_prog_CC="$CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_CC="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +CC=$ac_cv_prog_CC +if test -n "$CC"; then + { echo "$as_me:$LINENO: result: $CC" >&5 +echo "${ECHO_T}$CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$CC" && break + done +fi +if test -z "$CC"; then + ac_ct_CC=$CC + for ac_prog in cl.exe +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_CC+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CC"; then + ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_CC="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_CC=$ac_cv_prog_ac_ct_CC +if test -n "$ac_ct_CC"; then + { echo "$as_me:$LINENO: result: $ac_ct_CC" >&5 +echo "${ECHO_T}$ac_ct_CC" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + + test -n "$ac_ct_CC" && break +done + + if test "x$ac_ct_CC" = x; then + CC="" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + CC=$ac_ct_CC + fi +fi + +fi + + +test -z "$CC" && { { echo "$as_me:$LINENO: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&5 +echo "$as_me: error: no acceptable C compiler found in \$PATH +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + +# Provide some information about the compiler. +echo "$as_me:$LINENO: checking for C compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (ac_try="$ac_compiler --version >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler --version >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -v >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -v >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (ac_try="$ac_compiler -V >&5" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compiler -V >&5") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files a.out a.exe b.out" +# Try to create an executable without -o first, disregard a.out. +# It will help us diagnose broken compilers, and finding out an intuition +# of exeext. +{ echo "$as_me:$LINENO: checking for C compiler default output file name" >&5 +echo $ECHO_N "checking for C compiler default output file name... $ECHO_C" >&6; } +ac_link_default=`echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'` +# +# List of possible output files, starting from the most likely. +# The algorithm is not robust to junk in `.', hence go to wildcards (a.*) +# only as a last resort. b.out is created by i960 compilers. +ac_files='a_out.exe a.exe conftest.exe a.out conftest a.* conftest.* b.out' +# +# The IRIX 6 linker writes into existing files which may not be +# executable, retaining their permissions. Remove them first so a +# subsequent execution test works. +ac_rmfiles= +for ac_file in $ac_files +do + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + * ) ac_rmfiles="$ac_rmfiles $ac_file";; + esac +done +rm -f $ac_rmfiles + +if { (ac_try="$ac_link_default" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link_default") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # Autoconf-2.13 could set the ac_cv_exeext variable to `no'. +# So ignore a value of `no', otherwise this would lead to `EXEEXT = no' +# in a Makefile. We should not override ac_cv_exeext if it was cached, +# so that the user can short-circuit this test for compilers unknown to +# Autoconf. +for ac_file in $ac_files '' +do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) + ;; + [ab].out ) + # We found the default executable, but exeext='' is most + # certainly right. + break;; + *.* ) + if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no; + then :; else + ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + fi + # We set ac_cv_exeext here because the later test for it is not + # safe: cross compilers may not add the suffix if given an `-o' + # argument, so we may need to know it at that point already. + # Even if this section looks crufty: it has the advantage of + # actually working. + break;; + * ) + break;; + esac +done +test "$ac_cv_exeext" = no && ac_cv_exeext= + +else + ac_file='' +fi + +{ echo "$as_me:$LINENO: result: $ac_file" >&5 +echo "${ECHO_T}$ac_file" >&6; } +if test -z "$ac_file"; then + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: C compiler cannot create executables +See \`config.log' for more details." >&5 +echo "$as_me: error: C compiler cannot create executables +See \`config.log' for more details." >&2;} + { (exit 77); exit 77; }; } +fi + +ac_exeext=$ac_cv_exeext + +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether the C compiler works" >&5 +echo $ECHO_N "checking whether the C compiler works... $ECHO_C" >&6; } +# FIXME: These cross compiler hacks should be removed for Autoconf 3.0 +# If not cross compiling, check that we can run a simple program. +if test "$cross_compiling" != yes; then + if { ac_try='./$ac_file' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + cross_compiling=no + else + if test "$cross_compiling" = maybe; then + cross_compiling=yes + else + { { echo "$as_me:$LINENO: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot run C compiled programs. +If you meant to cross compile, use \`--host'. +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } + fi + fi +fi +{ echo "$as_me:$LINENO: result: yes" >&5 +echo "${ECHO_T}yes" >&6; } + +rm -f a.out a.exe conftest$ac_cv_exeext b.out +ac_clean_files=$ac_clean_files_save +# Check that the compiler produces executables we can run. If not, either +# the compiler is broken, or we cross compile. +{ echo "$as_me:$LINENO: checking whether we are cross compiling" >&5 +echo $ECHO_N "checking whether we are cross compiling... $ECHO_C" >&6; } +{ echo "$as_me:$LINENO: result: $cross_compiling" >&5 +echo "${ECHO_T}$cross_compiling" >&6; } + +{ echo "$as_me:$LINENO: checking for suffix of executables" >&5 +echo $ECHO_N "checking for suffix of executables... $ECHO_C" >&6; } +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + # If both `conftest.exe' and `conftest' are `present' (well, observable) +# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will +# work properly (i.e., refer to `conftest.exe'), while it won't with +# `rm'. +for ac_file in conftest.exe conftest conftest.*; do + test -f "$ac_file" || continue + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.o | *.obj ) ;; + *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'` + break;; + * ) break;; + esac +done +else + { { echo "$as_me:$LINENO: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of executables: cannot compile and link +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest$ac_cv_exeext +{ echo "$as_me:$LINENO: result: $ac_cv_exeext" >&5 +echo "${ECHO_T}$ac_cv_exeext" >&6; } + +rm -f conftest.$ac_ext +EXEEXT=$ac_cv_exeext +ac_exeext=$EXEEXT +{ echo "$as_me:$LINENO: checking for suffix of object files" >&5 +echo $ECHO_N "checking for suffix of object files... $ECHO_C" >&6; } +if test "${ac_cv_objext+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.o conftest.obj +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; then + for ac_file in conftest.o conftest.obj conftest.*; do + test -f "$ac_file" || continue; + case $ac_file in + *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf ) ;; + *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'` + break;; + esac +done +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +{ { echo "$as_me:$LINENO: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&5 +echo "$as_me: error: cannot compute suffix of object files: cannot compile +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +rm -f conftest.$ac_cv_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_objext" >&5 +echo "${ECHO_T}$ac_cv_objext" >&6; } +OBJEXT=$ac_cv_objext +ac_objext=$OBJEXT +{ echo "$as_me:$LINENO: checking whether we are using the GNU C compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C compiler... $ECHO_C" >&6; } +if test "${ac_cv_c_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_compiler_gnu=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +ac_cv_c_compiler_gnu=$ac_compiler_gnu + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_c_compiler_gnu" >&6; } +GCC=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CFLAGS=${CFLAGS+set} +ac_save_CFLAGS=$CFLAGS +{ echo "$as_me:$LINENO: checking whether $CC accepts -g" >&5 +echo $ECHO_N "checking whether $CC accepts -g... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_save_c_werror_flag=$ac_c_werror_flag + ac_c_werror_flag=yes + ac_cv_prog_cc_g=no + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + CFLAGS="" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_c_werror_flag=$ac_save_c_werror_flag + CFLAGS="-g" + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + ac_c_werror_flag=$ac_save_c_werror_flag +fi +{ echo "$as_me:$LINENO: result: $ac_cv_prog_cc_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_g" >&6; } +if test "$ac_test_CFLAGS" = set; then + CFLAGS=$ac_save_CFLAGS +elif test $ac_cv_prog_cc_g = yes; then + if test "$GCC" = yes; then + CFLAGS="-g -O2" + else + CFLAGS="-g" + fi +else + if test "$GCC" = yes; then + CFLAGS="-O2" + else + CFLAGS= + fi +fi +{ echo "$as_me:$LINENO: checking for $CC option to accept ISO C89" >&5 +echo $ECHO_N "checking for $CC option to accept ISO C89... $ECHO_C" >&6; } +if test "${ac_cv_prog_cc_c89+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_cv_prog_cc_c89=no +ac_save_CC=$CC +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include +/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */ +struct buf { int x; }; +FILE * (*rcsopen) (struct buf *, struct stat *, int); +static char *e (p, i) + char **p; + int i; +{ + return p[i]; +} +static char *f (char * (*g) (char **, int), char **p, ...) +{ + char *s; + va_list v; + va_start (v,p); + s = g (p, va_arg (v,int)); + va_end (v); + return s; +} + +/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has + function prototypes and stuff, but not '\xHH' hex character constants. + These don't provoke an error unfortunately, instead are silently treated + as 'x'. The following induces an error, until -std is added to get + proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an + array size at least. It's necessary to write '\x00'==0 to get something + that's true only with -std. */ +int osf4_cc_array ['\x00' == 0 ? 1 : -1]; + +/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters + inside strings and character constants. */ +#define FOO(x) 'x' +int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1]; + +int test (int i, double x); +struct s1 {int (*f) (int a);}; +struct s2 {int (*f) (double a);}; +int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int); +int argc; +char **argv; +int +main () +{ +return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1]; + ; + return 0; +} +_ACEOF +for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \ + -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__" +do + CC="$ac_save_CC $ac_arg" + rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_prog_cc_c89=$ac_arg +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + +fi + +rm -f core conftest.err conftest.$ac_objext + test "x$ac_cv_prog_cc_c89" != "xno" && break +done +rm -f conftest.$ac_ext +CC=$ac_save_CC + +fi +# AC_CACHE_VAL +case "x$ac_cv_prog_cc_c89" in + x) + { echo "$as_me:$LINENO: result: none needed" >&5 +echo "${ECHO_T}none needed" >&6; } ;; + xno) + { echo "$as_me:$LINENO: result: unsupported" >&5 +echo "${ECHO_T}unsupported" >&6; } ;; + *) + CC="$CC $ac_cv_prog_cc_c89" + { echo "$as_me:$LINENO: result: $ac_cv_prog_cc_c89" >&5 +echo "${ECHO_T}$ac_cv_prog_cc_c89" >&6; } ;; +esac + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + +if test -n "$ac_tool_prefix"; then + # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args. +set dummy ${ac_tool_prefix}ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$RANLIB"; then + ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +RANLIB=$ac_cv_prog_RANLIB +if test -n "$RANLIB"; then + { echo "$as_me:$LINENO: result: $RANLIB" >&5 +echo "${ECHO_T}$RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + +fi +if test -z "$ac_cv_prog_RANLIB"; then + ac_ct_RANLIB=$RANLIB + # Extract the first word of "ranlib", so it can be a program name with args. +set dummy ranlib; ac_word=$2 +{ echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6; } +if test "${ac_cv_prog_ac_ct_RANLIB+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_RANLIB"; then + ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then + ac_cv_prog_ac_ct_RANLIB="ranlib" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done +IFS=$as_save_IFS + +fi +fi +ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB +if test -n "$ac_ct_RANLIB"; then + { echo "$as_me:$LINENO: result: $ac_ct_RANLIB" >&5 +echo "${ECHO_T}$ac_ct_RANLIB" >&6; } +else + { echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6; } +fi + + if test "x$ac_ct_RANLIB" = x; then + RANLIB=":" + else + case $cross_compiling:$ac_tool_warned in +yes:) +{ echo "$as_me:$LINENO: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&5 +echo "$as_me: WARNING: In the future, Autoconf will not detect cross-tools +whose name does not start with the host triplet. If you think this +configuration is useful to you, please write to autoconf@gnu.org." >&2;} +ac_tool_warned=yes ;; +esac + RANLIB=$ac_ct_RANLIB + fi +else + RANLIB="$ac_cv_prog_RANLIB" +fi + + + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu +{ echo "$as_me:$LINENO: checking how to run the C preprocessor" >&5 +echo $ECHO_N "checking how to run the C preprocessor... $ECHO_C" >&6; } +# On Suns, sometimes $CPP names a directory. +if test -n "$CPP" && test -d "$CPP"; then + CPP= +fi +if test -z "$CPP"; then + if test "${ac_cv_prog_CPP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Double quotes because CPP needs to be expanded + for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp" + do + ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + break +fi + + done + ac_cv_prog_CPP=$CPP + +fi + CPP=$ac_cv_prog_CPP +else + ac_cv_prog_CPP=$CPP +fi +{ echo "$as_me:$LINENO: result: $CPP" >&5 +echo "${ECHO_T}$CPP" >&6; } +ac_preproc_ok=false +for ac_c_preproc_warn_flag in '' yes +do + # Use a header file that comes with gcc, so configuring glibc + # with a fresh cross-compiler works. + # Prefer to if __STDC__ is defined, since + # exists even on freestanding compilers. + # On the NeXT, cc -E runs the code through the compiler's parser, + # not just through cpp. "Syntax error" is here to catch this case. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#ifdef __STDC__ +# include +#else +# include +#endif + Syntax error +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Broken: fails on valid input. +continue +fi + +rm -f conftest.err conftest.$ac_ext + + # OK, works on sane cases. Now check whether nonexistent headers + # can be detected and how. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + # Broken: success on invalid input. +continue +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + # Passes both tests. +ac_preproc_ok=: +break +fi + +rm -f conftest.err conftest.$ac_ext + +done +# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped. +rm -f conftest.err conftest.$ac_ext +if $ac_preproc_ok; then + : +else + { { echo "$as_me:$LINENO: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&5 +echo "$as_me: error: C preprocessor \"$CPP\" fails sanity check +See \`config.log' for more details." >&2;} + { (exit 1); exit 1; }; } +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + + +{ echo "$as_me:$LINENO: checking for grep that handles long lines and -e" >&5 +echo $ECHO_N "checking for grep that handles long lines and -e... $ECHO_C" >&6; } +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + # Extract the first word of "grep ggrep" to use in msg output +if test -z "$GREP"; then +set dummy grep ggrep; ac_prog_name=$2 +if test "${ac_cv_path_GREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_GREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in grep ggrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_GREP" && $as_test_x "$ac_path_GREP"; } || continue + # Check for GNU ac_path_GREP and select it if it is found. + # Check for GNU $ac_path_GREP +case `"$ac_path_GREP" --version 2>&1` in +*GNU*) + ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'GREP' >> "conftest.nl" + "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_GREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_GREP="$ac_path_GREP" + ac_path_GREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_GREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +GREP="$ac_cv_path_GREP" +if test -z "$GREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_GREP=$GREP +fi + + +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_GREP" >&5 +echo "${ECHO_T}$ac_cv_path_GREP" >&6; } + GREP="$ac_cv_path_GREP" + + +{ echo "$as_me:$LINENO: checking for egrep" >&5 +echo $ECHO_N "checking for egrep... $ECHO_C" >&6; } +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if echo a | $GREP -E '(a|b)' >/dev/null 2>&1 + then ac_cv_path_EGREP="$GREP -E" + else + # Extract the first word of "egrep" to use in msg output +if test -z "$EGREP"; then +set dummy egrep; ac_prog_name=$2 +if test "${ac_cv_path_EGREP+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_path_EGREP_found=false +# Loop through the user's path and test for each of PROGNAME-LIST +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_prog in egrep; do + for ac_exec_ext in '' $ac_executable_extensions; do + ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext" + { test -f "$ac_path_EGREP" && $as_test_x "$ac_path_EGREP"; } || continue + # Check for GNU ac_path_EGREP and select it if it is found. + # Check for GNU $ac_path_EGREP +case `"$ac_path_EGREP" --version 2>&1` in +*GNU*) + ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;; +*) + ac_count=0 + echo $ECHO_N "0123456789$ECHO_C" >"conftest.in" + while : + do + cat "conftest.in" "conftest.in" >"conftest.tmp" + mv "conftest.tmp" "conftest.in" + cp "conftest.in" "conftest.nl" + echo 'EGREP' >> "conftest.nl" + "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break + diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break + ac_count=`expr $ac_count + 1` + if test $ac_count -gt ${ac_path_EGREP_max-0}; then + # Best one so far, save it but keep looking for a better one + ac_cv_path_EGREP="$ac_path_EGREP" + ac_path_EGREP_max=$ac_count + fi + # 10*(2^10) chars as input seems more than enough + test $ac_count -gt 10 && break + done + rm -f conftest.in conftest.tmp conftest.nl conftest.out;; +esac + + + $ac_path_EGREP_found && break 3 + done +done + +done +IFS=$as_save_IFS + + +fi + +EGREP="$ac_cv_path_EGREP" +if test -z "$EGREP"; then + { { echo "$as_me:$LINENO: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&5 +echo "$as_me: error: no acceptable $ac_prog_name could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" >&2;} + { (exit 1); exit 1; }; } +fi + +else + ac_cv_path_EGREP=$EGREP +fi + + + fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_path_EGREP" >&5 +echo "${ECHO_T}$ac_cv_path_EGREP" >&6; } + EGREP="$ac_cv_path_EGREP" + + +{ echo "$as_me:$LINENO: checking for ANSI C header files" >&5 +echo $ECHO_N "checking for ANSI C header files... $ECHO_C" >&6; } +if test "${ac_cv_header_stdc+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#include +#include + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_header_stdc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_header_stdc=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + +if test $ac_cv_header_stdc = yes; then + # SunOS 4.x string.h does not declare mem*, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "memchr" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI. + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include + +_ACEOF +if (eval "$ac_cpp conftest.$ac_ext") 2>&5 | + $EGREP "free" >/dev/null 2>&1; then + : +else + ac_cv_header_stdc=no +fi +rm -f conftest* + +fi + +if test $ac_cv_header_stdc = yes; then + # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi. + if test "$cross_compiling" = yes; then + : +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include +#if ((' ' & 0x0FF) == 0x020) +# define ISLOWER(c) ('a' <= (c) && (c) <= 'z') +# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c)) +#else +# define ISLOWER(c) \ + (('a' <= (c) && (c) <= 'i') \ + || ('j' <= (c) && (c) <= 'r') \ + || ('s' <= (c) && (c) <= 'z')) +# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c)) +#endif + +#define XOR(e, f) (((e) && !(f)) || (!(e) && (f))) +int +main () +{ + int i; + for (i = 0; i < 256; i++) + if (XOR (islower (i), ISLOWER (i)) + || toupper (i) != TOUPPER (i)) + return 2; + return 0; +} +_ACEOF +rm -f conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { ac_try='./conftest$ac_exeext' + { (case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_try") 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: program exited with status $ac_status" >&5 +echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +( exit $ac_status ) +ac_cv_header_stdc=no +fi +rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext +fi + + +fi +fi +{ echo "$as_me:$LINENO: result: $ac_cv_header_stdc" >&5 +echo "${ECHO_T}$ac_cv_header_stdc" >&6; } +if test $ac_cv_header_stdc = yes; then + +cat >>confdefs.h <<\_ACEOF +#define STDC_HEADERS 1 +_ACEOF + +fi + +# On IRIX 5.3, sys/types and inttypes.h are conflicting. + + + + + + + + + +for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \ + inttypes.h stdint.h unistd.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default + +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + eval "$as_ac_Header=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_Header=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + + + +for ac_header in sys/types.h sys/param.h sys/stat.h sys/time.h sys/mman.h sys/uio.h sys/socket.h sys/time.h sys/vfs.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------------- ## +## Report this to Alistair Crooks ## +## ----------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + +for ac_header in arpa/inet.h netinet/in.h netinet/tcp.h netdb.h poll.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------------- ## +## Report this to Alistair Crooks ## +## ----------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + +for ac_header in asm/byteorder.h sys/bswap.h sys/byteorder.h sys/select.h libkern/OSByteOrder.h byteswap.h machine/endian.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------------- ## +## Report this to Alistair Crooks ## +## ----------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + + + + + + + + + + + + + + +for ac_header in ctype.h errno.h fcntl.h pthread.h pwd.h signal.h stdint.h stdlib.h syslog.h unistd.h string.h stdarg.h utime.h uuid.h +do +as_ac_Header=`echo "ac_cv_header_$ac_header" | $as_tr_sh` +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + { echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +else + # Is the header compilable? +{ echo "$as_me:$LINENO: checking $ac_header usability" >&5 +echo $ECHO_N "checking $ac_header usability... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +#include <$ac_header> +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_header_compiler=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_compiler=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_compiler" >&5 +echo "${ECHO_T}$ac_header_compiler" >&6; } + +# Is the header present? +{ echo "$as_me:$LINENO: checking $ac_header presence" >&5 +echo $ECHO_N "checking $ac_header presence... $ECHO_C" >&6; } +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include <$ac_header> +_ACEOF +if { (ac_try="$ac_cpp conftest.$ac_ext" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_cpp conftest.$ac_ext") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } >/dev/null && { + test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" || + test ! -s conftest.err + }; then + ac_header_preproc=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_header_preproc=no +fi + +rm -f conftest.err conftest.$ac_ext +{ echo "$as_me:$LINENO: result: $ac_header_preproc" >&5 +echo "${ECHO_T}$ac_header_preproc" >&6; } + +# So? What about this header? +case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in + yes:no: ) + { echo "$as_me:$LINENO: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&5 +echo "$as_me: WARNING: $ac_header: accepted by the compiler, rejected by the preprocessor!" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the compiler's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the compiler's result" >&2;} + ac_header_preproc=yes + ;; + no:yes:* ) + { echo "$as_me:$LINENO: WARNING: $ac_header: present but cannot be compiled" >&5 +echo "$as_me: WARNING: $ac_header: present but cannot be compiled" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: check for missing prerequisite headers?" >&5 +echo "$as_me: WARNING: $ac_header: check for missing prerequisite headers?" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: see the Autoconf documentation" >&5 +echo "$as_me: WARNING: $ac_header: see the Autoconf documentation" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&5 +echo "$as_me: WARNING: $ac_header: section \"Present But Cannot Be Compiled\"" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: proceeding with the preprocessor's result" >&5 +echo "$as_me: WARNING: $ac_header: proceeding with the preprocessor's result" >&2;} + { echo "$as_me:$LINENO: WARNING: $ac_header: in the future, the compiler will take precedence" >&5 +echo "$as_me: WARNING: $ac_header: in the future, the compiler will take precedence" >&2;} + ( cat <<\_ASBOX +## ----------------------------------------------- ## +## Report this to Alistair Crooks ## +## ----------------------------------------------- ## +_ASBOX + ) | sed "s/^/$as_me: WARNING: /" >&2 + ;; +esac +{ echo "$as_me:$LINENO: checking for $ac_header" >&5 +echo $ECHO_N "checking for $ac_header... $ECHO_C" >&6; } +if { as_var=$as_ac_Header; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + eval "$as_ac_Header=\$ac_header_preproc" +fi +ac_res=`eval echo '${'$as_ac_Header'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } + +fi +if test `eval echo '${'$as_ac_Header'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_header" | $as_tr_cpp` 1 +_ACEOF + +fi + +done + + +{ echo "$as_me:$LINENO: checking for an ANSI C-conforming const" >&5 +echo $ECHO_N "checking for an ANSI C-conforming const... $ECHO_C" >&6; } +if test "${ac_cv_c_const+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +/* FIXME: Include the comments suggested by Paul. */ +#ifndef __cplusplus + /* Ultrix mips cc rejects this. */ + typedef int charset[2]; + const charset cs; + /* SunOS 4.1.1 cc rejects this. */ + char const *const *pcpcc; + char **ppc; + /* NEC SVR4.0.2 mips cc rejects this. */ + struct point {int x, y;}; + static struct point const zero = {0,0}; + /* AIX XL C 1.02.0.0 rejects this. + It does not let you subtract one const X* pointer from another in + an arm of an if-expression whose if-part is not a constant + expression */ + const char *g = "string"; + pcpcc = &g + (g ? g-g : 0); + /* HPUX 7.0 cc rejects these. */ + ++pcpcc; + ppc = (char**) pcpcc; + pcpcc = (char const *const *) ppc; + { /* SCO 3.2v4 cc rejects this. */ + char *t; + char const *s = 0 ? (char *) 0 : (char const *) 0; + + *t++ = 0; + if (s) return 0; + } + { /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */ + int x[] = {25, 17}; + const int *foo = &x[0]; + ++foo; + } + { /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */ + typedef const int *iptr; + iptr p = 0; + ++p; + } + { /* AIX XL C 1.02.0.0 rejects this saying + "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */ + struct s { int j; const int *ap[3]; }; + struct s *b; b->j = 5; + } + { /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */ + const int foo = 10; + if (!foo) return 0; + } + return !cs[0] && !zero.x; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_c_const=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_c_const=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_c_const" >&5 +echo "${ECHO_T}$ac_cv_c_const" >&6; } +if test $ac_cv_c_const = no; then + +cat >>confdefs.h <<\_ACEOF +#define const +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for size_t" >&5 +echo $ECHO_N "checking for size_t... $ECHO_C" >&6; } +if test "${ac_cv_type_size_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef size_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_size_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_size_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_size_t" >&5 +echo "${ECHO_T}$ac_cv_type_size_t" >&6; } +if test $ac_cv_type_size_t = yes; then + : +else + +cat >>confdefs.h <<_ACEOF +#define size_t unsigned int +_ACEOF + +fi + +{ echo "$as_me:$LINENO: checking for socklen_t" >&5 +echo $ECHO_N "checking for socklen_t... $ECHO_C" >&6; } +if test "${ac_cv_type_socklen_t+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +#include +#include + + +typedef socklen_t ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_socklen_t=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_socklen_t=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_socklen_t" >&5 +echo "${ECHO_T}$ac_cv_type_socklen_t" >&6; } +if test $ac_cv_type_socklen_t = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKLEN_T 1 +_ACEOF + + +fi + +{ echo "$as_me:$LINENO: checking for long long" >&5 +echo $ECHO_N "checking for long long... $ECHO_C" >&6; } +if test "${ac_cv_type_long_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef long long ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_long_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_long_long=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_long_long" >&5 +echo "${ECHO_T}$ac_cv_type_long_long" >&6; } +if test $ac_cv_type_long_long = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_LONG_LONG 1 +_ACEOF + + +fi +{ echo "$as_me:$LINENO: checking for unsigned long long" >&5 +echo $ECHO_N "checking for unsigned long long... $ECHO_C" >&6; } +if test "${ac_cv_type_unsigned_long_long+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_includes_default +typedef unsigned long long ac__type_new_; +int +main () +{ +if ((ac__type_new_ *) 0) + return 0; +if (sizeof (ac__type_new_)) + return 0; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (ac_try="$ac_compile" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_compile") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest.$ac_objext; then + ac_cv_type_unsigned_long_long=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_type_unsigned_long_long=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext +fi +{ echo "$as_me:$LINENO: result: $ac_cv_type_unsigned_long_long" >&5 +echo "${ECHO_T}$ac_cv_type_unsigned_long_long" >&6; } +if test $ac_cv_type_unsigned_long_long = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_UNSIGNED_LONG_LONG 1 +_ACEOF + + +fi + +cat >>confdefs.h <<_ACEOF +#define HAVE_SOCKLEN_T $ac_cv_type_socklen_t +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define HAVE_LONG_LONG $ac_cv_type_long_long +_ACEOF + +cat >>confdefs.h <<_ACEOF +#define HAVE_UNSIGNED_LONG_LONG $ac_cv_type_unsigned_long_long +_ACEOF + + + +{ echo "$as_me:$LINENO: checking for gethostbyname in -lnsl" >&5 +echo $ECHO_N "checking for gethostbyname in -lnsl... $ECHO_C" >&6; } +if test "${ac_cv_lib_nsl_gethostbyname+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lnsl $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char gethostbyname (); +int +main () +{ +return gethostbyname (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_nsl_gethostbyname=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_nsl_gethostbyname=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_nsl_gethostbyname" >&5 +echo "${ECHO_T}$ac_cv_lib_nsl_gethostbyname" >&6; } +if test $ac_cv_lib_nsl_gethostbyname = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBNSL 1 +_ACEOF + + LIBS="-lnsl $LIBS" + +fi + + +{ echo "$as_me:$LINENO: checking for connect in -lsocket" >&5 +echo $ECHO_N "checking for connect in -lsocket... $ECHO_C" >&6; } +if test "${ac_cv_lib_socket_connect+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lsocket $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char connect (); +int +main () +{ +return connect (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_socket_connect=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_socket_connect=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_socket_connect" >&5 +echo "${ECHO_T}$ac_cv_lib_socket_connect" >&6; } +if test $ac_cv_lib_socket_connect = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBSOCKET 1 +_ACEOF + + LIBS="-lsocket $LIBS" + +fi + + +{ echo "$as_me:$LINENO: checking for inet_aton in -lresolv" >&5 +echo $ECHO_N "checking for inet_aton in -lresolv... $ECHO_C" >&6; } +if test "${ac_cv_lib_resolv_inet_aton+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + ac_check_lib_save_LIBS=$LIBS +LIBS="-lresolv $LIBS" +cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char inet_aton (); +int +main () +{ +return inet_aton (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + ac_cv_lib_resolv_inet_aton=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + ac_cv_lib_resolv_inet_aton=no +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +LIBS=$ac_check_lib_save_LIBS +fi +{ echo "$as_me:$LINENO: result: $ac_cv_lib_resolv_inet_aton" >&5 +echo "${ECHO_T}$ac_cv_lib_resolv_inet_aton" >&6; } +if test $ac_cv_lib_resolv_inet_aton = yes; then + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBRESOLV 1 +_ACEOF + + LIBS="-lresolv $LIBS" + +fi + + + + + + + + + + + + + + + + + + + + + + + +for ac_func in __bswap64 asprintf asnprintf bswap64 daemon fsync_range getaddrinfo getnameinfo htobe64 memset bcopy poll snprintf strlcpy strtoll syslog uuid_create uuid_to_string vasprintf vasnprintf vsnprintf +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +{ echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6; } +if { as_var=$as_ac_var; eval "test \"\${$as_var+set}\" = set"; }; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any GCC internal prototype to avoid an error. + Use char because int might match the return type of a GCC + builtin and then its argument prototype would still apply. */ +#ifdef __cplusplus +extern "C" +#endif +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined __stub_$ac_func || defined __stub___$ac_func +choke me +#endif + +int +main () +{ +return $ac_func (); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (ac_try="$ac_link" +case "(($ac_try" in + *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;; + *) ac_try_echo=$ac_try;; +esac +eval "echo \"\$as_me:$LINENO: $ac_try_echo\"") >&5 + (eval "$ac_link") 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && { + test -z "$ac_c_werror_flag" || + test ! -s conftest.err + } && test -s conftest$ac_exeext && + $as_test_x conftest$ac_exeext; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + + eval "$as_ac_var=no" +fi + +rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \ + conftest$ac_exeext conftest.$ac_ext +fi +ac_res=`eval echo '${'$as_ac_var'}'` + { echo "$as_me:$LINENO: result: $ac_res" >&5 +echo "${ECHO_T}$ac_res" >&6; } +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +ac_config_files="$ac_config_files Makefile" + +cat >confcache <<\_ACEOF +# This file is a shell script that caches the results of configure +# tests run on this system so they can be shared between configure +# scripts and configure runs, see configure's option --config-cache. +# It is not useful on other systems. If it contains results you don't +# want to keep, you may remove or edit it. +# +# config.status only pays attention to the cache file if you give it +# the --recheck option to rerun configure. +# +# `ac_cv_env_foo' variables (set or unset) will be overridden when +# loading this file, other *unset* `ac_cv_foo' will be assigned the +# following values. + +_ACEOF + +# The following way of writing the cache mishandles newlines in values, +# but we know of no workaround that is simple, portable, and efficient. +# So, we kill variables containing newlines. +# Ultrix sh set writes to stderr and can't be redirected directly, +# and sets the high bit in the cache file unless we assign to the vars. +( + for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do + eval ac_val=\$$ac_var + case $ac_val in #( + *${as_nl}*) + case $ac_var in #( + *_cv_*) { echo "$as_me:$LINENO: WARNING: Cache variable $ac_var contains a newline." >&5 +echo "$as_me: WARNING: Cache variable $ac_var contains a newline." >&2;} ;; + esac + case $ac_var in #( + _ | IFS | as_nl) ;; #( + *) $as_unset $ac_var ;; + esac ;; + esac + done + + (set) 2>&1 | + case $as_nl`(ac_space=' '; set) 2>&1` in #( + *${as_nl}ac_space=\ *) + # `set' does not quote correctly, so add quotes (double-quote + # substitution turns \\\\ into \\, and sed turns \\ into \). + sed -n \ + "s/'/'\\\\''/g; + s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p" + ;; #( + *) + # `set' quotes correctly as required by POSIX, so do not add quotes. + sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p" + ;; + esac | + sort +) | + sed ' + /^ac_cv_env_/b end + t clear + :clear + s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/ + t end + s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/ + :end' >>confcache +if diff "$cache_file" confcache >/dev/null 2>&1; then :; else + if test -w "$cache_file"; then + test "x$cache_file" != "x/dev/null" && + { echo "$as_me:$LINENO: updating cache $cache_file" >&5 +echo "$as_me: updating cache $cache_file" >&6;} + cat confcache >$cache_file + else + { echo "$as_me:$LINENO: not updating unwritable cache $cache_file" >&5 +echo "$as_me: not updating unwritable cache $cache_file" >&6;} + fi +fi +rm -f confcache + +test "x$prefix" = xNONE && prefix=$ac_default_prefix +# Let make expand exec_prefix. +test "x$exec_prefix" = xNONE && exec_prefix='${prefix}' + +DEFS=-DHAVE_CONFIG_H + +ac_libobjs= +ac_ltlibobjs= +for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue + # 1. Remove the extension, and $U if already installed. + ac_script='s/\$U\././;s/\.o$//;s/\.obj$//' + ac_i=`echo "$ac_i" | sed "$ac_script"` + # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR + # will be set to the directory where LIBOBJS objects are built. + ac_libobjs="$ac_libobjs \${LIBOBJDIR}$ac_i\$U.$ac_objext" + ac_ltlibobjs="$ac_ltlibobjs \${LIBOBJDIR}$ac_i"'$U.lo' +done +LIBOBJS=$ac_libobjs + +LTLIBOBJS=$ac_ltlibobjs + + + +: ${CONFIG_STATUS=./config.status} +ac_clean_files_save=$ac_clean_files +ac_clean_files="$ac_clean_files $CONFIG_STATUS" +{ echo "$as_me:$LINENO: creating $CONFIG_STATUS" >&5 +echo "$as_me: creating $CONFIG_STATUS" >&6;} +cat >$CONFIG_STATUS <<_ACEOF +#! $SHELL +# Generated by $as_me. +# Run this file to recreate the current configuration. +# Compiler output produced by configure, useful for debugging +# configure, is in config.log if it exists. + +debug=false +ac_cs_recheck=false +ac_cs_silent=false +SHELL=\${CONFIG_SHELL-$SHELL} +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +## --------------------- ## +## M4sh Initialization. ## +## --------------------- ## + +# Be more Bourne compatible +DUALCASE=1; export DUALCASE # for MKS sh +if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then + emulate sh + NULLCMD=: + # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which + # is contrary to our usage. Disable this feature. + alias -g '${1+"$@"}'='"$@"' + setopt NO_GLOB_SUBST +else + case `(set -o) 2>/dev/null` in + *posix*) set -o posix ;; +esac + +fi + + + + +# PATH needs CR +# Avoid depending upon Character Ranges. +as_cr_letters='abcdefghijklmnopqrstuvwxyz' +as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ' +as_cr_Letters=$as_cr_letters$as_cr_LETTERS +as_cr_digits='0123456789' +as_cr_alnum=$as_cr_Letters$as_cr_digits + +# The user is always right. +if test "${PATH_SEPARATOR+set}" != set; then + echo "#! /bin/sh" >conf$$.sh + echo "exit 0" >>conf$$.sh + chmod +x conf$$.sh + if (PATH="/nonexistent;."; conf$$.sh) >/dev/null 2>&1; then + PATH_SEPARATOR=';' + else + PATH_SEPARATOR=: + fi + rm -f conf$$.sh +fi + +# Support unset when possible. +if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then + as_unset=unset +else + as_unset=false +fi + + +# IFS +# We need space, tab and new line, in precisely that order. Quoting is +# there to prevent editors from complaining about space-tab. +# (If _AS_PATH_WALK were called with IFS unset, it would disable word +# splitting by setting IFS to empty value.) +as_nl=' +' +IFS=" "" $as_nl" + +# Find who we are. Look in the path if we contain no directory separator. +case $0 in + *[\\/]* ) as_myself=$0 ;; + *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break +done +IFS=$as_save_IFS + + ;; +esac +# We did not find ourselves, most probably we were run as `sh COMMAND' +# in which case we are not to be found in the path. +if test "x$as_myself" = x; then + as_myself=$0 +fi +if test ! -f "$as_myself"; then + echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2 + { (exit 1); exit 1; } +fi + +# Work around bugs in pre-3.0 UWIN ksh. +for as_var in ENV MAIL MAILPATH +do ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var +done +PS1='$ ' +PS2='> ' +PS4='+ ' + +# NLS nuisances. +for as_var in \ + LANG LANGUAGE LC_ADDRESS LC_ALL LC_COLLATE LC_CTYPE LC_IDENTIFICATION \ + LC_MEASUREMENT LC_MESSAGES LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER \ + LC_TELEPHONE LC_TIME +do + if (set +x; test -z "`(eval $as_var=C; export $as_var) 2>&1`"); then + eval $as_var=C; export $as_var + else + ($as_unset $as_var) >/dev/null 2>&1 && $as_unset $as_var + fi +done + +# Required to use basename. +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then + as_basename=basename +else + as_basename=false +fi + + +# Name of the executable. +as_me=`$as_basename -- "$0" || +$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \ + X"$0" : 'X\(//\)$' \| \ + X"$0" : 'X\(/\)' \| . 2>/dev/null || +echo X/"$0" | + sed '/^.*\/\([^/][^/]*\)\/*$/{ + s//\1/ + q + } + /^X\/\(\/\/\)$/{ + s//\1/ + q + } + /^X\/\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + +# CDPATH. +$as_unset CDPATH + + + + as_lineno_1=$LINENO + as_lineno_2=$LINENO + test "x$as_lineno_1" != "x$as_lineno_2" && + test "x`expr $as_lineno_1 + 1`" = "x$as_lineno_2" || { + + # Create $as_me.lineno as a copy of $as_myself, but with $LINENO + # uniformly replaced by the line number. The first 'sed' inserts a + # line-number line after each line using $LINENO; the second 'sed' + # does the real work. The second script uses 'N' to pair each + # line-number line with the line containing $LINENO, and appends + # trailing '-' during substitution so that $LINENO is not a special + # case at line end. + # (Raja R Harinath suggested sed '=', and Paul Eggert wrote the + # scripts with optimization help from Paolo Bonzini. Blame Lee + # E. McMahon (1931-1989) for sed's syntax. :-) + sed -n ' + p + /[$]LINENO/= + ' <$as_myself | + sed ' + s/[$]LINENO.*/&-/ + t lineno + b + :lineno + N + :loop + s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/ + t loop + s/-\n.*// + ' >$as_me.lineno && + chmod +x "$as_me.lineno" || + { echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2 + { (exit 1); exit 1; }; } + + # Don't try to exec as it changes $[0], causing all sort of problems + # (the dirname of $[0] is not the place where we might find the + # original and so on. Autoconf is especially sensitive to this). + . "./$as_me.lineno" + # Exit status is that of the last command. + exit +} + + +if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then + as_dirname=dirname +else + as_dirname=false +fi + +ECHO_C= ECHO_N= ECHO_T= +case `echo -n x` in +-n*) + case `echo 'x\c'` in + *c*) ECHO_T=' ';; # ECHO_T is single tab character. + *) ECHO_C='\c';; + esac;; +*) + ECHO_N='-n';; +esac + +if expr a : '\(a\)' >/dev/null 2>&1 && + test "X`expr 00001 : '.*\(...\)'`" = X001; then + as_expr=expr +else + as_expr=false +fi + +rm -f conf$$ conf$$.exe conf$$.file +if test -d conf$$.dir; then + rm -f conf$$.dir/conf$$.file +else + rm -f conf$$.dir + mkdir conf$$.dir +fi +echo >conf$$.file +if ln -s conf$$.file conf$$ 2>/dev/null; then + as_ln_s='ln -s' + # ... but there are two gotchas: + # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail. + # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable. + # In both cases, we have to default to `cp -p'. + ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe || + as_ln_s='cp -p' +elif ln conf$$.file conf$$ 2>/dev/null; then + as_ln_s=ln +else + as_ln_s='cp -p' +fi +rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file +rmdir conf$$.dir 2>/dev/null + +if mkdir -p . 2>/dev/null; then + as_mkdir_p=: +else + test -d ./-p && rmdir ./-p + as_mkdir_p=false +fi + +if test -x / >/dev/null 2>&1; then + as_test_x='test -x' +else + if ls -dL / >/dev/null 2>&1; then + as_ls_L_option=L + else + as_ls_L_option= + fi + as_test_x=' + eval sh -c '\'' + if test -d "$1"; then + test -d "$1/."; + else + case $1 in + -*)set "./$1";; + esac; + case `ls -ld'$as_ls_L_option' "$1" 2>/dev/null` in + ???[sx]*):;;*)false;;esac;fi + '\'' sh + ' +fi +as_executable_p=$as_test_x + +# Sed expression to map a string onto a valid CPP name. +as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'" + +# Sed expression to map a string onto a valid variable name. +as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'" + + +exec 6>&1 + +# Save the log message, to keep $[0] and so on meaningful, and to +# report actual input values of CONFIG_FILES etc. instead of their +# values after options handling. +ac_log=" +This file was extended by netbsd-iscsi $as_me 20080207, which was +generated by GNU Autoconf 2.61. Invocation command line was + + CONFIG_FILES = $CONFIG_FILES + CONFIG_HEADERS = $CONFIG_HEADERS + CONFIG_LINKS = $CONFIG_LINKS + CONFIG_COMMANDS = $CONFIG_COMMANDS + $ $0 $@ + +on `(hostname || uname -n) 2>/dev/null | sed 1q` +" + +_ACEOF + +cat >>$CONFIG_STATUS <<_ACEOF +# Files that config.status was made for. +config_files="$ac_config_files" +config_headers="$ac_config_headers" + +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +ac_cs_usage="\ +\`$as_me' instantiates files from templates according to the +current configuration. + +Usage: $0 [OPTIONS] [FILE]... + + -h, --help print this help, then exit + -V, --version print version number and configuration settings, then exit + -q, --quiet do not print progress messages + -d, --debug don't remove temporary files + --recheck update $as_me by reconfiguring in the same conditions + --file=FILE[:TEMPLATE] + instantiate the configuration file FILE + --header=FILE[:TEMPLATE] + instantiate the configuration header FILE + +Configuration files: +$config_files + +Configuration headers: +$config_headers + +Report bugs to ." + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +ac_cs_version="\\ +netbsd-iscsi config.status 20080207 +configured by $0, generated by GNU Autoconf 2.61, + with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\" + +Copyright (C) 2006 Free Software Foundation, Inc. +This config.status script is free software; the Free Software Foundation +gives unlimited permission to copy, distribute and modify it." + +ac_pwd='$ac_pwd' +srcdir='$srcdir' +INSTALL='$INSTALL' +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If no file are specified by the user, then we need to provide default +# value. By we need to know if files were specified by the user. +ac_need_defaults=: +while test $# != 0 +do + case $1 in + --*=*) + ac_option=`expr "X$1" : 'X\([^=]*\)='` + ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'` + ac_shift=: + ;; + *) + ac_option=$1 + ac_optarg=$2 + ac_shift=shift + ;; + esac + + case $ac_option in + # Handling of the options. + -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r) + ac_cs_recheck=: ;; + --version | --versio | --versi | --vers | --ver | --ve | --v | -V ) + echo "$ac_cs_version"; exit ;; + --debug | --debu | --deb | --de | --d | -d ) + debug=: ;; + --file | --fil | --fi | --f ) + $ac_shift + CONFIG_FILES="$CONFIG_FILES $ac_optarg" + ac_need_defaults=false;; + --header | --heade | --head | --hea ) + $ac_shift + CONFIG_HEADERS="$CONFIG_HEADERS $ac_optarg" + ac_need_defaults=false;; + --he | --h) + # Conflict between --help and --header + { echo "$as_me: error: ambiguous option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; };; + --help | --hel | -h ) + echo "$ac_cs_usage"; exit ;; + -q | -quiet | --quiet | --quie | --qui | --qu | --q \ + | -silent | --silent | --silen | --sile | --sil | --si | --s) + ac_cs_silent=: ;; + + # This is an error. + -*) { echo "$as_me: error: unrecognized option: $1 +Try \`$0 --help' for more information." >&2 + { (exit 1); exit 1; }; } ;; + + *) ac_config_targets="$ac_config_targets $1" + ac_need_defaults=false ;; + + esac + shift +done + +ac_configure_extra_args= + +if $ac_cs_silent; then + exec 6>/dev/null + ac_configure_extra_args="$ac_configure_extra_args --silent" +fi + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +if \$ac_cs_recheck; then + echo "running CONFIG_SHELL=$SHELL $SHELL $0 "$ac_configure_args \$ac_configure_extra_args " --no-create --no-recursion" >&6 + CONFIG_SHELL=$SHELL + export CONFIG_SHELL + exec $SHELL "$0"$ac_configure_args \$ac_configure_extra_args --no-create --no-recursion +fi + +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +exec 5>>config.log +{ + echo + sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX +## Running $as_me. ## +_ASBOX + echo "$ac_log" +} >&5 + +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF + +# Handling of arguments. +for ac_config_target in $ac_config_targets +do + case $ac_config_target in + "../include/config.h") CONFIG_HEADERS="$CONFIG_HEADERS ../include/config.h" ;; + "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;; + + *) { { echo "$as_me:$LINENO: error: invalid argument: $ac_config_target" >&5 +echo "$as_me: error: invalid argument: $ac_config_target" >&2;} + { (exit 1); exit 1; }; };; + esac +done + + +# If the user did not use the arguments to specify the items to instantiate, +# then the envvar interface is used. Set only those that are not. +# We use the long form for the default assignment because of an extremely +# bizarre bug on SunOS 4.1.3. +if $ac_need_defaults; then + test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files + test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers +fi + +# Have a temporary directory for convenience. Make it in the build tree +# simply because there is no reason against having it here, and in addition, +# creating and moving files from /tmp can sometimes cause problems. +# Hook for its removal unless debugging. +# Note that there is a small window in which the directory will not be cleaned: +# after its creation but before its name has been assigned to `$tmp'. +$debug || +{ + tmp= + trap 'exit_status=$? + { test -z "$tmp" || test ! -d "$tmp" || rm -fr "$tmp"; } && exit $exit_status +' 0 + trap '{ (exit 1); exit 1; }' 1 2 13 15 +} +# Create a (secure) tmp directory for tmp files. + +{ + tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` && + test -n "$tmp" && test -d "$tmp" +} || +{ + tmp=./conf$$-$RANDOM + (umask 077 && mkdir "$tmp") +} || +{ + echo "$me: cannot create a temporary directory in ." >&2 + { (exit 1); exit 1; } +} + +# +# Set up the sed scripts for CONFIG_FILES section. +# + +# No need to generate the scripts if there are no CONFIG_FILES. +# This happens for instance when ./config.status config.h +if test -n "$CONFIG_FILES"; then + +_ACEOF + + + +ac_delim='%!_!# ' +for ac_last_try in false false false false false :; do + cat >conf$$subs.sed <<_ACEOF +SHELL!$SHELL$ac_delim +PATH_SEPARATOR!$PATH_SEPARATOR$ac_delim +PACKAGE_NAME!$PACKAGE_NAME$ac_delim +PACKAGE_TARNAME!$PACKAGE_TARNAME$ac_delim +PACKAGE_VERSION!$PACKAGE_VERSION$ac_delim +PACKAGE_STRING!$PACKAGE_STRING$ac_delim +PACKAGE_BUGREPORT!$PACKAGE_BUGREPORT$ac_delim +exec_prefix!$exec_prefix$ac_delim +prefix!$prefix$ac_delim +program_transform_name!$program_transform_name$ac_delim +bindir!$bindir$ac_delim +sbindir!$sbindir$ac_delim +libexecdir!$libexecdir$ac_delim +datarootdir!$datarootdir$ac_delim +datadir!$datadir$ac_delim +sysconfdir!$sysconfdir$ac_delim +sharedstatedir!$sharedstatedir$ac_delim +localstatedir!$localstatedir$ac_delim +includedir!$includedir$ac_delim +oldincludedir!$oldincludedir$ac_delim +docdir!$docdir$ac_delim +infodir!$infodir$ac_delim +htmldir!$htmldir$ac_delim +dvidir!$dvidir$ac_delim +pdfdir!$pdfdir$ac_delim +psdir!$psdir$ac_delim +libdir!$libdir$ac_delim +localedir!$localedir$ac_delim +mandir!$mandir$ac_delim +DEFS!$DEFS$ac_delim +ECHO_C!$ECHO_C$ac_delim +ECHO_N!$ECHO_N$ac_delim +ECHO_T!$ECHO_T$ac_delim +LIBS!$LIBS$ac_delim +build_alias!$build_alias$ac_delim +host_alias!$host_alias$ac_delim +target_alias!$target_alias$ac_delim +INSTALL_PROGRAM!$INSTALL_PROGRAM$ac_delim +INSTALL_SCRIPT!$INSTALL_SCRIPT$ac_delim +INSTALL_DATA!$INSTALL_DATA$ac_delim +CC!$CC$ac_delim +CFLAGS!$CFLAGS$ac_delim +LDFLAGS!$LDFLAGS$ac_delim +CPPFLAGS!$CPPFLAGS$ac_delim +ac_ct_CC!$ac_ct_CC$ac_delim +EXEEXT!$EXEEXT$ac_delim +OBJEXT!$OBJEXT$ac_delim +RANLIB!$RANLIB$ac_delim +CPP!$CPP$ac_delim +GREP!$GREP$ac_delim +EGREP!$EGREP$ac_delim +LIBOBJS!$LIBOBJS$ac_delim +LTLIBOBJS!$LTLIBOBJS$ac_delim +_ACEOF + + if test `sed -n "s/.*$ac_delim\$/X/p" conf$$subs.sed | grep -c X` = 53; then + break + elif $ac_last_try; then + { { echo "$as_me:$LINENO: error: could not make $CONFIG_STATUS" >&5 +echo "$as_me: error: could not make $CONFIG_STATUS" >&2;} + { (exit 1); exit 1; }; } + else + ac_delim="$ac_delim!$ac_delim _$ac_delim!! " + fi +done + +ac_eof=`sed -n '/^CEOF[0-9]*$/s/CEOF/0/p' conf$$subs.sed` +if test -n "$ac_eof"; then + ac_eof=`echo "$ac_eof" | sort -nru | sed 1q` + ac_eof=`expr $ac_eof + 1` +fi + +cat >>$CONFIG_STATUS <<_ACEOF +cat >"\$tmp/subs-1.sed" <<\CEOF$ac_eof +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b end +_ACEOF +sed ' +s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g +s/^/s,@/; s/!/@,|#_!!_#|/ +:n +t n +s/'"$ac_delim"'$/,g/; t +s/$/\\/; p +N; s/^.*\n//; s/[,\\&]/\\&/g; s/@/@|#_!!_#|/g; b n +' >>$CONFIG_STATUS >$CONFIG_STATUS <<_ACEOF +:end +s/|#_!!_#|//g +CEOF$ac_eof +_ACEOF + + +# VPATH may cause trouble with some makes, so we remove $(srcdir), +# ${srcdir} and @srcdir@ from VPATH if srcdir is ".", strip leading and +# trailing colons and then remove the whole line if VPATH becomes empty +# (actually we leave an empty line to preserve line numbers). +if test "x$srcdir" = x.; then + ac_vpsub='/^[ ]*VPATH[ ]*=/{ +s/:*\$(srcdir):*/:/ +s/:*\${srcdir}:*/:/ +s/:*@srcdir@:*/:/ +s/^\([^=]*=[ ]*\):*/\1/ +s/:*$// +s/^[^=]*=[ ]*$// +}' +fi + +cat >>$CONFIG_STATUS <<\_ACEOF +fi # test -n "$CONFIG_FILES" + + +for ac_tag in :F $CONFIG_FILES :H $CONFIG_HEADERS +do + case $ac_tag in + :[FHLC]) ac_mode=$ac_tag; continue;; + esac + case $ac_mode$ac_tag in + :[FHL]*:*);; + :L* | :C*:*) { { echo "$as_me:$LINENO: error: Invalid tag $ac_tag." >&5 +echo "$as_me: error: Invalid tag $ac_tag." >&2;} + { (exit 1); exit 1; }; };; + :[FH]-) ac_tag=-:-;; + :[FH]*) ac_tag=$ac_tag:$ac_tag.in;; + esac + ac_save_IFS=$IFS + IFS=: + set x $ac_tag + IFS=$ac_save_IFS + shift + ac_file=$1 + shift + + case $ac_mode in + :L) ac_source=$1;; + :[FH]) + ac_file_inputs= + for ac_f + do + case $ac_f in + -) ac_f="$tmp/stdin";; + *) # Look for the file first in the build tree, then in the source tree + # (if the path is not absolute). The absolute path cannot be DOS-style, + # because $ac_f cannot contain `:'. + test -f "$ac_f" || + case $ac_f in + [\\/$]*) false;; + *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";; + esac || + { { echo "$as_me:$LINENO: error: cannot find input file: $ac_f" >&5 +echo "$as_me: error: cannot find input file: $ac_f" >&2;} + { (exit 1); exit 1; }; };; + esac + ac_file_inputs="$ac_file_inputs $ac_f" + done + + # Let's still pretend it is `configure' which instantiates (i.e., don't + # use $as_me), people would be surprised to read: + # /* config.h. Generated by config.status. */ + configure_input="Generated from "`IFS=: + echo $* | sed 's|^[^:]*/||;s|:[^:]*/|, |g'`" by configure." + if test x"$ac_file" != x-; then + configure_input="$ac_file. $configure_input" + { echo "$as_me:$LINENO: creating $ac_file" >&5 +echo "$as_me: creating $ac_file" >&6;} + fi + + case $ac_tag in + *:-:* | *:-) cat >"$tmp/stdin";; + esac + ;; + esac + + ac_dir=`$as_dirname -- "$ac_file" || +$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$ac_file" : 'X\(//\)[^/]' \| \ + X"$ac_file" : 'X\(//\)$' \| \ + X"$ac_file" : 'X\(/\)' \| . 2>/dev/null || +echo X"$ac_file" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + { as_dir="$ac_dir" + case $as_dir in #( + -*) as_dir=./$as_dir;; + esac + test -d "$as_dir" || { $as_mkdir_p && mkdir -p "$as_dir"; } || { + as_dirs= + while :; do + case $as_dir in #( + *\'*) as_qdir=`echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #( + *) as_qdir=$as_dir;; + esac + as_dirs="'$as_qdir' $as_dirs" + as_dir=`$as_dirname -- "$as_dir" || +$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \ + X"$as_dir" : 'X\(//\)[^/]' \| \ + X"$as_dir" : 'X\(//\)$' \| \ + X"$as_dir" : 'X\(/\)' \| . 2>/dev/null || +echo X"$as_dir" | + sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{ + s//\1/ + q + } + /^X\(\/\/\)[^/].*/{ + s//\1/ + q + } + /^X\(\/\/\)$/{ + s//\1/ + q + } + /^X\(\/\).*/{ + s//\1/ + q + } + s/.*/./; q'` + test -d "$as_dir" && break + done + test -z "$as_dirs" || eval "mkdir $as_dirs" + } || test -d "$as_dir" || { { echo "$as_me:$LINENO: error: cannot create directory $as_dir" >&5 +echo "$as_me: error: cannot create directory $as_dir" >&2;} + { (exit 1); exit 1; }; }; } + ac_builddir=. + +case "$ac_dir" in +.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;; +*) + ac_dir_suffix=/`echo "$ac_dir" | sed 's,^\.[\\/],,'` + # A ".." for each directory in $ac_dir_suffix. + ac_top_builddir_sub=`echo "$ac_dir_suffix" | sed 's,/[^\\/]*,/..,g;s,/,,'` + case $ac_top_builddir_sub in + "") ac_top_builddir_sub=. ac_top_build_prefix= ;; + *) ac_top_build_prefix=$ac_top_builddir_sub/ ;; + esac ;; +esac +ac_abs_top_builddir=$ac_pwd +ac_abs_builddir=$ac_pwd$ac_dir_suffix +# for backward compatibility: +ac_top_builddir=$ac_top_build_prefix + +case $srcdir in + .) # We are building in place. + ac_srcdir=. + ac_top_srcdir=$ac_top_builddir_sub + ac_abs_top_srcdir=$ac_pwd ;; + [\\/]* | ?:[\\/]* ) # Absolute name. + ac_srcdir=$srcdir$ac_dir_suffix; + ac_top_srcdir=$srcdir + ac_abs_top_srcdir=$srcdir ;; + *) # Relative name. + ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix + ac_top_srcdir=$ac_top_build_prefix$srcdir + ac_abs_top_srcdir=$ac_pwd/$srcdir ;; +esac +ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix + + + case $ac_mode in + :F) + # + # CONFIG_FILE + # + + case $INSTALL in + [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;; + *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;; + esac +_ACEOF + +cat >>$CONFIG_STATUS <<\_ACEOF +# If the template does not know about datarootdir, expand it. +# FIXME: This hack should be removed a few years after 2.60. +ac_datarootdir_hack=; ac_datarootdir_seen= + +case `sed -n '/datarootdir/ { + p + q +} +/@datadir@/p +/@docdir@/p +/@infodir@/p +/@localedir@/p +/@mandir@/p +' $ac_file_inputs` in +*datarootdir*) ac_datarootdir_seen=yes;; +*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*) + { echo "$as_me:$LINENO: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5 +echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;} +_ACEOF +cat >>$CONFIG_STATUS <<_ACEOF + ac_datarootdir_hack=' + s&@datadir@&$datadir&g + s&@docdir@&$docdir&g + s&@infodir@&$infodir&g + s&@localedir@&$localedir&g + s&@mandir@&$mandir&g + s&\\\${datarootdir}&$datarootdir&g' ;; +esac +_ACEOF + +# Neutralize VPATH when `$srcdir' = `.'. +# Shell code in configure.ac might set extrasub. +# FIXME: do we really want to maintain this feature? +cat >>$CONFIG_STATUS <<_ACEOF + sed "$ac_vpsub +$extrasub +_ACEOF +cat >>$CONFIG_STATUS <<\_ACEOF +:t +/@[a-zA-Z_][a-zA-Z_0-9]*@/!b +s&@configure_input@&$configure_input&;t t +s&@top_builddir@&$ac_top_builddir_sub&;t t +s&@srcdir@&$ac_srcdir&;t t +s&@abs_srcdir@&$ac_abs_srcdir&;t t +s&@top_srcdir@&$ac_top_srcdir&;t t +s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t +s&@builddir@&$ac_builddir&;t t +s&@abs_builddir@&$ac_abs_builddir&;t t +s&@abs_top_builddir@&$ac_abs_top_builddir&;t t +s&@INSTALL@&$ac_INSTALL&;t t +$ac_datarootdir_hack +" $ac_file_inputs | sed -f "$tmp/subs-1.sed" >$tmp/out + +test -z "$ac_datarootdir_hack$ac_datarootdir_seen" && + { ac_out=`sed -n '/\${datarootdir}/p' "$tmp/out"`; test -n "$ac_out"; } && + { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' "$tmp/out"`; test -z "$ac_out"; } && + { echo "$as_me:$LINENO: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&5 +echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir' +which seems to be undefined. Please make sure it is defined." >&2;} + + rm -f "$tmp/stdin" + case $ac_file in + -) cat "$tmp/out"; rm -f "$tmp/out";; + *) rm -f "$ac_file"; mv "$tmp/out" $ac_file;; + esac + ;; + :H) + # + # CONFIG_HEADER + # +_ACEOF + +# Transform confdefs.h into a sed script `conftest.defines', that +# substitutes the proper values into config.h.in to produce config.h. +rm -f conftest.defines conftest.tail +# First, append a space to every undef/define line, to ease matching. +echo 's/$/ /' >conftest.defines +# Then, protect against being on the right side of a sed subst, or in +# an unquoted here document, in config.status. If some macros were +# called several times there might be several #defines for the same +# symbol, which is useless. But do not sort them, since the last +# AC_DEFINE must be honored. +ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]* +# These sed commands are passed to sed as "A NAME B PARAMS C VALUE D", where +# NAME is the cpp macro being defined, VALUE is the value it is being given. +# PARAMS is the parameter list in the macro definition--in most cases, it's +# just an empty string. +ac_dA='s,^\\([ #]*\\)[^ ]*\\([ ]*' +ac_dB='\\)[ (].*,\\1define\\2' +ac_dC=' ' +ac_dD=' ,' + +uniq confdefs.h | + sed -n ' + t rset + :rset + s/^[ ]*#[ ]*define[ ][ ]*// + t ok + d + :ok + s/[\\&,]/\\&/g + s/^\('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/ '"$ac_dA"'\1'"$ac_dB"'\2'"${ac_dC}"'\3'"$ac_dD"'/p + s/^\('"$ac_word_re"'\)[ ]*\(.*\)/'"$ac_dA"'\1'"$ac_dB$ac_dC"'\2'"$ac_dD"'/p + ' >>conftest.defines + +# Remove the space that was appended to ease matching. +# Then replace #undef with comments. This is necessary, for +# example, in the case of _POSIX_SOURCE, which is predefined and required +# on some systems where configure will not decide to define it. +# (The regexp can be short, since the line contains either #define or #undef.) +echo 's/ $// +s,^[ #]*u.*,/* & */,' >>conftest.defines + +# Break up conftest.defines: +ac_max_sed_lines=50 + +# First sed command is: sed -f defines.sed $ac_file_inputs >"$tmp/out1" +# Second one is: sed -f defines.sed "$tmp/out1" >"$tmp/out2" +# Third one will be: sed -f defines.sed "$tmp/out2" >"$tmp/out1" +# et cetera. +ac_in='$ac_file_inputs' +ac_out='"$tmp/out1"' +ac_nxt='"$tmp/out2"' + +while : +do + # Write a here document: + cat >>$CONFIG_STATUS <<_ACEOF + # First, check the format of the line: + cat >"\$tmp/defines.sed" <<\\CEOF +/^[ ]*#[ ]*undef[ ][ ]*$ac_word_re[ ]*\$/b def +/^[ ]*#[ ]*define[ ][ ]*$ac_word_re[( ]/b def +b +:def +_ACEOF + sed ${ac_max_sed_lines}q conftest.defines >>$CONFIG_STATUS + echo 'CEOF + sed -f "$tmp/defines.sed"' "$ac_in >$ac_out" >>$CONFIG_STATUS + ac_in=$ac_out; ac_out=$ac_nxt; ac_nxt=$ac_in + sed 1,${ac_max_sed_lines}d conftest.defines >conftest.tail + grep . conftest.tail >/dev/null || break + rm -f conftest.defines + mv conftest.tail conftest.defines +done +rm -f conftest.defines conftest.tail + +echo "ac_result=$ac_in" >>$CONFIG_STATUS +cat >>$CONFIG_STATUS <<\_ACEOF + if test x"$ac_file" != x-; then + echo "/* $configure_input */" >"$tmp/config.h" + cat "$ac_result" >>"$tmp/config.h" + if diff $ac_file "$tmp/config.h" >/dev/null 2>&1; then + { echo "$as_me:$LINENO: $ac_file is unchanged" >&5 +echo "$as_me: $ac_file is unchanged" >&6;} + else + rm -f $ac_file + mv "$tmp/config.h" $ac_file + fi + else + echo "/* $configure_input */" + cat "$ac_result" + fi + rm -f "$tmp/out12" + ;; + + + esac + +done # for ac_tag + + +{ (exit 0); exit 0; } +_ACEOF +chmod +x $CONFIG_STATUS +ac_clean_files=$ac_clean_files_save + + +# configure is writing to config.log, and then calls config.status. +# config.status does its own redirection, appending to config.log. +# Unfortunately, on DOS this fails, as config.log is still kept open +# by configure, so config.status won't be able to write to it; its +# output is simply discarded. So we exec the FD to /dev/null, +# effectively closing config.log, so it can be properly (re)opened and +# appended to by config.status. When coming back to configure, we +# need to make the FD available again. +if test "$no_create" != yes; then + ac_cs_success=: + ac_config_status_args= + test "$silent" = yes && + ac_config_status_args="$ac_config_status_args --quiet" + exec 5>/dev/null + $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false + exec 5>>config.log + # Use ||, not &&, to avoid exiting from the if with $? = 1, which + # would make configure fail if this is the last instruction. + $ac_cs_success || { (exit 1); exit 1; } +fi + diff --git a/external/bsd/iscsi/dist/src/configure.ac b/external/bsd/iscsi/dist/src/configure.ac new file mode 100644 index 000000000000..2722780e85be --- /dev/null +++ b/external/bsd/iscsi/dist/src/configure.ac @@ -0,0 +1,40 @@ +dnl Process this file with autoconf to produce a configure script. +AC_PREREQ(2.57) +AC_INIT([netbsd-iscsi],[20080207],[Alistair Crooks ]) +AC_CONFIG_SRCDIR([iscsi.c]) +AC_CONFIG_HEADER(../include/config.h) + +dnl Checks for programs. +AC_PROG_INSTALL +AC_PROG_CC +AC_PROG_RANLIB + +dnl Checks for header files. +AC_HEADER_STDC +AC_CHECK_HEADERS(sys/types.h sys/param.h sys/stat.h sys/time.h sys/mman.h sys/uio.h sys/socket.h sys/time.h sys/vfs.h) +AC_CHECK_HEADERS(arpa/inet.h netinet/in.h netinet/tcp.h netdb.h poll.h) +AC_CHECK_HEADERS(asm/byteorder.h sys/bswap.h sys/byteorder.h sys/select.h libkern/OSByteOrder.h byteswap.h machine/endian.h) +AC_CHECK_HEADERS(ctype.h errno.h fcntl.h pthread.h pwd.h signal.h stdint.h stdlib.h syslog.h unistd.h string.h stdarg.h utime.h uuid.h) + +dnl Checks for typedefs, structures, and compiler characteristics. +AC_C_CONST +AC_TYPE_SIZE_T +AC_CHECK_TYPES(socklen_t,,,[ +#include +#include +]) +AC_CHECK_TYPES([long long, unsigned long long]) +AC_DEFINE_UNQUOTED(HAVE_SOCKLEN_T, $ac_cv_type_socklen_t) +AC_DEFINE_UNQUOTED(HAVE_LONG_LONG, $ac_cv_type_long_long) +AC_DEFINE_UNQUOTED(HAVE_UNSIGNED_LONG_LONG, $ac_cv_type_unsigned_long_long) + +dnl check for libraries +AC_CHECK_LIB(nsl, gethostbyname) +AC_CHECK_LIB(socket, connect) +AC_CHECK_LIB(resolv, inet_aton) + +dnl Check for functionality +AC_CHECK_FUNCS(__bswap64 asprintf asnprintf bswap64 daemon fsync_range getaddrinfo getnameinfo htobe64 memset bcopy poll snprintf strlcpy strtoll syslog uuid_create uuid_to_string vasprintf vasnprintf vsnprintf) + +dnl that's it for now... +AC_OUTPUT(Makefile) diff --git a/external/bsd/iscsi/dist/src/disk.c b/external/bsd/iscsi/dist/src/disk.c new file mode 100644 index 000000000000..a050d4e298bd --- /dev/null +++ b/external/bsd/iscsi/dist/src/disk.c @@ -0,0 +1,1298 @@ +/* $NetBSD: disk.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#ifdef HAVE_UUID_H +#include +#endif + +#include "scsi_cmd_codes.h" + +#include "iscsi.h" +#include "compat.h" +#include "iscsiutil.h" +#include "device.h" +#include "target.h" +#include "defs.h" +#include "storage.h" + +#define CONFIG_DISK_NUM_LUNS_DFLT 1 +#define CONFIG_DISK_BLOCK_LEN_DFLT 512 +#define CONFIG_DISK_NUM_BLOCKS_DFLT 204800 +#define CONFIG_DISK_INITIAL_CHECK_CONDITION 0 +#define CONFIG_DISK_MAX_LUNS 8 + +/* End disk configuration */ + +/* + * Globals + */ +enum { + MAX_RESERVATIONS = 32, + + ISCSI_FS = 0x03, + ISCSI_CONTROL = 0x04 +}; + +#define MB(x) ((x) * 1024 * 1024) + +/* this struct describes an iscsi LUN */ +typedef struct iscsi_disk_t { + int type; /* type of disk - fs/mmap and fs */ + char filename[MAXPATHLEN]; /* filename for the disk itself */ + uint8_t *buffer; /* buffer for disk read/write ops */ + uint64_t blockc; /* # of blocks */ + uint64_t blocklen; /* block size */ + uint64_t luns; /* # of luns */ + uint64_t size; /* size of complete disk */ + uuid_t uuid; /* disk's uuid */ + char *uuid_string; /* uuid string */ + targv_t *tv; /* the component devices and extents */ + uint32_t resc; /* # of reservation keys */ + uint64_t reskeys[MAX_RESERVATIONS]; /* the reservation keys */ +} iscsi_disk_t; + +DEFINE_ARRAY(disks_t, iscsi_disk_t); + +static disks_t disks; +static iscsi_disk_t defaults; + +#ifndef FDATASYNC +/* +this means that we probably don't have the fsync_range(2) system call, +but no matter - define this here to preserve the abstraction for the +disk/extent code +*/ +#define FDATASYNC 0x0010 +#endif + +/* + * Private Interface + */ + +static int disk_read(target_session_t * , iscsi_scsi_cmd_args_t * , uint32_t , uint16_t , uint8_t); +static int disk_write(target_session_t * , iscsi_scsi_cmd_args_t * , uint8_t , uint32_t , uint32_t); + +/* return the de index and offset within the device for RAID0 */ +static int +raid0_getoff(disc_device_t *dp, uint64_t off, uint32_t *d, uint64_t *de_off) +{ + uint64_t o; + + for (o = 0, *d = 0 ; *d < dp->c ; o += dp->xv[*d].size, (*d)++) { + if (off >= o && off < o + dp->xv[*d].size) { + break; + } + } + *de_off = off - o; + return (*d < dp->c); +} + +/* open the extent's device */ +static int +extent_open(disc_extent_t *xp, int mode, int flags) +{ + return xp->fd = open(xp->dev, mode, flags); +} + +/* (recursively) open the device's devices */ +static int +device_open(disc_device_t *dp, int flags, int mode) +{ + int fd; + uint32_t i; + + for (fd = -1, i = 0 ; i < dp->c ; i++) { + switch (dp->xv[i].type) { + case DE_DEVICE: + if ((fd = device_open(dp->xv[i].u.dp, flags, mode)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((fd = extent_open(dp->xv[i].u.xp, flags, mode)) < 0) { + return -1; + } + break; + default: + break; + } + } + return fd; +} + +/* and for the undecided... */ +static int +de_open(disc_de_t *dp, int flags, int mode) +{ + switch(dp->type) { + case DE_DEVICE: + return device_open(dp->u.dp, flags, mode); + case DE_EXTENT: + return extent_open(dp->u.xp, flags, mode); + default: + return -1; + } +} + +/* lseek on the extent */ +static off_t +extent_lseek(disc_extent_t *xp, off_t off, int whence) +{ + return lseek(xp->fd, (long long)(xp->sacred + off), whence); +} + +/* (recursively) lseek on the device's devices */ +static off_t +device_lseek(disc_device_t *dp, off_t off, int whence) +{ + uint64_t suboff; + off_t ret; + uint32_t d; + + ret = -1; + switch(dp->raid) { + case 0: + if (raid0_getoff(dp, (uint64_t) off, &d, &suboff)) { + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_lseek(dp->xv[d].u.dp, (off_t) suboff, whence)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_lseek(dp->xv[d].u.xp, (off_t) suboff, whence)) < 0) { + return -1; + } + break; + default: + break; + } + } + break; + case 1: + for (d = 0 ; d < dp->c ; d++) { + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_lseek(dp->xv[d].u.dp, (off_t) off, whence)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_lseek(dp->xv[d].u.xp, (off_t) off, whence)) < 0) { + return -1; + } + break; + default: + break; + } + } + break; + default: + break; + } + return dp->off = ret; +} + +/* and for the undecided... */ +static off_t +de_lseek(disc_de_t *dp, off_t off, int whence) +{ + switch(dp->type) { + case DE_DEVICE: + return device_lseek(dp->u.dp, off, whence); + case DE_EXTENT: + return extent_lseek(dp->u.xp, off, whence); + default: + return -1; + } +} + +/* fsync_range on the extent */ +static int +extent_fsync_range(disc_extent_t *xp, int how, off_t from, off_t len) +{ +#ifdef HAVE_FSYNC_RANGE + return fsync_range(xp->fd, how, (off_t)(xp->sacred + from), len); +#else + return fsync(xp->fd); +#endif +} + +/* (recursively) fsync_range on the device's devices */ +static int +device_fsync_range(disc_device_t *dp, int how, off_t from, off_t len) +{ + uint64_t suboff; + int ret; + uint32_t d; + + ret = -1; + switch(dp->raid) { + case 0: + if (raid0_getoff(dp, (uint64_t) from, &d, &suboff)) { + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_fsync_range(dp->xv[d].u.dp, how, (off_t)suboff, len)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_fsync_range(dp->xv[d].u.xp, how, (off_t)suboff, len)) < 0) { + return -1; + } + break; + default: + break; + } + } + break; + case 1: + for (d = 0 ; d < dp->c ; d++) { + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_fsync_range(dp->xv[d].u.dp, how, from, len)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_fsync_range(dp->xv[d].u.xp, how, from, len)) < 0) { + return -1; + } + break; + default: + break; + } + } + break; + default: + break; + } + dp->off = (uint64_t) ret; + return ret; +} + +/* and for the undecided... */ +static int +de_fsync_range(disc_de_t *dp, int how, off_t from, off_t len) +{ + switch(dp->type) { + case DE_DEVICE: + return device_fsync_range(dp->u.dp, how, from, len); + case DE_EXTENT: + return extent_fsync_range(dp->u.xp, how, from, len); + default: + return -1; + } +} + +/* read from the extent */ +static ssize_t +extent_read(disc_extent_t *xp, void *buf, size_t cc) +{ + return read(xp->fd, buf, cc); +} + +/* (recursively) read from the device's devices */ +static ssize_t +device_read(disc_device_t *dp, void *buf, size_t cc) +{ + uint64_t suboff; + uint64_t got; + ssize_t ret; + size_t subcc; + char *cbuf; + uint32_t d; + + ret = -1; + switch(dp->raid) { + case 0: + for (cbuf = (char *) buf, got = 0 ; got < cc ; got += ret) { + if (!raid0_getoff(dp, dp->off, &d, &suboff)) { + return -1; + } + if (device_lseek(dp, (off_t)dp->off, SEEK_SET) < 0) { + return -1; + } + subcc = MIN(cc - (size_t)got, (size_t)(dp->len - (size_t)dp->off)); + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_read(dp->xv[d].u.dp, &cbuf[(int)got], subcc)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_read(dp->xv[d].u.xp, &cbuf[(int)got], subcc)) < 0) { + return -1; + } + break; + default: + break; + } + dp->off += ret; + } + ret = (ssize_t)got; + break; + case 1: + for (d = 0 ; d < dp->c ; d++) { + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_read(dp->xv[d].u.dp, buf, cc)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_read(dp->xv[d].u.xp, buf, cc)) < 0) { + return -1; + } + break; + default: + break; + } + } + dp->off += ret; + break; + default: + break; + } + return ret; +} + +/* and for the undecided... */ +static ssize_t +de_read(disc_de_t *dp, void *buf, size_t cc) +{ + switch(dp->type) { + case DE_DEVICE: + return device_read(dp->u.dp, buf, cc); + case DE_EXTENT: + return extent_read(dp->u.xp, buf, cc); + default: + return -1; + } +} + +/* write to the extent */ +static ssize_t +extent_write(disc_extent_t *xp, void *buf, size_t cc) +{ + return write(xp->fd, buf, cc); +} + +/* (recursively) write to the device's devices */ +static ssize_t +device_write(disc_device_t *dp, void *buf, size_t cc) +{ + uint64_t suboff; + uint64_t done; + ssize_t ret; + size_t subcc; + char *cbuf; + uint32_t d; + + ret = -1; + switch(dp->raid) { + case 0: + for (cbuf = (char *) buf, done = 0 ; done < cc ; done += ret) { + if (!raid0_getoff(dp, dp->off, &d, &suboff)) { + return -1; + } + subcc = (size_t) MIN(cc - (size_t)done, (size_t)(dp->len - dp->off)); + if (device_lseek(dp, (off_t)dp->off, SEEK_SET) < 0) { + return -1; + } + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_write(dp->xv[d].u.dp, &cbuf[(int)done], subcc)) < 0) { + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_write(dp->xv[d].u.xp, &cbuf[(int)done], subcc)) < 0) { + return -1; + } + break; + default: + break; + } + dp->off += ret; + } + ret = (ssize_t) done; + break; + case 1: + for (d = 0 ; d < dp->c ; d++) { + switch (dp->xv[d].type) { + case DE_DEVICE: + if ((ret = device_write(dp->xv[d].u.dp, buf, cc)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "device_write RAID1 device write failure\n"); + return -1; + } + break; + case DE_EXTENT: + if ((ret = extent_write(dp->xv[d].u.xp, buf, cc)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "device_write RAID1 extent write failure\n"); + return -1; + } + break; + default: + break; + } + } + dp->off += ret; + break; + default: + break; + } + return ret; +} + +/* and for the undecided... */ +static ssize_t +de_write(disc_de_t *dp, void *buf, size_t cc) +{ + switch(dp->type) { + case DE_DEVICE: + return device_write(dp->u.dp, buf, cc); + case DE_EXTENT: + return extent_write(dp->u.xp, buf, cc); + default: + return -1; + } +} + +/* return non-zero if the target is writable */ +static int +target_writable(disc_target_t *tp) +{ + return !(tp->flags & TARGET_READONLY); +} + +/* return size of the extent */ +static uint64_t +extent_getsize(disc_extent_t *xp) +{ + return xp->len; +} + +/* (recursively) return the size of the device's devices */ +static uint64_t +device_getsize(disc_device_t *dp) +{ + uint64_t size; + uint32_t d; + + size = 0; + switch(dp->raid) { + case 0: + for (d = 0 ; d < dp->c ; d++) { + switch (dp->xv[d].type) { + case DE_DEVICE: + size += device_getsize(dp->xv[d].u.dp); + break; + case DE_EXTENT: + size += extent_getsize(dp->xv[d].u.xp); + break; + default: + break; + } + } + break; + case 1: + size = dp->len; + break; + default: + break; + } + return size; +} + +/* and for the undecided... */ +static int64_t +de_getsize(disc_de_t *dp) +{ + switch(dp->type) { + case DE_DEVICE: + return device_getsize(dp->u.dp); + case DE_EXTENT: + return extent_getsize(dp->u.xp); + default: + return -1; + } +} + +/* return a filename for the device or extent */ +static char * +disc_get_filename(disc_de_t *de) +{ + switch (de->type) { + case DE_EXTENT: + return de->u.xp->dev; + case DE_DEVICE: + return disc_get_filename(&de->u.dp->xv[0]); + default: + return NULL; + } +} + +/* + * Public Interface (called by utarget and ktarket) + */ + + /* set various global variables */ +void +device_set_var(const char *var, char *arg) +{ + if (strcmp(var, "blocklen") == 0) { + defaults.blocklen = strtoll(arg, (char **)NULL, 10); + } else if (strcmp(var, "blocks") == 0) { + defaults.blockc = strtoll(arg, (char **)NULL, 10); + } else if (strcmp(var, "luns") == 0) { + defaults.luns = strtoll(arg, (char **)NULL, 10); + } else { + (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var); + } +} + +/* allocate some space for a disk/extent, using an lseek, read and write combination */ +static int +de_allocate(disc_de_t *de, char *filename) +{ + off_t size; + char block[DEFAULT_TARGET_BLOCK_LEN]; + + size = de_getsize(de); + if (de_lseek(de, size - sizeof(block), SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error seeking \"%s\"\n", filename); + return 0; + } + if (de_read(de, block, sizeof(block)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error reading \"%s\"", filename); + return 0; + } + if (de_write(de, block, sizeof(block)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error writing \"%s\"", filename); + return 0; + } + return 1; +} + +/* allocate space as desired */ +static int +allocate_space(disc_target_t *tp) +{ + uint32_t i; + + /* Don't perform check for writability in the target here, as the + following write() in de_allocate is non-destructive */ + switch(tp->de.type) { + case DE_EXTENT: + return de_allocate(&tp->de, tp->target); + case DE_DEVICE: + for (i = 0 ; i < tp->de.u.dp->c ; i++) { + if (!de_allocate(&tp->de.u.dp->xv[i], tp->target)) { + return 0; + } + } + return 1; + default: + break; + } + return 0; +} + +/* copy src to dst, of size `n' bytes, padding any extra with `pad' */ +static void +strpadcpy(uint8_t *dst, size_t dstlen, const char *src, const size_t srclen, char pad) +{ + size_t i; + + if (srclen < dstlen) { + (void) memcpy(dst, src, srclen); + for (i = srclen ; i < dstlen ; i++) { + dst[i] = pad; + } + } else { + (void) memcpy(dst, src, dstlen); + } +} + +/* handle REPORT LUNs SCSI command */ +static int +report_luns(uint64_t *data, int64_t luns) +{ + uint64_t lun; + int32_t off; + + for (lun = 0, off = 8 ; lun < (uint64_t)luns ; lun++, off += sizeof(lun)) { + data[(int)lun] = ISCSI_HTONLL(lun); + } + return off; +} + +/* handle persistent reserve in command */ +static int +persistent_reserve_in(uint8_t action, uint8_t *data) +{ + uint64_t key; + + switch(action) { + case PERSISTENT_RESERVE_IN_READ_KEYS: + key = 0; /* simulate "just powered on" */ + *((uint32_t *) (void *)data) = (uint32_t) ISCSI_HTONL((uint32_t) 0); + *((uint32_t *) (void *)data + 4) = (uint32_t) ISCSI_HTONL((uint32_t) sizeof(key)); /* length in bytes of list of keys */ + *((uint64_t *) (void *)data + 8) = (uint64_t) ISCSI_HTONLL(key); + return 8 + sizeof(key); + case PERSISTENT_RESERVE_IN_REPORT_CAPABILITIES: + (void) memset(data, 0x0, 8); + *((uint16_t *) (void *)data) = (uint16_t) ISCSI_HTONS((uint16_t) 8); /* length is fixed at 8 bytes */ + data[2] = PERSISTENT_RESERVE_IN_CRH; /* also SIP_C, ATP_C and PTPL_C here */ + data[3] = 0; /* also TMV and PTPL_A here */ + data[4] = 0; /* also WR_EX_AR, EX_AC_RD, WR_EX_RD, EX_AC, WR_EX here */ + data[5] = 0; /* also EX_AC_AR here */ + return 8; + default: + iscsi_trace_error(__FILE__, __LINE__, "persistent_reserve_in: action %x unrecognised\n", action); + return 0; + } +} + +/* initialise the device */ +/* ARGSUSED */ +int +device_init(globals_t *gp __attribute__((__unused__)), targv_t *tvp, disc_target_t *tp) +{ + int mode; + + ALLOC(iscsi_disk_t, disks.v, disks.size, disks.c, 10, 10, "device_init", ;); + disks.v[disks.c].tv = tvp; + if ((disks.v[disks.c].luns = defaults.luns) == 0) { + disks.v[disks.c].luns = CONFIG_DISK_NUM_LUNS_DFLT; + } + if ((disks.v[disks.c].blocklen = defaults.blocklen) == 0) { + disks.v[disks.c].blocklen = CONFIG_DISK_BLOCK_LEN_DFLT; + } + disks.v[disks.c].size = de_getsize(&tp->de); + disks.v[disks.c].blockc = disks.v[disks.c].size / disks.v[disks.c].blocklen; + NEWARRAY(uint8_t, disks.v[disks.c].buffer, MB(1), "buffer1", ;); + switch(disks.v[disks.c].blocklen) { + case 512: + case 1024: + case 2048: + case 4096: + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "Invalid block len %" PRIu64 ". Choose one of 512, 1024, 2048, 4096.\n", disks.v[disks.c].blocklen); + return -1; + } + disks.v[disks.c].type = ISCSI_FS; + printf("DISK: %" PRIu64 " logical unit%s (%" PRIu64 " blocks, %" PRIu64 " bytes/block), type %s\n", + disks.v[disks.c].luns, + (disks.v[disks.c].luns == 1) ? "" : "s", + disks.v[disks.c].blockc, disks.v[disks.c].blocklen, + (disks.v[disks.c].type == ISCSI_FS) ? "iscsi fs" : "iscsi fs mmap"); + printf("DISK: LUN 0: "); + (void) strlcpy(disks.v[disks.c].filename, disc_get_filename(&tp->de), sizeof(disks.v[disks.c].filename)); + mode = (tp->flags & TARGET_READONLY) ? O_RDONLY : (O_CREAT | O_RDWR); + if (de_open(&tp->de, mode, 0666) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\"\n", disks.v[disks.c].filename); + return -1; + } + if (!(tp->flags & TARGET_READONLY) && !allocate_space(tp)) { + iscsi_trace_error(__FILE__, __LINE__, "error allocating space for \"%s\"", tp->target); + return -1; + } + printf("%" PRIu64 " MB %sdisk storage for \"%s\"\n", + (de_getsize(&tp->de) / MB(1)), + (tp->flags & TARGET_READONLY) ? "readonly " : "", + tp->target); + return disks.c++; +} + +/* handle MODE_SENSE_6 and MODE_SENSE_10 commands */ +static int +mode_sense(const int bytes, target_cmd_t *cmd) +{ + iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd; + uint16_t len; + uint8_t *cp; + uint8_t *cdb = args->cdb; + size_t mode_data_len; + + switch(bytes) { + case 6: + cp = args->send_data; + len = ISCSI_MODE_SENSE_LEN; + mode_data_len = len + 3; + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "MODE_SENSE_6\n"); + (void) memset(cp, 0x0, mode_data_len); + + cp[0] = mode_data_len; + cp[1] = 0; + cp[2] = 0; + cp[3] = 8; /* block descriptor length */ + cp[10] = 2; /* density code and block length */ + + args->input = 1; + args->length = (unsigned)(len); + args->status = SCSI_SUCCESS; + return 1; + case 10: + cp = args->send_data; + len = ISCSI_MODE_SENSE_LEN; + mode_data_len = len + 3; + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "MODE_SENSE_10\n"); + (void) memset(cp, 0x0, mode_data_len); + if (cdb[4] == 0) { + /* zero length cdb means just return success */ + args->input = 1; + args->length = (unsigned)(mode_data_len); + args->status = SCSI_SUCCESS; + return 1; + } + if ((cdb[2] & PAGE_CONTROL_MASK) == PAGE_CONTROL_CHANGEABLE_VALUES) { + /* just send back a CHECK CONDITION */ + args->input = 1; + args->length = (unsigned)(len); + args->status = SCSI_CHECK_CONDITION; + cp[2] = SCSI_SKEY_ILLEGAL_REQUEST; + cp[12] = ASC_LUN_UNSUPPORTED; + cp[13] = ASCQ_LUN_UNSUPPORTED; + return 1; + } + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "PC %02x\n", cdb[2]); + + cp[0] = mode_data_len; + cp[1] = 0; + cp[2] = 0; + cp[3] = 8; /* block descriptor length */ + cp[10] = 2; /* density code and block length */ + + args->input = 1; + args->length = (unsigned)(len); + args->status = SCSI_SUCCESS; + return 1; + } + return 0; +} + + +int +device_command(target_session_t * sess, target_cmd_t * cmd) +{ + iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd; + uint32_t status; + uint32_t lba; + uint16_t len; + uint8_t *totsize; + uint8_t *totlen; + uint8_t *cp; + uint8_t *data; + uint8_t *cdb = args->cdb; + uint8_t lun = (uint8_t) (args->lun >> 32); + + totsize = &cdb[4]; + + /* + * added section to return no device equivalent for lun request + * beyond available lun + */ + if (lun >= disks.v[sess->d].luns) { + data = args->send_data; + (void) memset(data, 0x0, (size_t) *totsize); + /* + * data[0] = 0x7F; means no device + */ + data[0] = 0x1F; /* device type */ + data[0] |= 0x60;/* peripheral qualifier */ + args->input = 1; + args->length = cdb[4] + 1; + args->status = SCSI_SUCCESS; + return 0; + } + + lun = (uint8_t) sess->d; + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "SCSI op %#x (lun %d): \n", cdb[0], lun); + + switch (cdb[0]) { + + case TEST_UNIT_READY: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "TEST_UNIT_READY\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case INQUIRY: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "INQUIRY%s\n", (cdb[1] & INQUIRY_EVPD_BIT) ? " for Vital Product Data" : ""); + data = args->send_data; + args->status = SCSI_SUCCESS; + (void) memset(data, 0x0, (unsigned) *totsize); /* Clear allocated buffer */ + if (cdb[1] & INQUIRY_EVPD_BIT) { + totlen = &data[3]; + switch(cdb[2]) { + case INQUIRY_UNIT_SERIAL_NUMBER_VPD: + data[0] = DISK_PERIPHERAL_DEVICE; + data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD; + len = 16; + *totlen = len; + /* add target device's Unit Serial Number */ + /* section 7.6.10 of SPC-3 says that if there is no serial number, use spaces */ + strpadcpy(&data[4], (unsigned)len, " ", strlen(" "), ' '); + break; + case INQUIRY_DEVICE_IDENTIFICATION_VPD: + data[0] = DISK_PERIPHERAL_DEVICE; + data[1] = INQUIRY_DEVICE_IDENTIFICATION_VPD; + *totlen = 0; + cp = &data[4]; + /* add target device's IQN */ + cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) | INQUIRY_DEVICE_CODESET_UTF8; + cp[1] = (INQUIRY_DEVICE_PIV << 7) | (INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) | INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME; + len = (uint8_t) snprintf((char *)&cp[4], + (unsigned)(*totsize - (int)(cp - &data[4])), + "%s", + sess->globals->targetname); + cp[3] = len; + *totlen += len + 4; + cp += len + 4; + /* add target port's IQN + LUN */ + cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) | INQUIRY_DEVICE_CODESET_UTF8; + cp[1] = (INQUIRY_DEVICE_PIV << 7) | (INQUIRY_DEVICE_ASSOCIATION_TARGET_PORT << 4) | INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME; + len = (uint8_t) snprintf((char *)&cp[4], + (unsigned)(*totsize - (int)(cp - &data[4])), + "%s,t,%#x", + sess->globals->targetname, + lun); + cp[3] = len; + *totlen += len + 4; + cp += len + 4; + /* add target port's IQN + LUN extension */ + cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) | INQUIRY_DEVICE_CODESET_UTF8; + cp[1] = (INQUIRY_DEVICE_PIV << 7) | (INQUIRY_DEVICE_ASSOCIATION_LOGICAL_UNIT << 4) | INQUIRY_DEVICE_IDENTIFIER_SCSI_NAME; + if (disks.v[sess->d].uuid_string == NULL) { + uuid_create(&disks.v[sess->d].uuid, &status); + uuid_to_string(&disks.v[sess->d].uuid, &disks.v[sess->d].uuid_string, &status); + } + len = (uint8_t) snprintf((char *)&cp[4], + (unsigned)(*totsize - (int)(cp - &data[4])), + "%s,L,0x%8.8s%4.4s%4.4s", + sess->globals->targetname, + disks.v[sess->d].uuid_string, + &disks.v[sess->d].uuid_string[9], + &disks.v[sess->d].uuid_string[14]); + cp[3] = len; + *totlen += len + 4; + cp += len + 4; + /* add target's uuid as a T10 identifier */ + cp[0] = (INQUIRY_DEVICE_ISCSI_PROTOCOL << 4) | INQUIRY_DEVICE_CODESET_UTF8; + cp[1] = (INQUIRY_DEVICE_PIV << 7) | (INQUIRY_DEVICE_ASSOCIATION_TARGET_DEVICE << 4) | INQUIRY_IDENTIFIER_TYPE_T10; + strpadcpy(&cp[4], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' '); + len = 8; + len += (uint8_t) snprintf((char *)&cp[8 + 4], + (unsigned)(*totsize - (int)(cp - &data[4])), + "0x%8.8s%4.4s%4.4s", + disks.v[sess->d].uuid_string, + &disks.v[sess->d].uuid_string[9], + &disks.v[sess->d].uuid_string[14]); + cp[3] = len; + *totlen += len + 4; + args->length = *totlen + 6; + break; + case INQUIRY_SUPPORTED_VPD_PAGES: + data[0] = DISK_PERIPHERAL_DEVICE; + data[1] = INQUIRY_SUPPORTED_VPD_PAGES; + *totlen = 3; /* # of supported pages */ + data[4] = INQUIRY_SUPPORTED_VPD_PAGES; + data[5] = INQUIRY_DEVICE_IDENTIFICATION_VPD; + data[6] = EXTENDED_INQUIRY_DATA_VPD; + args->length = *totsize + 1; + break; + case EXTENDED_INQUIRY_DATA_VPD: + data[0] = DISK_PERIPHERAL_DEVICE; + data[1] = EXTENDED_INQUIRY_DATA_VPD; + data[3] = 0x3c; /* length is defined to be 60 */ + data[4] = 0; + data[5] = 0; + args->length = 64; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "Unsupported INQUIRY VPD page %x\n", cdb[2]); + args->status = SCSI_CHECK_CONDITION; + break; + } + } else { + char versionstr[8]; + + data[0] = DISK_PERIPHERAL_DEVICE; + data[2] = SCSI_VERSION_SPC; + data[4] = *totsize - 4; /* Additional length */ + data[7] |= (WIDE_BUS_32 | WIDE_BUS_16); + strpadcpy(&data[8], 8, ISCSI_VENDOR, strlen(ISCSI_VENDOR), ' '); + strpadcpy(&data[16], 16, ISCSI_PRODUCT, strlen(ISCSI_PRODUCT), ' '); + (void) snprintf(versionstr, sizeof(versionstr), "%d", ISCSI_VERSION); + strpadcpy(&data[32], 4, versionstr, strlen(versionstr), ' '); + args->length = cdb[4] + 1; + } + if (args->status == SCSI_SUCCESS) { + args->input = 1; + } + break; + + case MODE_SELECT_6: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "MODE_SELECT_6\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case STOP_START_UNIT: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "STOP_START_UNIT\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case READ_CAPACITY: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "READ_CAPACITY\n"); + data = args->send_data; + *((uint32_t *) (void *)data) = (uint32_t) ISCSI_HTONL((uint32_t) disks.v[sess->d].blockc - 1); /* Max LBA */ + *((uint32_t *) (void *)(data + 4)) = (uint32_t) ISCSI_HTONL((uint32_t) disks.v[sess->d].blocklen); /* Block len */ + args->input = 8; + args->length = 8; + args->status = SCSI_SUCCESS; + break; + + case WRITE_6: + lba = ISCSI_NTOHL(*((uint32_t *) (void *)cdb)) & 0x001fffff; + if ((len = *totsize) == 0) { + len = 256; + } + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "WRITE_6(lba %u, len %u blocks)\n", lba, len); + if (disk_write(sess, args, lun, lba, (unsigned) len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_write() failed\n"); + args->status = SCSI_CHECK_CONDITION; + } + args->length = 0; + break; + + + case READ_6: + lba = ISCSI_NTOHL(*((uint32_t *) (void *)cdb)) & 0x001fffff; + if ((len = *totsize) == 0) { + len = 256; + } + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "READ_6(lba %u, len %u blocks)\n", lba, len); + if (disk_read(sess, args, lba, len, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_read() failed\n"); + args->status = SCSI_CHECK_CONDITION; + } + args->input = 1; + break; + + case MODE_SENSE_6: + mode_sense(6, cmd); + break; + + case WRITE_10: + case WRITE_VERIFY: + cdb2lba(&lba, &len, cdb); + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "WRITE_10 | WRITE_VERIFY(lba %u, len %u blocks)\n", lba, len); + if (disk_write(sess, args, lun, lba, (unsigned) len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_write() failed\n"); + args->status = SCSI_CHECK_CONDITION; + } + args->length = 0; + break; + + case READ_10: + cdb2lba(&lba, &len, cdb); + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "READ_10(lba %u, len %u blocks)\n", lba, len); + if (disk_read(sess, args, lba, len, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_read() failed\n"); + args->status = SCSI_CHECK_CONDITION; + } + args->input = 1; + break; + + case VERIFY: + /* For now just set the status to success. */ + args->status = SCSI_SUCCESS; + break; + + case SYNC_CACHE: + cdb2lba(&lba, &len, cdb); + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "SYNC_CACHE (lba %u, len %u blocks)\n", lba, len); + if (de_fsync_range(&disks.v[sess->d].tv->v[lun].de, FDATASYNC, lba, (off_t)(len * disks.v[sess->d].blocklen)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_read() failed\n"); + args->status = SCSI_CHECK_CONDITION; + } else { + args->status = SCSI_SUCCESS; + args->length = 0; + } + break; + + case LOG_SENSE: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "LOG_SENSE\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case MODE_SENSE_10: + mode_sense(10, cmd); + break; + + case MODE_SELECT_10: + /* XXX still to do */ + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "MODE_SELECT_10\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case PERSISTENT_RESERVE_IN: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "PERSISTENT_RESERVE_IN\n"); + args->length = persistent_reserve_in((cdb[1] & PERSISTENT_RESERVE_IN_SERVICE_ACTION_MASK), args->send_data); + args->status = SCSI_SUCCESS; + break; + + case REPORT_LUNS: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "REPORT LUNS\n"); + args->length = report_luns((uint64_t *)(void *)&args->send_data[8], (off_t)disks.v[sess->d].luns); + *((uint32_t *) (void *)args->send_data) = ISCSI_HTONL(disks.v[sess->d].luns * sizeof(uint64_t)); + args->input = 8; + args->status = SCSI_SUCCESS; + break; + + case RESERVE_6: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "RESERVE_6\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case RELEASE_6: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "RELEASE_6\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case RESERVE_10: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "RESERVE_10\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + case RELEASE_10: + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "RELEASE_10\n"); + args->status = SCSI_SUCCESS; + args->length = 0; + break; + + default: + iscsi_trace_error(__FILE__, __LINE__, "UNKNOWN OPCODE %#x\n", cdb[0]); + /* to not cause confusion with some initiators */ + args->status = SCSI_CHECK_CONDITION; + break; + } + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "SCSI op %#x: done (status %#x)\n", cdb[0], args->status); + return 0; +} + +/*ARGSUSED*/ +int +device_shutdown(target_session_t *sess) +{ + return 1; +} + +/* + * Private Interface + */ + +static int +disk_write(target_session_t *sess, iscsi_scsi_cmd_args_t *args, uint8_t lun, uint32_t lba, uint32_t len) +{ + uint64_t byte_offset = lba * disks.v[sess->d].blocklen; + uint64_t num_bytes = len * disks.v[sess->d].blocklen; + uint8_t *ptr = NULL; + struct iovec sg; + + iscsi_trace(TRACE_SCSI_DATA, __FILE__, __LINE__, "writing %" PRIu64 " bytes from socket into device at byte offset %" PRIu64 "\n", num_bytes, byte_offset); + + /* Assign ptr for write data */ + + RETURN_GREATER("num_bytes (FIX ME)", (unsigned) num_bytes, MB(1), NO_CLEANUP, -1); + ptr = disks.v[sess->d].buffer; + + /* Have target do data transfer */ + + sg.iov_base = ptr; + sg.iov_len = (unsigned)num_bytes; + if (target_transfer_data(sess, args, &sg, 1) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_transfer_data() failed\n"); + } + /* Finish up write */ + if (de_lseek(&disks.v[sess->d].tv->v[lun].de, (off_t) byte_offset, SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "lseek() to offset %" PRIu64 " failed\n", byte_offset); + return -1; + } + if (!target_writable(&disks.v[sess->d].tv->v[lun])) { + iscsi_trace_error(__FILE__, __LINE__, "write() of %" PRIu64 " bytes failed at offset %" PRIu64 ", size %" PRIu64 "[READONLY TARGET]\n", num_bytes, byte_offset, de_getsize(&disks.v[sess->d].tv->v[lun].de)); + return -1; + } + if ((uint64_t)de_write(&disks.v[sess->d].tv->v[lun].de, ptr, (unsigned) num_bytes) != num_bytes) { + iscsi_trace_error(__FILE__, __LINE__, "write() of %" PRIu64 " bytes failed at offset %" PRIu64 ", size %" PRIu64 "\n", num_bytes, byte_offset, de_getsize(&disks.v[sess->d].tv->v[lun].de)); + return -1; + } + iscsi_trace(TRACE_SCSI_DATA, __FILE__, __LINE__, "wrote %" PRIu64 " bytes to device OK\n", num_bytes); + return 0; +} + +static int +disk_read(target_session_t * sess, iscsi_scsi_cmd_args_t * args, uint32_t lba, uint16_t len, uint8_t lun) +{ + uint64_t byte_offset = lba * disks.v[sess->d].blocklen; + uint64_t num_bytes = len * disks.v[sess->d].blocklen; + uint64_t extra = 0; + uint8_t *ptr = NULL; + uint32_t n; + int rc; + + RETURN_EQUAL("len", len, 0, NO_CLEANUP, -1); + if ((lba > (disks.v[sess->d].blockc - 1)) || ((lba + len) > disks.v[sess->d].blockc)) { + iscsi_trace_error(__FILE__, __LINE__, "attempt to read beyond end of media\n"); + iscsi_trace_error(__FILE__, __LINE__, "max_lba = %" PRIu64 ", requested lba = %u, len = %u\n", disks.v[sess->d].blockc - 1, lba, len); + return -1; + } + RETURN_GREATER("num_bytes (FIX ME)", (unsigned) num_bytes, MB(1), NO_CLEANUP, -1); + ptr = disks.v[sess->d].buffer; + n = 0; + do { + if (de_lseek(&disks.v[sess->d].tv->v[lun].de, (off_t)(n + byte_offset), SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "lseek() failed\n"); + return -1; + } + rc = de_read(&disks.v[sess->d].tv->v[lun].de, ptr + n, (size_t)(num_bytes - n)); + if (rc <= 0) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed: rc %d errno %d\n", rc, errno); + return -1; + } + n += rc; + if (n < num_bytes) { + iscsi_trace_error(__FILE__, __LINE__, "Got partial file read: %d bytes of %" PRIu64 "\n", rc, num_bytes - n + rc); + } + } while (n < num_bytes); + + ((struct iovec *) (void *)args->send_data)[0].iov_base = ptr + (unsigned) extra; + ((struct iovec *) (void *)args->send_data)[0].iov_len = (unsigned) num_bytes; + args->length = (unsigned) num_bytes; + args->send_sg_len = 1; + args->status = 0; + + return 0; +} diff --git a/external/bsd/iscsi/dist/src/driver.c b/external/bsd/iscsi/dist/src/driver.c new file mode 100644 index 000000000000..f04076d86321 --- /dev/null +++ b/external/bsd/iscsi/dist/src/driver.c @@ -0,0 +1,652 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Intel SCSI device driver for iSCSI + */ + +#ifdef __linux__ +#include +#include +#include +#include +#include +#endif + +#include "iscsiutil.h" +#include "util.c" +#include "driver.h" +#include "iscsi.h" +#include "iscsi.c" +#include "tests.h" +#include "tests.c" +#include "osd_ops.h" +#include "osd_ops.c" +#include "parameters.h" +#include "parameters.c" +#include "initiator.h" +#include "initiator.c" + +/* + * Version-specific include files + */ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) +#include +#else +struct proc_dir_entry iscsi_proc_dir = {PROC_SCSI_NOT_PRESENT, 5, "iscsi", S_IFDIR | S_IRUGO | S_IXUGO, 2}; +#endif + +#ifdef MODULE +Scsi_Host_Template driver_template = ISCSI; +#include "scsi_module.c" +#endif + +/* + * Globals + */ + +static initiator_cmd_t *g_cmd; +static iscsi_queue_t g_cmd_q; +static struct iovec **g_iov; +static iscsi_queue_t g_iovec_q; +static iscsi_driver_stats_t g_stats; + +/* + * Definitions + */ + +/* + * Starting with kernel 2.4.10, we define a license string. This source is under BSD License. + * Consult for details + */ + +MODULE_AUTHOR("Intel Corporation, "); +#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,10) +MODULE_LICENSE("Dual BSD/GPL"); /* This source is under BSD License. This is the closest ident that module.h provides */ +# endif + +/* + * Private + */ + +static int driver_init(void) { + int i; + + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "initializing iSCSI driver\n"); + if ((g_cmd=iscsi_malloc_atomic(sizeof(initiator_cmd_t)*CONFIG_INITIATOR_QUEUE_DEPTH))==NULL) { + iscsi_trace_error("iscsi_malloc_atomic() failed\n"); + return -1; + } + if ((g_iov=iscsi_malloc_atomic(sizeof(struct iovec*)*CONFIG_INITIATOR_QUEUE_DEPTH))==NULL) { + iscsi_trace_error("iscsi_malloc_atomic() failed\n"); + iscsi_free_atomic(g_cmd); + return -1; + } + for (i=0; imax_id = CONFIG_INITIATOR_NUM_TARGETS; + ptr->max_lun = CONFIG_DRIVER_MAX_LUNS; + ptr->max_cmd_len = 255; + iscsi_trace(TRACE_SCSI_DEBUG, "iSCSI host detected\n"); + spin_lock(&io_request_lock); + return 1; +} + +int iscsi_release(struct Scsi_Host *host) { + iscsi_trace(TRACE_SCSI_DEBUG, "releasing iSCSI host\n"); + driver_shutdown(); + iscsi_trace(TRACE_SCSI_DEBUG, "iSCSI host released\n"); + return 0; +} + +int iscsi_bios_param(Disk *disk, kdev_t dev, int *ip) { + ip[0] = 32; /* heads */ + ip[1] = 63; /* sectors */ + if((ip[2] = disk->capacity >> 11) > 1024) { /* cylinders, test for big disk */ + ip[0] = 255; /* heads */ + ip[1] = 63; /* sectors */ + ip[2] = disk->capacity / (255 * 63); /* cylinders */ + } + iscsi_trace(TRACE_SCSI_DEBUG, "%u sectors, H/S/C: %u/%u/%u\n", disk->capacity, ip[0], ip[1], ip[2]); + return 0; +} + +int iscsi_command(Scsi_Cmnd *SCpnt) { + iscsi_trace(TRACE_SCSI_DEBUG, "0x%p: op 0x%x, chan %i, target %i, lun %i, bufflen %i, sg %i\n", + SCpnt, SCpnt->cmnd[0], SCpnt->channel, SCpnt->target, SCpnt->lun, + SCpnt->request_bufflen, SCpnt->use_sg); + iscsi_trace_error("NOT IMPLEMENTED\n"); + return -1; +} + +int iscsi_done(void *ptr) { + initiator_cmd_t *cmd = (initiator_cmd_t *) ptr; + iscsi_scsi_cmd_args_t *scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr; + Scsi_Cmnd *SCpnt = (Scsi_Cmnd *) cmd->callback_arg; + unsigned long flags = 0; + if (SCpnt==0) { + return 0; + } + if (cmd->status==0) { + SCpnt->result = scsi_cmd->status; + } else { + SCpnt->result = -1; + } + iscsi_trace(TRACE_SCSI_DEBUG, "scsi_arg 0x%p SCpnt 0x%p op 0x%x done (result %i)\n", + scsi_cmd, SCpnt, SCpnt->cmnd[0], SCpnt->result); + if ((scsi_cmd->input)&&(scsi_cmd->output)) { + iscsi_trace_error("bidi xfers not implemented\n"); + return -1; + } else if (scsi_cmd->input) { + iscsi_spin_lock_irqsave(&g_stats.lock, &flags); + if ((g_stats.rx+SCpnt->request_bufflen)request_bufflen; + g_stats.rx_queued -= SCpnt->request_bufflen; + if (g_stats.num_rx_queued) g_stats.num_rx_queued--; + g_stats.num_rx++; + iscsi_spin_unlock_irqrestore(&g_stats.lock, &flags); + } else if (scsi_cmd->output) { + iscsi_spin_lock_irqsave(&g_stats.lock, &flags); + if ((g_stats.tx+SCpnt->request_bufflen)request_bufflen; + g_stats.tx_queued -= SCpnt->request_bufflen; + if (g_stats.num_tx_queued) g_stats.num_tx_queued--; + g_stats.num_tx++; + iscsi_spin_unlock_irqrestore(&g_stats.lock, &flags); + } + if (SCpnt->host_scribble) { + unsigned char *hs; + hs = SCpnt->host_scribble; + SCpnt->host_scribble = NULL; /* for abort */ + if (iscsi_queue_insert(&g_iovec_q, hs)!=0) { + iscsi_trace_error("iscsi_queue_insert() failed\n"); + return -1; + } + } + iscsi_free_atomic(scsi_cmd->ahs); + if (iscsi_queue_insert(&g_cmd_q, cmd)!=0) { + iscsi_trace_error("iscsi_queue_insert() failed\n"); + cmd->callback_arg = NULL; /* for abort */ + return -1; + } + cmd->callback_arg = NULL; /* for abort */ + if (SCpnt->result==0) { + SCpnt->scsi_done(SCpnt); + } else { + iscsi_trace_error("SCSI cmd 0x%x failed at iSCSI level (ignoring)\n", SCpnt->cmnd[0]); + } + return 0; +} + +int iscsi_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) { + initiator_cmd_t *cmd; + iscsi_scsi_cmd_args_t *scsi_cmd; + unsigned char *data; + unsigned length, trans_len; + int input, output; + unsigned long flags =0; + /* Tagged command queuing is handled from within this SCSI driver. */ + if ((SCpnt->device->tagged_supported)&&(SCpnt->device->tagged_queue)) { + SCpnt->tag = SCpnt->device->current_tag++; + } + + spin_unlock(&io_request_lock); + + iscsi_trace(TRACE_SCSI_DEBUG, "SCpnt %p: tid %i lun %i op 0x%x tag %u len %i sg %i buff 0x%p\n", + SCpnt, SCpnt->target, SCpnt->lun, SCpnt->cmnd[0], SCpnt->tag, SCpnt->request_bufflen, + SCpnt->use_sg, SCpnt->buffer); + + + /* Determine direction of data transfer */ + + trans_len = length = output = input = 0; + if ((SCpnt->cmnd[0]!=TEST_UNIT_READY)&&(SCpnt->request_bufflen)) { + if (SCpnt->sc_data_direction == SCSI_DATA_WRITE) { + output = 1; input = 0; + length = trans_len = SCpnt->request_bufflen; + iscsi_spin_lock_irqsave(&g_stats.lock, &flags); + g_stats.num_tx_queued++; + g_stats.tx_queued += trans_len; + iscsi_spin_unlock_irqrestore(&g_stats.lock, &flags); + } else if (SCpnt->sc_data_direction == SCSI_DATA_READ) { + length = output = 0; input = 1; + trans_len = SCpnt->request_bufflen; + iscsi_spin_lock_irqsave(&g_stats.lock, &flags); + g_stats.num_rx_queued++; + g_stats.rx_queued += trans_len; + iscsi_spin_unlock_irqrestore(&g_stats.lock, &flags); + } + } + + /* Convert scatterlist to iovec */ + + if (SCpnt->use_sg) { + struct scatterlist *sg = (struct scatterlist *) SCpnt->buffer; + struct iovec *iov; + int i; + + iov = iscsi_queue_remove(&g_iovec_q); + if (iov == NULL) { + iscsi_trace_error("iscsi_queue_remove() failed\n"); + spin_lock(&io_request_lock); + return -1; + } + for (i=0; iuse_sg; i++) { + iov[i].iov_base = sg[i].address; + iov[i].iov_len = sg[i].length; + } + data = SCpnt->host_scribble = (unsigned char *)iov; + } else { + data = SCpnt->buffer; + SCpnt->host_scribble = NULL; + } + + /* Get free cmd structure */ + + if ((cmd=iscsi_queue_remove(&g_cmd_q))==NULL) { + iscsi_trace_error("iscsi_queue_remove() failed\n"); + spin_lock(&io_request_lock); + return -1; + } + scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr; + memset(scsi_cmd, 0, sizeof(*scsi_cmd)); + scsi_cmd->send_data = output?data:0; + scsi_cmd->send_sg_len = output?SCpnt->use_sg:0; + scsi_cmd->recv_data = input?data:NULL; + scsi_cmd->recv_sg_len = input?SCpnt->use_sg:0; + scsi_cmd->input = input; + scsi_cmd->output = output; + scsi_cmd->length = length; + scsi_cmd->lun = SCpnt->lun; + scsi_cmd->lun = scsi_cmd->lun << 32; + scsi_cmd->trans_len = trans_len; + scsi_cmd->cdb = SCpnt->cmnd; + + /* AHS for CDBs larget than 16 bytes */ + + if (SCpnt->cmd_len>16) { + iscsi_trace(TRACE_ISCSI_DEBUG, "creating AHS for extended CDB (%i bytes)\n", SCpnt->cmd_len); + if ((scsi_cmd->ahs=iscsi_malloc_atomic(SCpnt->cmd_len-16))==NULL) { + iscsi_trace_error("iscsi_malloc_atomic() failed\n"); + spin_lock(&io_request_lock); + return -1; + } + memset(scsi_cmd->ahs, 0, 4); + *((uint16_t *)scsi_cmd->ahs) = HTONS(SCpnt->cmd_len-15); /* AHS length */ + scsi_cmd->ahs[2] = 0x01; /* Type */ + memcpy(scsi_cmd->ahs+4, SCpnt->cmnd+16, SCpnt->cmd_len-16); /* Copy in remaining CDB */ + scsi_cmd->ahs_len = SCpnt->cmd_len-16; + } + + SCpnt->scsi_done = done; /* The midlayer's callback called in iscsi_done */ + SCpnt->result = 0x02; /* Default to a check condition */ + cmd->callback = iscsi_done; /* This driver's callback called by initiator library */ + cmd->callback_arg = SCpnt; + cmd->isid = SCpnt->target; + if (initiator_enqueue(cmd)!=0) { + iscsi_trace_error("initiator_enqueue() failed\n"); + if (SCpnt->cmd_len>16) iscsi_free_atomic(scsi_cmd->ahs); + spin_lock(&io_request_lock); + return -1; + } + spin_lock(&io_request_lock); + return 0; +} + +int iscsi_proc_info (char *buffer, char **start, off_t offset, int length, int hostno, int writing) { + unsigned char *info = NULL; + uint32_t infolen = 8192; + int len = 0; + + iscsi_trace(TRACE_SCSI_DEBUG, "buffer = 0x%p, offset %u, length = %i, hostno %i, writing %i\n", + buffer, (unsigned) offset, length, hostno, writing); + + /* writing resets counters */ + + if (writing) { + iscsi_spin_lock(&g_stats.lock); + g_stats.num_tx = g_stats.num_tx_queued = 0; + g_stats.num_rx = g_stats.num_rx_queued = 0; + g_stats.tx_queued = g_stats.tx = g_stats.tx_overflow = g_stats.tx_error = 0; + g_stats.rx_queued = g_stats.rx = g_stats.rx_overflow = g_stats.rx_error = 0; + g_stats.aborts_success = g_stats.aborts_failed = 0; + g_stats.device_resets = g_stats.bus_resets = g_stats.host_resets = 0; + iscsi_spin_unlock(&g_stats.lock); + return 0; + } else { + if ((info=iscsi_malloc_atomic(infolen))==NULL) { + iscsi_trace_error("iscsi_malloc_atomic() failed\n"); + return -1; + } + len += snprintf(info, infolen, "%s\n\n", driver_template.name); + len += snprintf(&info[len], infolen - len, "Write file to reset counters (e.g., \"echo reset > /proc/scsi/iscsi/2\").\n\n"); + len += snprintf(&info[len], infolen - len, "--------------------\n"); + len += snprintf(&info[len], infolen - len, "Driver Configuration\n"); + + len += snprintf(&info[len], infolen - len, "--------------------\n\n"); + len += snprintf(&info[len], infolen - len, " CONFIG_INITIATOR_NUM_TARGETS: %u\n", CONFIG_INITIATOR_NUM_TARGETS); + len += snprintf(&info[len], infolen - len, " CONFIG_INITIATOR_QUEUE_DEPTH: %u\n\n", CONFIG_INITIATOR_QUEUE_DEPTH); + len += snprintf(&info[len], infolen - len, "---------------\n"); + len += snprintf(&info[len], infolen - len, "SCSI Statistics\n"); + len += snprintf(&info[len], infolen - len, "---------------\n\n"); + len += snprintf(&info[len], infolen - len, " Tx:\n"); + len += snprintf(&info[len], infolen - len, " queued: %u\n", g_stats.num_tx_queued); + len += snprintf(&info[len], infolen - len, " completed: %u\n", g_stats.num_tx); + len += snprintf(&info[len], infolen - len, " avg size: %u\n", g_stats.num_tx?(g_stats.tx/g_stats.num_tx):0); + len += snprintf(&info[len], infolen - len, " total bytes: %u MB\n", g_stats.tx/1048576 + g_stats.tx_overflow*4096); + len += snprintf(&info[len], infolen - len, " total overflow: %u\n", g_stats.tx_overflow); + len += snprintf(&info[len], infolen - len, " Rx:\n"); + len += snprintf(&info[len], infolen - len, " queued: %u\n", g_stats.num_rx_queued); + len += snprintf(&info[len], infolen - len, " completed: %u\n", g_stats.num_rx); + len += snprintf(&info[len], infolen - len, " avg size: %u\n", g_stats.num_rx?(g_stats.rx/g_stats.num_rx):0); + len += snprintf(&info[len], infolen - len, " total bytes: %u MB\n", g_stats.rx/1048576 + g_stats.rx_overflow*4096); + len += snprintf(&info[len], infolen - len, " total overflow: %u\n", g_stats.rx_overflow); + len += snprintf(&info[len], infolen - len, " Errors:\n"); + len += snprintf(&info[len], infolen - len, " aborts: %u\n", g_stats.aborts_success); + /* len += snprintf(&info[len], infolen - len, " failed aborts: %u\n", g_stats.aborts_failed); */ + len += snprintf(&info[len], infolen - len, " device resets: %u\n", g_stats.device_resets); + len += snprintf(&info[len], infolen - len, " bus resets: %u\n", g_stats.bus_resets); + len += snprintf(&info[len], infolen - len, " host resets: %u\n", g_stats.host_resets); + len += snprintf(&info[len], infolen - len, " Tx error bytes: %u\n", g_stats.tx_error); + len += snprintf(&info[len], infolen - len, " Rx error bytes: %u\n\n", g_stats.rx_error); + len += snprintf(&info[len], infolen - len, "--------------------\n"); + len += snprintf(&info[len], infolen - len, "iSCSI Initiator Info\n"); + len += snprintf(&info[len], infolen - len, "--------------------\n\n"); + + if ((len += initiator_info(&info[len], infolen, len))==-1) { + iscsi_trace_error("initiator_info() failed\n"); + if (info != NULL) iscsi_free_atomic(info); + return -1; + } + if (offset>len-1) { + len = 0; + } else if (offset+length>len-1) { + len -= offset; + } else { + len = length; + } + *start = buffer; + memcpy(buffer, info+offset, len); + if (info != NULL) iscsi_free_atomic(info); + return len; + } +} + +int iscsi_ioctl (Scsi_Device *dev, int cmd, void *argp) { + int i; + int lun = 0; + + /* Run tests for each target */ + + for (i=0; inext) { + if (device->host != host) { + iscsi_trace_error("got device for different host\n"); + continue; + } + if (device->tagged_supported) { + iscsi_trace(TRACE_SCSI_DEBUG, "target %i lun %i supports TCQ\n", device->id, device->lun); + device->tagged_queue = 1; + device->current_tag = 0; + device->queue_depth = CONFIG_INITIATOR_QUEUE_DEPTH; + iscsi_trace(TRACE_SCSI_DEBUG, "device queue depth set to %i\n", device->queue_depth); + } else { + iscsi_trace(TRACE_SCSI_DEBUG, "target %i lun %i does NOT support TCQ\n", device->id, device->lun); + device->queue_depth = 1; + } + } +} + +/* + * Error Handling Routines + */ + + +int iscsi_abort_handler (Scsi_Cmnd *SCpnt) { + iscsi_scsi_cmd_args_t *scsi_cmd; + initiator_session_t *sess; + int i; + unsigned long flags; + + spin_unlock_irq(&io_request_lock); + iscsi_trace_error("aborting SCSI cmd 0x%p (op 0x%x, tid %i, lun %i)\n", + SCpnt, SCpnt->cmnd[0], SCpnt->target, SCpnt->lun); + + + for (i=0; iinput)&&(scsi_cmd->output)) { + iscsi_trace_error("bidi xfers not implemented\n"); + spin_lock_irq(&io_request_lock); + return FAILED; + } else if (scsi_cmd->input) { + iscsi_spin_lock_irqsave(&g_stats.lock,&flags); + g_stats.rx_error += SCpnt->request_bufflen; + g_stats.rx_queued -= SCpnt->request_bufflen; + iscsi_spin_unlock_irqrestore(&g_stats.lock, &flags); + } else if (scsi_cmd->output) { + iscsi_spin_lock_irqsave(&g_stats.lock, &flags); + g_stats.tx_error += SCpnt->request_bufflen; + g_stats.tx_queued -= SCpnt->request_bufflen; + iscsi_spin_unlock_irqrestore(&g_stats.lock, &flags); + } + break; + } + } + + /* Destroy session */ + + if (g_target[SCpnt->target].has_session) { + sess = g_target[SCpnt->target].sess; + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + if (in_interrupt()) { + iscsi_trace_error("aborting within interrupt (killing Tx and Rx threads)\n"); +#endif + iscsi_trace_error("killing Tx and Rx threads\n"); + kill_proc(sess->rx_worker.pid, SIGKILL, 1); + kill_proc(sess->tx_worker.pid, SIGKILL, 1); + sess->tx_worker.state = 0; + sess->rx_worker.state = 0; +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,4,0) + } else { + iscsi_trace_error("aborting outside interrupt (gracefully ending Tx and Rx)\n"); + } +#endif + + iscsi_trace(TRACE_ISCSI_DEBUG, "destroying session\n"); + if (session_destroy_i(sess)!=0) { + iscsi_trace_error("session_destroy() failed\n"); + g_stats.aborts_failed++; + spin_lock_irq(&io_request_lock); + return FAILED; + } + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, "no session\n"); + } + + g_stats.aborts_success++; + + iscsi_trace_error("successfully aborted SCSI cmd 0x%p (op 0x%x, tid %i, lun %i)\n", + SCpnt, SCpnt->cmnd[0], SCpnt->target, SCpnt->lun); + spin_lock_irq(&io_request_lock); + return SUCCESS; +} + +int iscsi_device_reset_handler (Scsi_Cmnd *SCpnt) { + iscsi_trace_error("***********************\n"); + iscsi_trace_error("*** DEVICE %i RESET ***\n", SCpnt->target); + iscsi_trace_error("***********************\n"); + g_stats.device_resets++; + return SUCCESS; +} + +int iscsi_bus_reset_handler (Scsi_Cmnd *SCpnt) { + iscsi_trace_error("********************\n"); + iscsi_trace_error("*** BUS %i RESET ***\n", SCpnt->target); + iscsi_trace_error("********************\n"); + g_stats.bus_resets++; + return SUCCESS; +} + +int iscsi_host_reset_handler(Scsi_Cmnd *SCpnt) { + iscsi_trace_error("*********************\n"); + iscsi_trace_error("*** HOST RESET %i ***\n", SCpnt->target); + iscsi_trace_error("*********************\n"); + g_stats.host_resets++; + return SUCCESS; +} diff --git a/external/bsd/iscsi/dist/src/initiator.c b/external/bsd/iscsi/dist/src/initiator.c new file mode 100644 index 000000000000..1895672ad632 --- /dev/null +++ b/external/bsd/iscsi/dist/src/initiator.c @@ -0,0 +1,3246 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_NETINET_TCP_H +#include +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include "iscsi.h" +#include "initiator.h" + +static initiator_target_t g_target[CONFIG_INITIATOR_NUM_TARGETS]; + +/* + * Globals + */ +static uint32_t g_tag; +static iscsi_spin_t g_tag_spin; +static hash_t g_tag_hash; +static iscsi_worker_t g_enqueue_worker; +static iscsi_queue_t g_enqueue_q; +static iscsi_queue_t g_session_q; +static int g_initiator_state; +static char *gfilename; + +/* Testing of initiator_abort */ + +static initiator_cmd_t *g_cmd = NULL; + +/* + * Enqueue worker functions. The enqueue worker is responsible for enqueing + * all iSCSI commands to one of the Tx workers. It is also the thread + * responsible for initializing sessions, discovering targets and getting + * each session into full feature phase. + */ + +static int enqueue_worker_proc(void *); +static int login_phase_i(initiator_session_t *, char *, int); +static int logout_phase_i(initiator_session_t *); + +/* + * Tx functions. initiator_cmd_t pointers are enqueued to the Tx worker + * for a given session by the enqueue worker. The Tx worker will send out these + * commands and wait for the Rx worker to process the response. The pointer is + * inserted into the hashtable g_tag_hash, keyed by the initiator tag of the iSCSI + * commands. + */ + +static int tx_worker_proc_i(void *); +static int text_command_i(initiator_cmd_t *); +static int login_command_i(initiator_cmd_t *); +static int logout_command_i(initiator_cmd_t *); +static int scsi_command_i(initiator_cmd_t *); +static int nop_out_i(initiator_cmd_t *); + + +/* + * Rx functions. Upon receipt of an incoming PDU, the Rx worker will first + * extract the tag (if it exists for the PDU) and then the associated + * initiator_cmd_t pointer stored in the hash table. One of Rx functions + * will be called to processs the PDU. The Rx worker will invoke the callback + * function associated with the command once the command has been retired. + */ + +static int rx_worker_proc_i(void *); +static int login_response_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int text_response_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int logout_response_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int scsi_response_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int scsi_read_data_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int scsi_r2t_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int nop_in_i(initiator_session_t *, initiator_cmd_t *, uint8_t *); +static int reject_i(initiator_session_t *, uint8_t *); +static int async_msg_i(initiator_session_t *, uint8_t *); + + +/* + * Misc. Prototypes + */ + + +static int session_init_i(initiator_session_t **, uint64_t ); +static int session_destroy_i(initiator_session_t *); +static int wait_callback_i(void *); +static int discovery_phase(int, strv_t *); + + +/* + * Private Functions + */ + +#if 0 +static void +dump_session(initiator_session_t * sess) +{ + iscsi_parameter_value_t *vp; + iscsi_parameter_t *ip; + + for (ip = sess->params ; ip ; ip = ip->next) { + printf("Key: %s Type: %d\n",ip->key,ip->type); + for (vp = ip->value_l ; vp ; vp = vp->next) { + printf("Value: %s\n",vp->value); + } + } +} +#endif +/* This function reads the target IP and target name information */ +/* from the input configuration file, and populates the */ +/* g_target data structure fields. */ +static int +get_target_config(const char *hostname, int port) +{ + int i; + + for (i = 0 ; i < CONFIG_INITIATOR_NUM_TARGETS ; i++) { + (void) strlcpy(g_target[i].name, hostname, sizeof(g_target[i].name)); + g_target[i].port = port; + } + return 0; +} + +static int +session_init_i(initiator_session_t ** sess, uint64_t isid) +{ + initiator_session_t *s; + iscsi_parameter_t **l; + char *user; + int auth_type; + int mutual_auth; + int one = 1; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initializing session %llu\n", isid); + + /* Get free session */ + if ((*sess = iscsi_queue_remove(&g_session_q)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_remove() failed\n"); + return -1; + } + s = *sess; + user = NULL; + if (s->sess_params.cred.user) { + user = s->sess_params.cred.user; + } + auth_type = s->sess_params.auth_type; + mutual_auth = s->sess_params.mutual_auth; + (void) memset(s, 0x0, sizeof(*s)); + s->state = INITIATOR_SESSION_STATE_INITIALIZING; + s->isid = s->tx_worker.id = s->rx_worker.id = isid; + s->cmds = NULL; + s->sess_params.cred.user = user; + s->sess_params.auth_type = auth_type; + s->sess_params.mutual_auth = mutual_auth; + + iscsi_spin_init(&s->cmds_spin); + g_target[isid].has_session = 1; + + /* Create socket */ + if (!iscsi_sock_create(&s->sock)) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_create() failed\n"); + return -1; + } + if (!iscsi_sock_setsockopt(&s->sock, SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_setsockopt() failed\n"); + return -1; + } + + /* Initialize wait queues */ + + ISCSI_MUTEX_INIT(&s->tx_worker.work_mutex, return -1); + ISCSI_COND_INIT(&s->tx_worker.work_cond, return -1); + ISCSI_MUTEX_INIT(&s->tx_worker.exit_mutex, return -1); + ISCSI_COND_INIT(&s->tx_worker.exit_cond, return -1); + ISCSI_MUTEX_INIT(&s->rx_worker.work_mutex, return -1); + ISCSI_COND_INIT(&s->rx_worker.work_cond, return -1); + ISCSI_MUTEX_INIT(&s->rx_worker.exit_mutex, return -1); + ISCSI_COND_INIT(&s->rx_worker.exit_cond, return -1); + + /* Build parameter list */ + + /* + * ISCSI_PARAM_TYPE_LIST format: + * ISCSI_PARAM_TYPE_BINARY format: + * ISCSI_PARAM_TYPE_NUMERICAL format: + * ISCSI_PARAM_TYPE_DECLARATIVE format: "" + */ + + s->params = NULL; + l = &(s->params); + /* CHAP Support Parameters */ + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthMethod", "None", "CHAP,None", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "CHAP_A", "None", "5", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_N", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_R", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_I", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_C", "", "", return -1); + /* CHAP Support Parameters */ + + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "HeaderDigest", "None", "None", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "DataDigest", "None", "None", return -1); + + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxConnections", "1", "1", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SendTargets", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARE_MULTI, "TargetName", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorName", "iqn.1994-04.org.NetBSD:iscsi-initiator", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAlias", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorAlias", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARE_MULTI, "TargetAddress", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "InitialR2T", "Yes", "Yes,No", return -1); + + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "ImmediateData", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxRecvDataSegmentLength", "8192", "16777215", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxBurstLength", "262144", "16777215", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "FirstBurstLength", "65536", "16777215", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetPortalGroupTag", "1", "65535", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Wait", "2", "2", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Retain", "20", "20", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxOutstandingR2T", "1", "1", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataPDUInOrder", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataSequenceInOrder", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "ErrorRecoveryLevel", "0", "0", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SessionType", "Normal", "Normal,Discovery", return -1); + + /* Start Tx worker */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "starting Tx worker %llu\n", isid); + if (iscsi_queue_init(&s->tx_queue, CONFIG_INITIATOR_QUEUE_DEPTH) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + return -1; + } + ISCSI_LOCK(&s->tx_worker.exit_mutex, return -1); + if (iscsi_thread_create(&s->tx_worker.thread, (void *) tx_worker_proc_i, &s->tx_worker) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_threads_create() failed\n"); + return -1; + } + ISCSI_WAIT(&s->tx_worker.exit_cond, &s->tx_worker.exit_mutex, return -1); + ISCSI_UNLOCK(&s->tx_worker.exit_mutex, return -1); + if (s->state == INITIATOR_SESSION_STATE_DESTROYING) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %llu is being destroyed, exiting\n", isid); + return -1; + } + if (s->tx_worker.state & ISCSI_WORKER_STATE_ERROR) { + iscsi_trace_error(__FILE__, __LINE__, "Tx worker %llu started with an error\n", isid); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "got signal from Tx worker\n"); + s->state = INITIATOR_SESSION_STATE_INITIALIZED; + + return 0; +} + +static int +session_destroy_i(initiator_session_t * sess) +{ + initiator_cmd_t *ptr; + uint64_t isid = sess->isid; + + if (sess == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "session pointer is NULL\n"); + return -1; + } + if (g_target[sess->isid].has_session == 0) { + iscsi_trace_error(__FILE__, __LINE__, "g_target[%llu].has_session==0??\n", sess->isid); + return -1; + } + sess->state = INITIATOR_SESSION_STATE_DESTROYING; + + /* Abort all outstanding commands */ + + for (ptr = sess->cmds; ptr != NULL; ptr = ptr->next) { + if (initiator_abort(ptr) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_abort() failed\n"); + return -1; + } + } + + if (sess->tx_worker.state & ISCSI_WORKER_STATE_STARTED) { + if (sess->tx_worker.state & ISCSI_WORKER_STATE_EXITING) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Tx worker %llu already signalled for exit\n", sess->isid); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "signaling Tx worker %llu into exiting state\n", sess->isid); + ISCSI_LOCK(&sess->tx_worker.work_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "signaling socket shutdown to Tx worker %llu\n", sess->isid); + if (iscsi_sock_shutdown(sess->sock, 1) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_shutdown() failed\n"); + } + ISCSI_SIGNAL(&sess->tx_worker.work_cond, return -1); + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, return -1); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Checking exit condition of Tx worker\n"); + while ((sess->tx_worker.state & ISCSI_WORKER_STATE_EXITING) != ISCSI_WORKER_STATE_EXITING) { + ISCSI_SPIN; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Tx worker %llu has exited\n", sess->isid); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Tx worker was not started. Nothing to signal\n"); + } + + /* Destroy Tx state */ + while ((ptr = iscsi_queue_remove(&sess->tx_queue)) != NULL) { + ptr->status = -1; + if (ptr->callback && ((*ptr->callback)(ptr) != 0)) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + } + } + iscsi_queue_destroy(&sess->tx_queue); + + if (sess->rx_worker.state & ISCSI_WORKER_STATE_STARTED) { + if (sess->rx_worker.state & ISCSI_WORKER_STATE_EXITING) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Rx worker %llu already signalled for exit\n", sess->isid); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "signaling Rx worker %llu into exiting state\n", sess->isid); + if (iscsi_sock_shutdown(sess->sock, 0) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_shutdown() failed\n"); + } + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Checking exit condition of Rx worker\n"); + while ((sess->rx_worker.state & ISCSI_WORKER_STATE_EXITING) != ISCSI_WORKER_STATE_EXITING) { + ISCSI_SPIN; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Rx worker %llu has exited\n", sess->isid); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Rx worker was not started. Nothing to signal\n"); + } + + /* Close socket */ + + if (iscsi_sock_close(sess->sock) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_close() failed\n"); + return -1; + } + /* Destroy wait queues */ + + ISCSI_MUTEX_DESTROY(&sess->tx_worker.work_mutex, return -1); + ISCSI_COND_DESTROY(&sess->tx_worker.work_cond, return -1); + ISCSI_MUTEX_DESTROY(&sess->tx_worker.exit_mutex, return -1); + ISCSI_COND_DESTROY(&sess->tx_worker.exit_cond, return -1); + ISCSI_MUTEX_DESTROY(&sess->rx_worker.work_mutex, return -1); + ISCSI_COND_DESTROY(&sess->rx_worker.work_cond, return -1); + ISCSI_MUTEX_DESTROY(&sess->rx_worker.exit_mutex, return -1); + ISCSI_COND_DESTROY(&sess->rx_worker.exit_cond, return -1); + + /* Destroy param list */ + + PARAM_LIST_DESTROY(sess->params, return -1); + + /* Enqueue session to free list */ + if (iscsi_queue_insert(&g_session_q, sess) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %p destroyed and requeued\n", sess); + + g_target[isid].has_session = 0; + + return 0; +} + +#define IS_DISCOVERY 1 +#define IS_SECURITY 1 + +enum { + SESS_TYPE_DISCOVERY = 1, + SESS_TYPE_NORMAL = 2, + SESS_TYPE_NONE = 3 +}; + +static int +params_out(initiator_session_t * sess, char *text, int *len, int textsize, int sess_type, int security) +{ + if (security == IS_SECURITY) { + PARAM_TEXT_ADD(sess->params, "InitiatorName", "iqn.1994-04.org.NetBSD.iscsi-initiator:agc", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "InitiatorAlias", "NetBSD", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "AuthMethod", "CHAP,None", text, len, textsize, 1, return -1); + } else { + PARAM_TEXT_ADD(sess->params, "HeaderDigest", "None", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "DataDigest", "None", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "MaxConnections", "1", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "InitialR2T", "Yes", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "ImmediateData", "Yes", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "MaxRecvDataSegmentLength", "8192", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "FirstBurstLength", "65536", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "MaxBurstLength", "262144", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "DefaultTime2Wait", "2", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "DefaultTime2Retain", "20", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "MaxOutstandingR2T", "1", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "DataPDUInOrder", "No", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "DataSequenceInOrder", "No", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "ErrorRecoveryLevel", "0", text, len, textsize, 1, return -1); + } + switch (sess_type) { + case SESS_TYPE_DISCOVERY: + PARAM_TEXT_ADD(sess->params, "SessionType", "Discovery", text, len, textsize, 1, return -1); + break; + case SESS_TYPE_NORMAL: + PARAM_TEXT_ADD(sess->params, "SessionType", "Normal", text, len, textsize, 1, return -1); + PARAM_TEXT_ADD(sess->params, "TargetName", g_target[sess->isid].TargetName, text, len, textsize, 1, return -1); + break; + default: + break; + } + PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred, text, *len, NULL, NULL, 0, 1, return -1); + return 0; +} + +static int +full_feature_negotiation_phase_i(initiator_session_t * sess, char *text, int text_len) +{ + initiator_cmd_t *cmd = NULL; + iscsi_text_cmd_args_t *text_cmd = NULL; + initiator_wait_t wait; + + /* Allocate command pointers */ + + if ((cmd = iscsi_malloc_atomic(sizeof(initiator_cmd_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + (void) memset(cmd, 0x0, sizeof(*cmd)); + if ((text_cmd = iscsi_malloc_atomic(sizeof(iscsi_text_cmd_args_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (cmd != NULL) + iscsi_free_atomic(cmd); /* initiator command */ + return -1; + } +#define FFN_ERROR {if (cmd != NULL) iscsi_free_atomic(cmd); if (text_cmd != NULL) iscsi_free_atomic(text_cmd); return -1;} + (void) memset(text_cmd, 0x0, sizeof(*text_cmd)); + + /* + * Note that , and are updated + * by text_response_i when we receive offers from + * the target. + */ + text_cmd->text = text; + text_cmd->length = text_len; + + do { + + /* Build text command */ + + text_cmd->final = 1; + text_cmd->cont = 0; + ISCSI_SET_TAG(&text_cmd->tag); + text_cmd->transfer_tag = 0xffffffff; + + /* Build wait for callback */ + + ISCSI_MUTEX_INIT(&wait.mutex, FFN_ERROR); + ISCSI_COND_INIT(&wait.cond, FFN_ERROR); + + /* Build initiator command */ + + cmd->type = ISCSI_TEXT_CMD; + cmd->ptr = text_cmd; + cmd->callback = wait_callback_i; + cmd->callback_arg = &wait; + cmd->isid = sess->isid; + + /* Enqueue initiator command to Tx worker */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueing text command to tx worker %llu\n", sess->isid); + ISCSI_LOCK(&wait.mutex, FFN_ERROR); + ISCSI_LOCK(&sess->tx_worker.work_mutex, FFN_ERROR); + if (iscsi_queue_insert(&sess->tx_queue, cmd) == -1) { + ISCSI_UNLOCK(&wait.mutex, ); + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + FFN_ERROR; + } + ISCSI_SIGNAL(&sess->tx_worker.work_cond, FFN_ERROR); + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, FFN_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueued text command ok\n"); + + /* Wait for callback */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "waiting on text callback\n"); + ISCSI_WAIT(&wait.cond, &wait.mutex, FFN_ERROR); + ISCSI_UNLOCK(&wait.mutex, FFN_ERROR); + ISCSI_COND_DESTROY(&wait.cond, FFN_ERROR); + ISCSI_MUTEX_DESTROY(&wait.mutex, FFN_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "received text callback ok\n"); + + /* + * See if we're done. text_response_i() overwrites + * text_cmd->final + */ + /* with the final bit in the text response from the target. */ + + if (!text_cmd->final) { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "more negotiation needed (sending %d bytes response parameters)\n", + text_cmd->length); + } + } while (!text_cmd->final); + + /* Free command pointers */ + + iscsi_free_atomic(cmd->ptr); /* text command */ + iscsi_free_atomic(cmd); /* initiator command */ + + return 0; +} + +#define DISCOVERY_PHASE_TEXT_LEN 1024 +#define DP_CLEANUP {if (text != NULL) iscsi_free_atomic(text);} +#define DP_ERROR {DP_CLEANUP; return -1;} + +int +initiator_set_target_name(int target, char *target_name) +{ + (void) strlcpy(g_target[target].iqnwanted, target_name, sizeof(g_target[target].iqnwanted)); + (void) strlcpy(g_target[target].TargetName, target_name, sizeof(g_target[target].TargetName)); + return 0; +} + + +int +initiator_get_targets(int target, strv_t *svp) +{ + initiator_session_t *sess = g_target[target].sess; + iscsi_parameter_value_t *vp; + iscsi_parameter_t *ip; + char *text = NULL; + int text_len = 0; + int i; + + if ((text = iscsi_malloc_atomic(DISCOVERY_PHASE_TEXT_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + + text_len = 0; + text[0] = 0x0; + + PARAM_TEXT_ADD(sess->params, "SendTargets", "all", text, &text_len, DISCOVERY_PHASE_TEXT_LEN, 1, DP_ERROR); + PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred, text, text_len, NULL, NULL, DISCOVERY_PHASE_TEXT_LEN, 1, DP_ERROR); + if (full_feature_negotiation_phase_i(sess, text, text_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "full_feature_negotiation_phase_i() failed\n"); + DP_ERROR; + } + i=0; + for (ip = sess->params ; ip ; ip = ip->next) { + if (strcmp(ip->key, "TargetName") == 0) { + for (vp = ip->value_l ; vp ; vp = vp->next) { + ALLOC(char *, svp->v, svp->size, svp->c, 10, 10, "igt", return -1); + svp->v[svp->c++] = strdup(vp->value); + ALLOC(char *, svp->v, svp->size, svp->c, 10, 10, "igt2", return -1); + svp->v[svp->c++] = strdup(param_val(sess->params, "TargetAddress")); + } + } + } + + return 1; +} + + +static int +discovery_phase(int target, strv_t *svp) +{ + initiator_session_t *sess; + iscsi_parameter_value_t *vp; + iscsi_parameter_t *ip; + unsigned i; + char *ptr; + char *colon_ptr; + char *comma_ptr; + char port[64]; + char *text = NULL; + int text_len = 0; + + if (target >= CONFIG_INITIATOR_NUM_TARGETS) { + iscsi_trace_error(__FILE__, __LINE__, "target (%d) out of range [0..%d]\n", target, CONFIG_INITIATOR_NUM_TARGETS); + return -1; + } + sess = g_target[target].sess; + if ((text = iscsi_malloc_atomic(DISCOVERY_PHASE_TEXT_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + /* Login to target */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "entering Discovery login phase with target %d (sock %#x)\n", target, (int) sess->sock); + text[0] = 0x0; + if (params_out(sess, text, &text_len, DISCOVERY_PHASE_TEXT_LEN, SESS_TYPE_DISCOVERY, IS_SECURITY) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "params_out() failed\n"); + DP_ERROR; + } + if (login_phase_i(sess, text, text_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "login_phase_i() failed\n"); + DP_ERROR; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "now full feature for Discovery with target %d\n", target); + + /* Full Feature Phase Negotiation (for SendTargets) */ + + text_len = 0; + text[0] = 0x0; + PARAM_TEXT_ADD(sess->params, "SendTargets", "all", text, &text_len, DISCOVERY_PHASE_TEXT_LEN, 1, DP_ERROR); + PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred, text, text_len, NULL, NULL, DISCOVERY_PHASE_TEXT_LEN, 1, DP_ERROR); + if (full_feature_negotiation_phase_i(sess, text, text_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "full_feature_negotiation_phase_i() failed\n"); + DP_ERROR; + } + + /* fill in information on the targets from the TargetName values */ + (void) memset(svp, 0x0, sizeof(*svp)); + for (ip = sess->params ; ip ; ip = ip->next) { + if (strcmp(ip->key, "TargetName") == 0) { + for (vp = ip->value_l ; vp ; vp = vp->next) { + ALLOC(char *, svp->v, svp->size, svp->c, 10, 10, "discovery_phase", return -1); + svp->v[svp->c++] = strdup(vp->value); + ALLOC(char *, svp->v, svp->size, svp->c, 10, 10, "discovery_phase2", return -1); + svp->v[svp->c++] = strdup(param_val(sess->params, "TargetAddress")); + } + } + } + + if (g_target[target].iqnwanted[0] == 0x0) { + /* + * Use the first TargetName and TargetAddress sent to us (all others + * are currently ignored) + */ + if (param_val(sess->params, "TargetName") != NULL) { + strlcpy(g_target[target].TargetName, param_val(sess->params, "TargetName"), sizeof(g_target[target].TargetName)); + } else { + iscsi_trace_error(__FILE__, __LINE__, "SendTargets failed\n"); + DP_ERROR; + } + if ((ptr = param_val(sess->params, "TargetAddress")) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "SendTargets failed\n"); + DP_ERROR; + } + } else { + /* the user has asked for a specific target - find it */ + for (i = 0 ; i < svp->c ; i += 2) { + if (strcmp(g_target[target].iqnwanted, svp->v[i]) == 0) { + strlcpy(g_target[target].TargetName, svp->v[i], sizeof(g_target[target].TargetName)); + ptr = svp->v[i + 1]; + break; + } + } + if (i >= svp->c) { + iscsi_trace_error(__FILE__, __LINE__, "SendTargets failed - target `%s' not found\n", g_target[target].iqnwanted); + DP_ERROR; + } + } + + if (*ptr == 0x0) { + iscsi_trace_error(__FILE__, __LINE__, "Target is not allowing access\n"); + DP_ERROR; + } + colon_ptr = strchr(ptr, ':'); + if ((comma_ptr = strchr(ptr, ',')) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "portal group tag is missing in \"%s\"\n", param_val(sess->params, "TargetAddress")); + DP_ERROR; + } + if (colon_ptr) { + strncpy(g_target[target].ip, ptr, (int)(colon_ptr - ptr)); + strncpy(port, colon_ptr + 1, (int)(comma_ptr - colon_ptr - 1)); + port[comma_ptr - colon_ptr - 1] = 0x0; + g_target[target].port = iscsi_atoi(port); + } else { + strncpy(g_target[target].ip, ptr, (int)(comma_ptr - ptr)); + g_target[target].port = ISCSI_PORT; + } + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Discovered \"%s\" at \"%s:%u\"\n", + g_target[target].TargetName, g_target[target].name, g_target[target].port); + + /* Logout from target */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "entering logout phase with target %d\n", target); + if (logout_phase_i(sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "logout_phase_i() failed\n"); + DP_ERROR; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "target %d logout phase complete\n", target); + + DP_CLEANUP; + return 0; +} + +#define FULL_FEATURE_PHASE_TEXT_LEN 1024 + +static int +full_feature_phase(initiator_session_t * sess) +{ + char *text; + int text_len; + + if ((text = iscsi_malloc_atomic(FULL_FEATURE_PHASE_TEXT_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } +#define FFP_CLEANUP {if (text != NULL) iscsi_free_atomic(text);} +#define FFP_ERROR {FFP_CLEANUP; return -1;} + /* Set text parameters */ + + text[0] = 0x0; + text_len = 0; + if (params_out(sess, text, &text_len, FULL_FEATURE_PHASE_TEXT_LEN, SESS_TYPE_NORMAL, IS_SECURITY) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "params_out() failed\n"); + FFP_ERROR; + } + /* Send login command */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "entering login phase\n"); + if (login_phase_i(sess, text, text_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "login_phase_i() failed\n"); + FFP_ERROR; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "login phase successful\n"); + + FFP_CLEANUP; + return 0; +} + +int +initiator_init(const char *hostname, int port, int address_family, const char *user, int auth_type, int mutual_auth, int digest_type) +{ + int i; + initiator_session_t *sess = NULL; + +#define INIT_CLEANUP {if (sess != NULL) iscsi_free_atomic(sess);} +#define INIT_ERROR {INIT_CLEANUP; return -1;} + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initializing initiator\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "target config filename to read from:%s\n", gfilename); + if (get_target_config(hostname, port) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "Error getting target configuration from config file\n"); + return -1; + } + g_initiator_state = 0; + if (iscsi_queue_init(&g_session_q, CONFIG_INITIATOR_MAX_SESSIONS) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + return -1; + } + for (i = 0; i < CONFIG_INITIATOR_MAX_SESSIONS; i++) { + if ((sess = iscsi_malloc_atomic(sizeof(initiator_session_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + if (iscsi_queue_insert(&g_session_q, sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + INIT_CLEANUP; + return -1; + } + sess->sess_params.cred.user = strdup(user); + sess->sess_params.auth_type = auth_type; + sess->sess_params.mutual_auth = mutual_auth; + sess->sess_params.digest_wanted = digest_type; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "%d free sessions available\n", CONFIG_INITIATOR_MAX_SESSIONS); + + g_tag = 0xabc123; + if (hash_init(&g_tag_hash, CONFIG_INITIATOR_QUEUE_DEPTH) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_init() failed\n"); + INIT_CLEANUP; + return -1; + } + iscsi_spin_init(&g_tag_spin); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tag hash table initialized with queue depth %d\n", CONFIG_INITIATOR_QUEUE_DEPTH); + + /* + * Start enqueue worker. This thread accepts scsi commands from + * initiator_enqueue() + */ + /* and queues them onto one of the tx worker queues. */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "starting enqueue worker\n"); + if (iscsi_queue_init(&g_enqueue_q, CONFIG_INITIATOR_QUEUE_DEPTH) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + INIT_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "about to initialize mutex\n"); + ISCSI_MUTEX_INIT(&g_enqueue_worker.work_mutex, INIT_ERROR); + ISCSI_COND_INIT(&g_enqueue_worker.work_cond, INIT_ERROR); + ISCSI_MUTEX_INIT(&g_enqueue_worker.exit_mutex, INIT_ERROR); + ISCSI_COND_INIT(&g_enqueue_worker.exit_cond, INIT_ERROR); + ISCSI_LOCK(&g_enqueue_worker.exit_mutex, INIT_ERROR); + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "spawning thread for enqueue worker\n"); + if (iscsi_thread_create(&g_enqueue_worker.thread, (void *) &enqueue_worker_proc, &g_enqueue_worker) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_threads_create() failed\n"); + INIT_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "thread spawned, waiting for signal\n"); + ISCSI_WAIT(&g_enqueue_worker.exit_cond, &g_enqueue_worker.exit_mutex, INIT_ERROR); + ISCSI_UNLOCK(&g_enqueue_worker.exit_mutex, INIT_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully started enqueue worker\n"); + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initiator initialization complete\n"); + return 0; +} + +int +initiator_shutdown(void) +{ + initiator_session_t *sess; + int i; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "shutting down initiator\n"); + + for (i = 0; i < CONFIG_INITIATOR_NUM_TARGETS; i++) { + if (g_target[i].has_session) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "entering logout phase for target %d\n", i); + if (g_target[i].sess->rx_worker.state & ISCSI_WORKER_STATE_ERROR) { + iscsi_trace_warning(__FILE__, __LINE__, "rx worker exited abnormal, skipping logout phase\n"); + } else { + if (logout_phase_i(g_target[i].sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "logout_phase_i() failed for target %d\n", i); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "logout phase complete for target %d (state %#x)\n", + i, g_target[i].sess->state); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "destroying session for target %d\n", i); + if (session_destroy_i(g_target[i].sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "session_destroy_i() failed for target %d\n", i); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session destroyed for target %d\n", i); + } + } + + g_initiator_state = INITIATOR_STATE_SHUTDOWN; + if (g_enqueue_worker.state & ISCSI_WORKER_STATE_EXITING) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue already exiting\n"); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "signaling enqueue worker into exiting state\n"); + ISCSI_LOCK(&g_enqueue_worker.work_mutex, return -1); + ISCSI_SIGNAL(&g_enqueue_worker.work_cond, return -1); + ISCSI_UNLOCK(&g_enqueue_worker.work_mutex, return -1); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Checking exit condition of enqueue worker\n"); + while ((g_enqueue_worker.state & ISCSI_WORKER_STATE_EXITING) != ISCSI_WORKER_STATE_EXITING) { + ISCSI_SPIN; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue worker has exited\n"); + + iscsi_queue_destroy(&g_enqueue_q); + ISCSI_MUTEX_DESTROY(&g_enqueue_worker.work_mutex, return -1); + ISCSI_COND_DESTROY(&g_enqueue_worker.work_cond, return -1); + ISCSI_MUTEX_DESTROY(&g_enqueue_worker.exit_mutex, return -1); + ISCSI_COND_DESTROY(&g_enqueue_worker.exit_cond, return -1); + + while ((sess = iscsi_queue_remove(&g_session_q)) != NULL) { + iscsi_free_atomic(sess); + } + iscsi_queue_destroy(&g_session_q); + iscsi_spin_destroy(&g_tag_spin); + hash_destroy(&g_tag_hash); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initiator shutdown complete\n"); + return 0; +} + +static int +wait_callback_i(void *ptr) +{ + initiator_wait_t *wait = (initiator_wait_t *) (((initiator_cmd_t *) ptr)->callback_arg); + + ISCSI_LOCK(&wait->mutex, return -1); + ISCSI_SIGNAL(&wait->cond, return -1); + ISCSI_UNLOCK(&wait->mutex, return -1); + return 0; +} + +int +initiator_abort(initiator_cmd_t * cmd) +{ + initiator_cmd_t *ptr, *prev; + initiator_session_t *sess; + + iscsi_trace_error(__FILE__, __LINE__, "aborting iSCSI cmd 0x%p (type %d, isid %llu)\n", + cmd, cmd->type, cmd->isid); + + hash_remove(&g_tag_hash, cmd->key); + if (g_target[cmd->isid].has_session) { + sess = g_target[cmd->isid].sess; + iscsi_spin_lock(&sess->cmds_spin); + prev = ptr = sess->cmds; + while (ptr != NULL) { + prev = ptr; + if (ptr == cmd) + break; + ptr = ptr->next; + } + if (ptr != NULL) { + if (prev == sess->cmds) { + sess->cmds = cmd->next; + } else { + prev->next = cmd->next; + } + } + iscsi_spin_unlock(&sess->cmds_spin); + } else { + iscsi_trace_error(__FILE__, __LINE__, "cmd 0x%p has no session\n", cmd); + } + cmd->status = -1; + if (cmd->callback) { + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "cmd->callback() failed\n"); + return -1; + } + } + iscsi_trace_error(__FILE__, __LINE__, "successfully aborted iSCSI cmd 0x%p (type %d, isid %llu)\n", + cmd, cmd->type, cmd->isid); + return 0; +} + +int +initiator_command(initiator_cmd_t * cmd) +{ + initiator_wait_t wait; + + ISCSI_MUTEX_INIT(&wait.mutex, return -1); + ISCSI_COND_INIT(&wait.cond, return -1); + ISCSI_LOCK(&wait.mutex, return -1); + cmd->callback = wait_callback_i; + cmd->callback_arg = &wait; + cmd->status = -1; + if (initiator_enqueue(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_enqueue() failed\n"); + return -1; + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "command (type %d) enqueued, waiting on condition\n", cmd->type); + ISCSI_WAIT(&wait.cond, &wait.mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "condition signaled\n"); + } + ISCSI_UNLOCK(&wait.mutex, return -1); + ISCSI_COND_DESTROY(&wait.cond, return -1); + ISCSI_MUTEX_DESTROY(&wait.mutex, return -1); + + return cmd->status; +} + +/* + * initiator_enqueue() may be called from within interrupt context within + * the midlayer. This function cannot block or be scheduled within. + * All we do is enqueue the args ptr to g_enqueue_q. The thread in + * enqueue_worker_proc will enqueue the ptr onto one of the tx queues. + */ + +int +initiator_enqueue(initiator_cmd_t * cmd) +{ + initiator_session_t *sess; + iscsi_scsi_cmd_args_t *scsi_cmd; + iscsi_nop_out_args_t *nop_out; + uint64_t target; + uint32_t tag; + + if ((target = cmd->isid) >= CONFIG_INITIATOR_NUM_TARGETS) { + iscsi_trace_error(__FILE__, __LINE__, "target (%d) out of range [0..%d]\n", target, CONFIG_INITIATOR_NUM_TARGETS); + return -1; + } + sess = g_target[target].sess; + if (g_target[target].has_session && (sess->state == INITIATOR_SESSION_STATE_LOGGED_IN_NORMAL)) { + + /* Give command directly to tx worker */ + + ISCSI_SET_TAG_IN_INTR(&tag); + target = cmd->isid; + + switch (cmd->type) { + case ISCSI_SCSI_CMD: + scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr; + scsi_cmd->tag = tag; + break; + case ISCSI_NOP_OUT: + nop_out = (iscsi_nop_out_args_t *) cmd->ptr; + if (nop_out->tag != 0xffffffff) { + nop_out->tag = tag; + } + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "enqueue_worker: unknown command type %d\n", cmd->type); + return -1; + } + if (iscsi_queue_insert(&sess->tx_queue, cmd) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + return -1; + } + ISCSI_LOCK(&sess->tx_worker.work_mutex, return -1); + ISCSI_SIGNAL(&sess->tx_worker.work_cond, return -1); + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initiator_cmd_t 0x%p given to tx_worker[%llu]\n", cmd, cmd->isid); + } else { + + /* + * Give command to enqueue worker to get us into full feature + * and then issue the command + */ + /* to one of the tx workers. */ + + if (iscsi_queue_insert(&g_enqueue_q, cmd) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + return -1; + } + ISCSI_LOCK(&g_enqueue_worker.work_mutex, return -1); + ISCSI_SIGNAL(&g_enqueue_worker.work_cond, return -1); + ISCSI_UNLOCK(&g_enqueue_worker.work_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initiator_cmd_t 0x%p given to enqueue worker\n", cmd); + } + return 0; +} + +static int +enqueue_worker_proc(void *arg) +{ + initiator_session_t *sess; + initiator_cmd_t *cmd; + iscsi_scsi_cmd_args_t *scsi_cmd; + iscsi_nop_out_args_t *nop_out; + iscsi_worker_t *me = (iscsi_worker_t *) arg; + uint64_t target; + uint32_t tag; + strv_t sv; + int rc; + + + ISCSI_THREAD_START("enqueue_worker"); + ISCSI_SET_THREAD(me) + ISCSI_LOCK(&me->exit_mutex, goto done); + + me->pid = ISCSI_GETPID; + me->state = ISCSI_WORKER_STATE_STARTED; + ISCSI_SIGNAL(&me->exit_cond, goto done); + ISCSI_UNLOCK(&me->exit_mutex, goto done); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: started\n"); + ISCSI_LOCK(&g_enqueue_worker.work_mutex, goto done); + for (;;) { + if (iscsi_queue_depth(&g_enqueue_q) || (g_initiator_state == INITIATOR_STATE_SHUTDOWN)) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueu, start to work\n"); + ISCSI_UNLOCK(&g_enqueue_worker.work_mutex, goto done); + if (g_initiator_state == INITIATOR_STATE_SHUTDOWN) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "got shutdown signal\n"); + goto done; + } + if ((cmd = iscsi_queue_remove(&g_enqueue_q)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "enqueue_worker: iscsi_queue_remove() failed\n"); + goto done; + } + ISCSI_SET_TAG(&tag); + target = cmd->isid; + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "enqueue_worker: dequeued initiator_cmd_t 0x%p (type %d, target %llu)\n", cmd, cmd->type, target); + switch (cmd->type) { + case ISCSI_SCSI_CMD: + scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr; + scsi_cmd->tag = tag; + break; + case ISCSI_NOP_OUT: + nop_out = (iscsi_nop_out_args_t *) cmd->ptr; + if (nop_out->tag != 0xffffffff) { + nop_out->tag = tag; + } + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "enqueue_worker: unknown command type %d\n", cmd->type); + goto done; + } + + /* Initialize session (if not already) */ +initialize: + if (!g_target[target].has_session) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: initializing target %llu session\n", target); + if (session_init_i(&g_target[target].sess, target) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "session_init_i() failed (ignoring command)\n"); + goto next; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: target %llu session initialized\n", target); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: target %llu session already initialized\n", target); + } + sess = g_target[target].sess; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: session 0x%p\n", sess); + + /* Discovery login if TargetName is zero length */ + + if (strlen(g_target[target].TargetName) == 0) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: entering Discovery phase with target %llu\n", target); + rc = discovery_phase(target, &sv); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: Discovery phase complete\n"); + + /* Destroy session */ + + if (sess->state != INITIATOR_SESSION_STATE_DESTROYING) { + if (g_target[target].has_session) { + if (session_destroy_i(g_target[target].sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "enqueue_worker: session_destroy_i() failed\n"); + goto done; + } + } + } + + /* + * If the Discovery phase was + * successful, we re-initialize the + * session, enter full feature phase + * and then execute the command. + */ + + if (rc == 0) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: discovery_phase() succeeded, entering full feature\n"); + goto initialize; + } else { + iscsi_trace_error(__FILE__, __LINE__, "enqueue_worker: discovery_phase() failed (ignoring command)\n"); + goto next; + } + } + /* Get into full feature if we're not already */ + + if (sess->state != INITIATOR_SESSION_STATE_LOGGED_IN_NORMAL) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: entering full feature with target %llu (sock %#x)\n", target, (int) sess->sock); + if (full_feature_phase(sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "enqueue_worker: full_feature_phase() failed (ignoring command)\n"); + goto next; + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: now full feature with target %llu\n", target); + } + } + /* + * Now we are in FPP, so set the mostly + * accessed parameters for easy retrieval + * during data transfer + */ + set_session_parameters(sess->params, &sess->sess_params); + + /* Add command to tx work queue and signal worker */ + + ISCSI_LOCK(&sess->tx_worker.work_mutex, goto done); + if (iscsi_queue_insert(&sess->tx_queue, cmd) == -1) { + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, goto done); + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + goto done; + } + ISCSI_SIGNAL(&sess->tx_worker.work_cond, goto done); + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, goto done); + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "enqueue_worker: gave initiator_cmd_t 0x%p to tx_worker[%llu]\n", cmd, cmd->isid); +next: + ISCSI_LOCK(&g_enqueue_worker.work_mutex, goto done); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: queue empty, awaiting condition\n"); + ISCSI_WAIT(&g_enqueue_worker.work_cond, &g_enqueue_worker.work_mutex, goto done); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueue_worker: condition signaled\n"); + } + } +done: + ISCSI_WORKER_EXIT(me); +} + + +/*********** + * Private * + ***********/ + + +/* + * Tx Worker (one per connection) + */ + +static int +tx_worker_proc_i(void *arg) +{ + iscsi_worker_t *me = (iscsi_worker_t *) arg; + initiator_cmd_t *cmd, *ptr; + initiator_session_t *sess = g_target[me->id].sess; + + ISCSI_THREAD_START("tx_worker"); + + ISCSI_SET_THREAD(me) + me->pid = ISCSI_GETPID; + me->state = ISCSI_WORKER_STATE_STARTED; + + /* Connect to target */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: connecting to %s:%d\n", + me->id, g_target[me->id].name, g_target[me->id].port); + sess->state = INITIATOR_SESSION_STATE_CONNECTING; + if (iscsi_sock_connect(sess->sock, g_target[me->id].name, g_target[me->id].port) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_connect() failed\n"); + + ISCSI_LOCK(&me->exit_mutex, return -1); + me->state |= ISCSI_WORKER_STATE_ERROR; + ISCSI_SIGNAL(&me->exit_cond, return -1); + ISCSI_UNLOCK(&me->exit_mutex, return -1); + goto done; + + } + sess->state = INITIATOR_SESSION_STATE_CONNECTED; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: connected to %s:%d\n", + me->id, g_target[me->id].name, g_target[me->id].port); + + /* Start Rx worker */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: starting Rx worker\n", me->id); + ISCSI_LOCK(&sess->rx_worker.exit_mutex, return -1); + if (iscsi_thread_create(&sess->rx_worker.thread, (void *) rx_worker_proc_i, sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_thread_create() failed\n"); + goto done; + } + ISCSI_WAIT(&sess->rx_worker.exit_cond, &sess->rx_worker.exit_mutex, return -1); + ISCSI_UNLOCK(&sess->rx_worker.exit_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: Rx worker started\n", me->id); + + /* Signal that we've started */ + ISCSI_LOCK(&me->exit_mutex, return -1); + ISCSI_SIGNAL(&me->exit_cond, return -1); + ISCSI_UNLOCK(&me->exit_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: successfully started\n", me->id); + + /* This Tx loop will exit when both the g_tx_queue is empty and */ + /* sess->state != INITIATOR_SESSION_STATE_DESTROYING */ + + ISCSI_LOCK(&me->work_mutex, return -1); + for (;;) { + + if (iscsi_queue_depth(&g_target[me->id].sess->tx_queue) || (sess->state == INITIATOR_SESSION_STATE_DESTROYING)) { + + if (sess->state == INITIATOR_SESSION_STATE_DESTROYING) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: session is being destroyed, exiting\n", me->id); + ISCSI_UNLOCK(&me->work_mutex, return -1); + goto done; + } + /* Get initiator command */ + + if ((cmd = iscsi_queue_remove(&g_target[me->id].sess->tx_queue)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: iscsi_queue_remove() failed\n", me->id); + ISCSI_UNLOCK(&me->work_mutex, return -1); + goto done; + } + ISCSI_UNLOCK(&me->work_mutex, return -1); + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "tx_worker[%d]: dequeued initiator_cmd_t 0x%p (type %d, target %llu)\n", me->id, cmd, cmd->type, cmd->isid); + + /* Make sure we've got the right command */ + + if (cmd->isid != (unsigned)me->id) { + iscsi_trace_error(__FILE__, __LINE__, "got command %#x for target %llu, expected %d\n", cmd->type, cmd->isid, me->id); + goto done; + } + /* + * Add to list of oustanding commands in session + * (unless NOP_OUT without ping) + */ + + if (!((cmd->type == ISCSI_NOP_OUT) && (((iscsi_nop_out_args_t *) (cmd->ptr))->tag == 0xffffffff))) { + cmd->next = NULL; + iscsi_spin_lock(&sess->cmds_spin); + for (ptr = sess->cmds; ((ptr) && (ptr->next != NULL)); ptr = ptr->next) { + } + if (ptr) { + ptr->next = cmd; + } else { + sess->cmds = cmd; + } + iscsi_spin_unlock(&sess->cmds_spin); + } + cmd->tx_done = 0; + switch (cmd->type) { + case ISCSI_LOGIN_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "tx_worker[%d]: ISCSI_LOGIN_CMD\n", me->id); + if (login_command_i(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: login_command_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_TEXT_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "tx_worker[%d]: ISCSI_TEXT_CMD\n", me->id); + if (text_command_i(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: text_command_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_SCSI_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "tx_worker[%d]: ISCSI_SCSI_CMD\n", me->id); + if (scsi_command_i(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: scsi_command_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_NOP_OUT: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "tx_worker[%d]: ISCSI_NOP_OUT\n", me->id); + if (nop_out_i(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: nop_out_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_LOGOUT_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "tx_worker[%d]: ISCSI_LOGOUT_CMD\n", me->id); + if (logout_command_i(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: logout_command_i() failed\n", me->id); + goto done; + } + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: unknown iSCSI command %#x\n", me->id, cmd->type); + cmd->status = -1; + break; + } + + /* Get lock for next iteration */ + + ISCSI_LOCK(&me->work_mutex, return -1); + + /* + * The Rx thread will receive a response for + * the command and execute the callback. We + * need to make sure the callback function is + * not executed before the Tx thread has + * completed sending the command. This is + * what tx_done is used for. The last step is + * to set tx_done and signal the Rx thread, + * which may be block on the condition. + * NOP_OUT (without ping) will have no + * response for the Rx thread to process - so + * we execute the callback directly. */ + + if ((cmd->type == ISCSI_NOP_OUT) && (((iscsi_nop_out_args_t *) (cmd->ptr))->tag == 0xffffffff)) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "executing callback() function directly for NOP_OUT (no NOP_IN)\n"); + if (cmd->callback(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "cmd->callback() failed\n"); + return -1; + } + } else { + ISCSI_LOCK(&sess->rx_worker.work_mutex, return -1); + cmd->tx_done = 1; + ISCSI_SIGNAL(&sess->rx_worker.work_cond, return -1); + ISCSI_UNLOCK(&sess->rx_worker.work_mutex, return -1); + } + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: awaiting condition\n", me->id); + ISCSI_WAIT(&me->work_cond, &me->work_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%d]: condition signaled\n", me->id); + } + } +done: + if (sess->state != INITIATOR_SESSION_STATE_DESTROYING) { + iscsi_trace_error(__FILE__, __LINE__, "tx_worker[%d]: session exited prematurely (state %#x)\n", me->id, sess->state); + me->state |= ISCSI_WORKER_STATE_ERROR; + } + ISCSI_WORKER_EXIT(me); + +} + +/* + * There is one Rx worker per connection. + */ + +static int +rx_worker_proc_i(void *arg) +{ + uint8_t header[ISCSI_HEADER_LEN]; + initiator_session_t *sess = (initiator_session_t *) arg; + iscsi_worker_t *me = &sess->rx_worker; + initiator_cmd_t *cmd = NULL; + initiator_cmd_t *prev, *ptr; + uint32_t tag; + + ISCSI_THREAD_START("rx_worker"); + ISCSI_SET_THREAD(me) + me->state = ISCSI_WORKER_STATE_STARTED; + me->pid = ISCSI_GETPID; + ISCSI_LOCK(&me->exit_mutex, return -1); + ISCSI_SIGNAL(&me->exit_cond, return -1); + ISCSI_UNLOCK(&me->exit_mutex, return -1); + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: started (sess %p)\n", me->id, sess); + + for (;;) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: reading iscsi header (sock %#x) \n", + me->id, (int) sess->sock); + if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: iscsi_sock_msg() failed\n", me->id); + goto done; + } + if (sess->state == INITIATOR_SESSION_STATE_DESTROYING) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: session is being destroyed\n", me->id); + goto done; + } + /* Get cmd ptr from hash table */ + + if ((ISCSI_OPCODE(header) != ISCSI_REJECT) && (ISCSI_OPCODE(header) != ISCSI_ASYNC)) { + tag = ISCSI_NTOHL(*((uint32_t *) (header + 16))); + if (tag != 0xffffffff) { + + /* + * remove command from g_tag_hash, cmd is + * local so we only need to lock the queue + * remove operation + */ + + if ((cmd = hash_remove(&g_tag_hash, tag)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "hash_remove() failed\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no cmd ptr associated with tag %#x\n", tag); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "cmd ptr %p associated with tag %#x\n", cmd, tag); + + ISCSI_LOCK(&sess->rx_worker.work_mutex, return -1); + if (!cmd->tx_done) { + ISCSI_WAIT(&sess->rx_worker.work_cond, &sess->rx_worker.work_mutex, return -1); + } + ISCSI_UNLOCK(&sess->rx_worker.work_mutex, return -1); + } + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no command associated with tag %#x\n", tag); + } + } + /* Remove cmd ptr from outstanding list */ + iscsi_spin_lock(&sess->cmds_spin); + prev = ptr = sess->cmds; + while (ptr != NULL) { + prev = ptr; + if (ptr == cmd) + break; + ptr = ptr->next; + } + if (ptr != NULL) { + if (prev == sess->cmds) { + sess->cmds = cmd->next; + } else { + prev->next = cmd->next; + } + } + iscsi_spin_unlock(&sess->cmds_spin); + switch (ISCSI_OPCODE(header)) { + case ISCSI_SCSI_RSP: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_SCSI_RSP\n", me->id); + if (scsi_response_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: scsi_response_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_READ_DATA: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_READ_DATA\n", me->id); + if (scsi_read_data_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: scsi_read_data_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_R2T: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_R2T\n", me->id); + if (scsi_r2t_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: scsi_r2t_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_NOP_IN: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_NOP_IN\n", me->id); + if (nop_in_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_in_i() failed\n"); + return -1; + } + break; + case ISCSI_LOGIN_RSP: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_LOGIN_RSP\n", me->id); + if (login_response_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: login_response_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_TEXT_RSP: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_TEXT_RSP\n", me->id); + if (text_response_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: text_response_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_LOGOUT_RSP: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_LOGOUT_RSP\n", me->id); + if (logout_response_i(sess, cmd, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: logout_response_i() failed\n", me->id); + goto done; + } + break; + case ISCSI_REJECT: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_REJECT\n", me->id); + if (reject_i(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "reject_i() failed\n"); + return -1; + } + break; + case ISCSI_ASYNC: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: ISCSI_ASYNC\n", me->id); + if (async_msg_i(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "async_msg_i() failed\n"); + goto done; + } + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "rx_worker[%d]: unexpected iSCSI op %#x\n", me->id, ISCSI_OPCODE(header)); + goto done; + } + } +done: + if (sess->state != INITIATOR_SESSION_STATE_DESTROYING) { + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "rx_worker[%d]: session exited prematurely (state %#x)\n", me->id, sess->state); + me->state |= ISCSI_WORKER_STATE_ERROR; + } + ISCSI_WORKER_EXIT(me); +} + +static int +text_command_i(initiator_cmd_t * cmd) +{ + iscsi_text_cmd_args_t *text_cmd = (iscsi_text_cmd_args_t *) cmd->ptr; + initiator_session_t *sess = g_target[cmd->isid].sess; + uint8_t header[ISCSI_HEADER_LEN]; + + /* + * Insert cmd into the hash table, keyed by the tag. The Rx thread + * will + */ + /* retreive the cmd ptr using the tag from the response PDU. */ + + if (hash_insert(&g_tag_hash, cmd, text_cmd->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + return -1; + } + /* Send text command PDU */ + + text_cmd->ExpStatSN = sess->ExpStatSN; + text_cmd->CmdSN = sess->CmdSN++; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending text command\n"); + if (iscsi_text_cmd_encap(header, text_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "(iscsi_text_cmd_encap() failed\n"); + return -1; + } + if ((unsigned)iscsi_sock_send_header_and_data(sess->sock, header, ISCSI_HEADER_LEN, text_cmd->text, text_cmd->length, 0) + != ISCSI_HEADER_LEN + text_cmd->length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed.\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "text command sent ok\n"); + + return 0; +} + +static int +login_command_i(initiator_cmd_t * cmd) +{ + iscsi_login_cmd_args_t *login_cmd = (iscsi_login_cmd_args_t *) cmd->ptr; + initiator_session_t *sess = g_target[cmd->isid].sess; + uint8_t header[ISCSI_HEADER_LEN]; + + /* + * Insert cmd into the hash table, keyed by the tag. The Rx thread + * will + */ + /* retreive the cmd ptr using the tag from the response PDU. */ + + if (hash_insert(&g_tag_hash, cmd, login_cmd->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + return -1; + } + /* Send login command PDU */ + login_cmd->ExpStatSN = sess->ExpStatSN; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending login command\n"); + if (iscsi_login_cmd_encap(header, login_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "(iscsi_login_cmd_encap() failed\n"); + return -1; + } + if ((unsigned)iscsi_sock_send_header_and_data(sess->sock, header, ISCSI_HEADER_LEN, login_cmd->text, login_cmd->length, 0) + != ISCSI_HEADER_LEN + login_cmd->length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed.\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "login command sent ok\n"); + + return 0; +} + +static int +logout_phase_i(initiator_session_t * sess) +{ + initiator_cmd_t *cmd = NULL; + iscsi_logout_cmd_args_t *logout_cmd = NULL; + initiator_wait_t wait; + + sess->state = INITIATOR_SESSION_STATE_LOGGING_OUT; + + /* Allocate command pointers */ + + if ((cmd = iscsi_malloc_atomic(sizeof(initiator_cmd_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + (void) memset(cmd, 0x0, sizeof(*cmd)); + if ((logout_cmd = iscsi_malloc_atomic(sizeof(iscsi_logout_cmd_args_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (cmd != NULL) + iscsi_free_atomic(cmd); + return -1; + } +#define LO_CLEANUP {if (cmd != NULL) iscsi_free_atomic(cmd); if (logout_cmd != NULL) iscsi_free_atomic(logout_cmd); } +#define LO_ERROR {LO_CLEANUP; return -1;} + (void) memset(logout_cmd, 0x0, sizeof(*logout_cmd)); + + /* Build logout command */ + + logout_cmd->cid = sess->cid; + logout_cmd->reason = ISCSI_LOGOUT_CLOSE_SESSION; + ISCSI_SET_TAG(&logout_cmd->tag); + logout_cmd->ExpStatSN = sess->ExpStatSN; + logout_cmd->CmdSN = sess->CmdSN++; + + /* Build wait for callback */ + + ISCSI_MUTEX_INIT(&wait.mutex, LO_ERROR); + ISCSI_COND_INIT(&wait.cond, LO_ERROR); + + /* Build initiator command */ + + cmd->type = ISCSI_LOGOUT_CMD; + cmd->ptr = logout_cmd; + cmd->callback = wait_callback_i; + cmd->callback_arg = &wait; + cmd->isid = sess->isid; + + /* Enqueue to Tx worker */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueing logout command to tx worker %llu\n", sess->isid); + ISCSI_LOCK(&wait.mutex, LO_ERROR); + ISCSI_LOCK(&sess->tx_worker.work_mutex, LO_ERROR); + if (iscsi_queue_insert(&sess->tx_queue, cmd) == -1) { + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, LO_ERROR); + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + LO_ERROR; + } + ISCSI_SIGNAL(&sess->tx_worker.work_cond, LO_ERROR); + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, LO_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueued logout command ok\n"); + + /* Wait for callback */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "waiting on logout callback\n"); + ISCSI_WAIT(&wait.cond, &wait.mutex, LO_ERROR); + ISCSI_UNLOCK(&wait.mutex, LO_ERROR); + ISCSI_COND_DESTROY(&wait.cond, LO_ERROR); + ISCSI_MUTEX_DESTROY(&wait.mutex, LO_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "received logout callback ok\n"); + + sess->state = INITIATOR_SESSION_STATE_LOGGED_OUT; + + LO_CLEANUP; + return 0; +} + +static void +alarm_handler(int arg) +{ + iscsi_trace_error(__FILE__, __LINE__, "***aborting cmd 0x%p***\n", g_cmd); + if (initiator_abort(g_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_abort() failed\n"); + } +} + +static int +login_phase_i(initiator_session_t * sess, char *text, int text_len) +{ + initiator_cmd_t *cmd = NULL; + initiator_wait_t wait; + iscsi_login_cmd_args_t *login_cmd = NULL; + struct sigaction act; + + sess->state = INITIATOR_SESSION_STATE_LOGGING_IN; + + /* Allocate command pointers */ + + if ((cmd = iscsi_malloc_atomic(sizeof(initiator_cmd_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + (void) memset(cmd, 0x0, sizeof(*cmd)); + if ((login_cmd = iscsi_malloc_atomic(sizeof(iscsi_login_cmd_args_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (cmd != NULL) + iscsi_free_atomic(cmd); + return -1; + } +#define LI_CLEANUP {if (cmd != NULL) iscsi_free_atomic(cmd); if (login_cmd != NULL) iscsi_free_atomic(login_cmd); } +#define LI_ERROR {LI_CLEANUP; return -1;} + (void) memset(login_cmd, 0x0, sizeof(*login_cmd)); + + /* This is the length of our original offer. */ + + login_cmd->text = text; + login_cmd->length = text_len; + login_cmd->transit = 1; + login_cmd->csg = ISCSI_LOGIN_STAGE_SECURITY; + login_cmd->nsg = ISCSI_LOGIN_STAGE_NEGOTIATE; + ISCSI_SET_TAG(&login_cmd->tag); + login_cmd->CmdSN = sess->CmdSN = 0; + + do { + + /* + * Build login command. Note that the and + * fields may get updated by login_response_i. + * Such is the case when we receive offers from the + * target. The new and fields will + * represent the response that we need to send to the + * target on the next login. + */ + + login_cmd->cont = 0; + login_cmd->version_min = ISCSI_VERSION; + login_cmd->version_max = ISCSI_VERSION; + login_cmd->cid = sess->cid = sess->isid; + login_cmd->isid = sess->isid = sess->isid; + login_cmd->tsih = 0; + + /* Build wait for callback */ + + ISCSI_MUTEX_INIT(&wait.mutex, LI_ERROR); + ISCSI_COND_INIT(&wait.cond, LI_ERROR); + + /* Build initiator command */ + + cmd->type = ISCSI_LOGIN_CMD; + cmd->ptr = login_cmd; + cmd->callback = wait_callback_i; + cmd->callback_arg = &wait; + cmd->isid = sess->isid; + + /* Set Alarm */ + + g_cmd = cmd; + act.sa_handler = alarm_handler; + sigaction(SIGALRM, &act, NULL); + alarm(5); + + /* Enqueue initiator command to Tx worker */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueing login command to tx worker %llu\n", sess->isid); + ISCSI_LOCK(&wait.mutex, LI_ERROR); + ISCSI_LOCK(&sess->tx_worker.work_mutex, LI_ERROR); + if (iscsi_queue_insert(&sess->tx_queue, cmd) == -1) { + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, LI_ERROR); + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + LI_ERROR; + + } + ISCSI_SIGNAL(&sess->tx_worker.work_cond, LI_ERROR); + ISCSI_UNLOCK(&sess->tx_worker.work_mutex, LI_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "enqueued login command ok\n"); + + /* Wait for callback */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "waiting on login callback\n"); + ISCSI_WAIT(&wait.cond, &wait.mutex, LI_ERROR); + ISCSI_UNLOCK(&wait.mutex, LI_ERROR); + ISCSI_COND_DESTROY(&wait.cond, LI_ERROR); + ISCSI_MUTEX_DESTROY(&wait.mutex, LI_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "received login callback ok\n"); + + alarm(0); + + if (cmd->status != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_cmd_t failed\n"); + LI_ERROR; + } + if (sess->state == INITIATOR_SESSION_STATE_LOGGING_IN) { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "more negotiation needed (sending %d bytes response parameters)\n", + login_cmd->length); + } + } while (sess->state == INITIATOR_SESSION_STATE_LOGGING_IN); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "login phase completed successfully\n"); + + LI_CLEANUP; + return 0; +} + + +#define TEXT_RESPONSE_TEXT_LEN 2048 + +static int +text_response_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_text_cmd_args_t *text_cmd; + iscsi_text_rsp_args_t text_rsp; + iscsi_parameter_t *l = sess->params; + char *text_in = NULL; + char *text_out = NULL; + int len_in = 0; + int len_out = 0; + int ret = 0; + +#define TI_CLEANUP {if (text_in != NULL) iscsi_free_atomic(text_in); if (text_out != NULL) iscsi_free_atomic(text_out);} +#define TI_ERROR {cmd->status=-1; goto callback;} + if (cmd) { + text_cmd = (iscsi_text_cmd_args_t *) cmd->ptr; + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t specified for iscsi_text_cmd_args_t??\n"); + return -1; + } + + /* Check arguments & update numbering */ + + if (iscsi_text_rsp_decap(header, &text_rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "text_response_decap() failed\n"); + TI_ERROR; + } + RETURN_NOT_EQUAL("Tag", text_rsp.tag, text_cmd->tag, TI_ERROR, -1); + RETURN_NOT_EQUAL("Transfer Tag", text_rsp.transfer_tag, 0xffffffff, TI_ERROR, -1); + RETURN_NOT_EQUAL("StatSN", text_rsp.StatSN, sess->ExpStatSN, TI_ERROR, -1); + RETURN_NOT_EQUAL("ExpCmdSN", text_rsp.ExpCmdSN, sess->CmdSN, TI_ERROR, -1); + sess->ExpStatSN = text_rsp.StatSN + 1; + + /* Parse input text parameters and generate any response */ + + if ((len_in = text_rsp.length) != 0) { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "allocating %d bytes input parameters\n", len_in); + if ((text_in = iscsi_malloc_atomic(len_in + 1)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + TI_ERROR; + } + if ((text_out = iscsi_malloc_atomic(TEXT_RESPONSE_TEXT_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + if (text_in != NULL) + iscsi_free_atomic(text_in); + TI_ERROR; + } + if (iscsi_sock_msg(sess->sock, 0, len_in, text_in, 0) != len_in) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TI_ERROR; + } + text_in[len_in] = 0x0; + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "read %d bytes input parameters ok\n", len_in); + + /* Reset the value lists for TargetName and TargetAddress */ + + if (param_val_reset(sess->params, "TargetName") != 0) { + iscsi_trace_error(__FILE__, __LINE__, "parm_val_reset() failed\n"); + TI_ERROR; + } + if (param_val_reset(sess->params, "TargetAddress") != 0) { + iscsi_trace_error(__FILE__, __LINE__, "parm_val_reset() failed\n"); + TI_ERROR; + } + /* Parse the incoming answer */ + + PARAM_TEXT_PARSE(l, &sess->sess_params.cred, text_in, len_in, text_out, &len_out, TEXT_RESPONSE_TEXT_LEN, 0, TI_ERROR); + + if (len_out) { + + RETURN_NOT_EQUAL("text_rsp.final", text_rsp.final, 0, TI_ERROR, -1); + + /* + * Copy response text into text_cmd->text and + * update the length text_cmd->length. This + * will be sent out on the next text command. + * */ + + PARAM_TEXT_PARSE(l, &sess->sess_params.cred, text_out, len_out, NULL, NULL, TEXT_RESPONSE_TEXT_LEN, 1, TI_ERROR); + + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "need to send %d bytes response back to target\n", len_out); + text_cmd->length = len_out; + memcpy(text_cmd->text, text_out, len_out); + } else { + text_cmd->length = 0; + } + } + text_cmd->final = text_rsp.final; + + /* Issue callback */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "iscsi_text_cmd_args_t done\n"); +callback: + if (cmd->status == -1) + ret = -1; + if (cmd->callback(cmd) != 0) { + ret = -1; + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + } + TI_CLEANUP; + return ret; +} + +#define LOGIN_RESPONSE_TEXT_LEN 2048 + +static int +login_response_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_login_cmd_args_t *login_cmd; + iscsi_login_rsp_args_t login_rsp; + iscsi_parameter_t *l = sess->params; + char *text_in = NULL; + char *text_out = NULL; + int len_in = 0; + int len_out = 0; + + if ((text_out = iscsi_malloc_atomic(LOGIN_RESPONSE_TEXT_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + cmd->status = -1; + goto callback; + } +#define LIR_CLEANUP {if (text_in != NULL) iscsi_free_atomic(text_in); if (text_out != NULL) iscsi_free_atomic(text_out);} +#define LIR_ERROR {cmd->status=-1; goto callback;} + if (cmd) { + login_cmd = (iscsi_login_cmd_args_t *) cmd->ptr; + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t specified for iscsi_login_cmd_args_t??\n"); + LIR_ERROR; + } + + /* Read login response */ + + if (iscsi_login_rsp_decap(header, &login_rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "login_response_decap() failed\n"); + LIR_ERROR; + } + RETURN_GREATER("Length (should this be hardcoded?)", login_rsp.length, 8192, LIR_CLEANUP, -1); /* XXX - agc */ + + /* Read & parse text response */ + + if ((len_in = login_rsp.length) != 0) { + if ((text_in = iscsi_malloc_atomic(len_in + 1)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + LIR_ERROR; + } + if (iscsi_sock_msg(sess->sock, 0, len_in, text_in, 0) != len_in) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + LIR_ERROR; + } + text_in[len_in] = 0x0; + PARAM_TEXT_PARSE(l, &sess->sess_params.cred, text_in, len_in, text_out, &len_out, LOGIN_RESPONSE_TEXT_LEN, 0, LIR_ERROR); + if (login_rsp.transit) { + WARN_NOT_EQUAL("len_out", len_out, 0); + } + } + /* Check args */ + + if (login_rsp.status_class != 0) { + iscsi_trace_error(__FILE__, __LINE__, "Bad Status-Class: got %d, expected %d\n", login_rsp.status_class, 0); + LIR_ERROR; + } + if (login_rsp.tag != login_cmd->tag) { + iscsi_trace_error(__FILE__, __LINE__, "Bad Tag: got %x, expected %x\n", login_rsp.tag, login_cmd->tag); + LIR_ERROR; + } + sess->ExpStatSN = login_rsp.StatSN + 1; + + + if (login_rsp.transit) { + + if (login_cmd->transit != 1) + iscsi_trace_warning(__FILE__, __LINE__, "incoming packet transit bit not set, csg = %d, nsg = %d\n", + login_cmd->csg, login_cmd->nsg); + + switch (login_rsp.nsg) { + case ISCSI_LOGIN_STAGE_NEGOTIATE: + login_cmd->csg = login_cmd->nsg; + login_cmd->nsg = ISCSI_LOGIN_STAGE_FULL_FEATURE; + if (params_out(sess, text_out, &len_out, LOGIN_RESPONSE_TEXT_LEN, SESS_TYPE_NONE, !IS_SECURITY) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "params_out() failed\n"); + LIR_ERROR; + } + login_cmd->length = len_out; + (void) memcpy(login_cmd->text, text_out, len_out); + break; + + case ISCSI_LOGIN_STAGE_FULL_FEATURE: + /* Check post conditions */ + + RETURN_EQUAL("TSIH", 0, login_rsp.tsih, LIR_ERROR, -1); + RETURN_NOT_EQUAL("ISID", (uint32_t) login_rsp.isid, (uint32_t) login_cmd->isid, LIR_ERROR, -1); + RETURN_NOT_EQUAL("ExpCmdSN", login_rsp.ExpCmdSN, login_cmd->CmdSN, LIR_ERROR, -1); + RETURN_GREATER("MaxCmdSN", login_rsp.ExpCmdSN, login_rsp.MaxCmdSN, LIR_ERROR, -1); + + /* Set remaining session parameters */ + + sess->CmdSN = login_rsp.ExpCmdSN; + sess->MaxCmdSN = login_rsp.MaxCmdSN; + sess->tsih = login_rsp.tsih; + sess->isid = login_rsp.isid; + + if (param_equiv(sess->params, "SessionType", "Normal")) { + sess->state = INITIATOR_SESSION_STATE_LOGGED_IN_NORMAL; + } else if (param_equiv(sess->params, "SessionType", "Discovery")) { + sess->state = INITIATOR_SESSION_STATE_LOGGED_IN_DISCOVERY; + } else { + iscsi_trace_error(__FILE__, __LINE__, "Unknown SessionType \"%s\"\n", param_val(sess->params, "SessionType")); + LIR_ERROR; + } + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "*********************************************\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* LOGIN SUCCESSFUL *\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "CID", sess->cid); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20llu *\n", "ISID", sess->isid); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "TSIH", sess->tsih); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "CmdSN", sess->CmdSN); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "MaxCmdSN", sess->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "ExpStatSN", sess->ExpStatSN); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "*********************************************\n"); + break; + default: + LIR_ERROR; + } + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "received partial login response\n"); + + /* Copy response text into login_cmd->text and update the */ + /* length login_cmd->length. This will be sent out on the */ + /* next login command. */ + + if (len_out) { + PARAM_TEXT_PARSE(l, &sess->sess_params.cred, text_out, len_out, NULL, NULL, 0, 1, LIR_ERROR); + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "need to send %d bytes response back to target\n", len_out); + + login_cmd->length = len_out; + memcpy(login_cmd->text, text_out, len_out); + if (strncmp(text_out, "CHAP_N=", strlen("CHAP_N=")) == 0) { + login_cmd->nsg = ISCSI_LOGIN_STAGE_NEGOTIATE; + login_cmd->transit = 1; + } + } else { + login_cmd->length = 0; + } + } + + /* Callback */ + +callback: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "iscsi_login_cmd_args_t done (cmd status %d, iscsi status %d)\n", + cmd->status, login_rsp.status_class); + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + LIR_CLEANUP; + return -1; + } + LIR_CLEANUP; + return 0; +} + +static int +logout_command_i(initiator_cmd_t * cmd) +{ + iscsi_logout_cmd_args_t *logout_cmd = (iscsi_logout_cmd_args_t *) cmd->ptr; + initiator_session_t *sess = g_target[cmd->isid].sess; + uint8_t header[ISCSI_HEADER_LEN]; + + /* + * Insert cmd into the hash table, keyed by the tag. The Rx thread + * will + */ + /* retreive the cmd ptr using the tag from the response PDU. */ + + if (hash_insert(&g_tag_hash, cmd, logout_cmd->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + return -1; + } + /* Send logout command PDU */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending logout command\n"); + if (iscsi_logout_cmd_encap(header, logout_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_logout_cmd_encap() failed\n"); + return -1; + } + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed.\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "logout command sent ok\n"); + + return 0; +} + + +static int +logout_response_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_logout_cmd_args_t *logout_cmd; + iscsi_logout_rsp_args_t logout_rsp; + +#define LOR_ERROR {cmd->status=-1; goto callback;} + if (cmd) { + if (cmd->ptr) { + logout_cmd = (iscsi_logout_cmd_args_t *) cmd->ptr; + } else { + iscsi_trace_error(__FILE__, __LINE__, "no iscsi_logout_cmd_args_t specified for initiator_cmd_t??\n"); + LOR_ERROR; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t specified for iscsi_logout_cmd_args_t??\n"); + return -1; + } + if (iscsi_logout_rsp_decap(header, &logout_rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_logout_rsp_decap() failed\n"); + LOR_ERROR; + } + RETURN_NOT_EQUAL("Response", logout_rsp.response, ISCSI_LOGOUT_STATUS_SUCCESS, LOR_ERROR, -1); + RETURN_NOT_EQUAL("Tag", logout_rsp.tag, logout_cmd->tag, LOR_ERROR, -1); + + /* Check and update numbering */ + + RETURN_NOT_EQUAL("StatSN", logout_rsp.StatSN, sess->ExpStatSN, LOR_ERROR, -1); + sess->ExpStatSN++; + + RETURN_NOT_EQUAL("ExpCmdSN", logout_rsp.ExpCmdSN, sess->CmdSN, LOR_ERROR, -1); + sess->MaxCmdSN = logout_rsp.MaxCmdSN; + + /* Callback */ + + cmd->status = 0; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "LOGOUT_CMD_T done (cmd status %d, iscsi status %d)\n", + cmd->status, logout_rsp.response); +callback: + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + return -1; + } + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "*********************************************\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* LOGOUT SUCCESSFUL *\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "CID", sess->cid); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20llu *\n", "ISID", sess->isid); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "* %20s:%20u *\n", "TSIH", sess->tsih); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "*********************************************\n"); + + return 0; +} + +static int +nop_out_i(initiator_cmd_t * cmd) +{ + uint8_t header[ISCSI_HEADER_LEN]; + iscsi_nop_out_args_t *nop_out = cmd->ptr; + initiator_session_t *sess = g_target[cmd->isid].sess; + int rc, length = nop_out->length; + + if (nop_out->tag != 0xffffffff) { + + /* + * Insert cmd into the hash table, keyed by + * nop_out->tag. Upon receipt of the NOP_IN_T, the Rx + * thread will retreive the cmd ptr using the tag from + * the NOP_IN_T PDU. */ + + if (hash_insert(&g_tag_hash, cmd, nop_out->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + return -1; + } + } + /* Encapsulate and send NOP */ + + nop_out->ExpStatSN = sess->ExpStatSN; + /* nop_out->CmdSN = sess->CmdSN++; */ + nop_out->transfer_tag = 0xffffffff; + if (iscsi_nop_out_encap(header, nop_out) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_nop_out_encap() failed\n"); + return -1; + } + /* + * We need to make a copy of nop_out->length and save in the + * variable length. Otherwise, we may get a seg fault - as if + * this is a NOP_OUT without ping, the Tx thread will issue + * the callback function immediately after we return - thereby + * de-allocating the NOP_OUT and initiator command structures. + * */ + + if ((rc = iscsi_sock_send_header_and_data(sess->sock, header, ISCSI_HEADER_LEN, nop_out->data, + length, 0)) != ISCSI_HEADER_LEN + length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed: got %d expected %d\n", rc, ISCSI_HEADER_LEN + length); + return -1; + } + cmd->status = 0; + return 0; +} + +static int +scsi_command_i(initiator_cmd_t * cmd) +{ + iscsi_scsi_cmd_args_t *scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr; + uint8_t header[ISCSI_HEADER_LEN]; + uint64_t target = cmd->isid; + initiator_session_t *sess = g_target[target].sess; + iscsi_write_data_t data; + struct iovec sg_singleton; + struct iovec *sg, *sg_copy, *sg_copy_orig, *sg_which; + int sg_len, sg_len_copy, sg_len_which; + int fragment_flag = 0; + + sg = sg_copy = sg_copy_orig = sg_which = NULL; + sg_len = sg_len_copy = sg_len_which = 0; + scsi_cmd->status = 0; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tx_worker[%llu]: scsi op %#x lun %llu trans_len %d length %d send_sg_len %d recv_sg_len %d\n", target, scsi_cmd->cdb[0], scsi_cmd->lun, scsi_cmd->trans_len, scsi_cmd->length, scsi_cmd->send_sg_len, scsi_cmd->recv_sg_len); + + RETURN_GREATER("target id", (uint32_t) target, CONFIG_INITIATOR_NUM_TARGETS - 1, NO_CLEANUP, -1); + + /* Set and check scsi_cmd */ + + if (scsi_cmd->trans_len > sess->sess_params.max_burst_length) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_cmd->trans_len (%u) > MaxBurstLength (%u)\n", + scsi_cmd->trans_len, sess->sess_params.max_burst_length); + return -1; + } + if (scsi_cmd->length > scsi_cmd->trans_len) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_cmd->length (%u) > scsi_cmd->trans_len (%u)\n", + scsi_cmd->length, scsi_cmd->trans_len); + return -1; + } + scsi_cmd->ExpStatSN = sess->ExpStatSN; + scsi_cmd->CmdSN = sess->CmdSN; + scsi_cmd->bytes_sent = scsi_cmd->bytes_recv = 0; + + /* Always use iovec for data */ + + if (scsi_cmd->output) { + if (scsi_cmd->send_sg_len) { /* Data already an iovec */ + sg = (struct iovec *) scsi_cmd->send_data; + sg_len = scsi_cmd->send_sg_len; + } else { /* Make iovec for data */ + sg_singleton.iov_base = scsi_cmd->send_data; + sg_singleton.iov_len = scsi_cmd->trans_len; + sg = &sg_singleton; + sg_len = 1; + } + } + /* + * Insert cmd into the hash table, keyed by scsi_cmd->tag. The Rx + * thread will + */ + /* retreive the cmd ptr using the tag from the response PDU. */ + + if (hash_insert(&g_tag_hash, cmd, scsi_cmd->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + goto error; + } + /* Send command PDU */ + + if (scsi_cmd->output && sess->sess_params.immediate_data) { + if (sess->sess_params.max_data_seg_length) { + scsi_cmd->length = MIN(sess->sess_params.max_data_seg_length, + scsi_cmd->trans_len); + } else { + scsi_cmd->length = scsi_cmd->trans_len; + } + if (scsi_cmd->length == scsi_cmd->trans_len) + scsi_cmd->final = 1; + } else { + scsi_cmd->length = 0; + scsi_cmd->final = 1; + } + if (iscsi_scsi_cmd_encap(header, scsi_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_scsi_cmd_encap() failed\n"); + goto error; + } + /* + * If we're sending any immediate data, we need to make a new + * iovec that contains only the immediata data (a subset of + * the original iovec). */ + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending command PDU with %u bytes immediate data\n", scsi_cmd->length); + if (scsi_cmd->length && sess->sess_params.immediate_data) { + if ((sg_copy = iscsi_malloc_atomic(sg_len * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto error; + } + fragment_flag++; + sg_copy_orig = sg_copy; + memcpy(sg_copy, sg, sizeof(struct iovec) * sg_len); + sg_len_copy = sg_len; + if (modify_iov(&sg_copy, &sg_len_copy, 0, scsi_cmd->length) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + goto error; + } + if (scsi_cmd->ahs) { + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + goto error; + } + if (iscsi_sock_msg(sess->sock, 1, scsi_cmd->ahs_len, scsi_cmd->ahs, 0) != scsi_cmd->ahs_len) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + goto error; + } + if ((unsigned)iscsi_sock_msg(sess->sock, 1, scsi_cmd->length, sg_copy, sg_len_copy) != scsi_cmd->length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + goto error; + } + } else { + if ((unsigned)iscsi_sock_send_header_and_data(sess->sock, header, ISCSI_HEADER_LEN, sg_copy, scsi_cmd->length, sg_len_copy) + != ISCSI_HEADER_LEN + scsi_cmd->length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + goto error; + } + } + scsi_cmd->bytes_sent += scsi_cmd->length; + } else { + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + goto error; + } + if (scsi_cmd->ahs_len) { + if (iscsi_sock_msg(sess->sock, 1, scsi_cmd->ahs_len, scsi_cmd->ahs, 0) != scsi_cmd->ahs_len) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + goto error; + } + } + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "command PDU sent with %u bytes immediate data (%u bytes AHS)\n", scsi_cmd->length, scsi_cmd->ahs_len); + + /* + * Send data PDUS if 1) we're not in R2T mode and 2) we + * haven't sent everything as immediate data and 3) we have + * not reached the first burst when sending immediate data + */ + if (scsi_cmd->output + && (!sess->sess_params.initial_r2t) + && (scsi_cmd->bytes_sent != scsi_cmd->trans_len) + && ((!sess->sess_params.first_burst_length) + || (scsi_cmd->bytes_sent < sess->sess_params.first_burst_length))) { + + uint32_t DataSN = 0; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "preparing to send %d bytes write data\n", scsi_cmd->trans_len - scsi_cmd->bytes_sent); + + do { + (void) memset(&data, 0x0, sizeof(data)); + + /* + * Take into account that MaxRecvPDULength and + * FirstBurstLength could both be "0" (no limit) + */ + if (sess->sess_params.max_data_seg_length) { + if (sess->sess_params.first_burst_length) { + data.length = MIN_3( + sess->sess_params.first_burst_length - scsi_cmd->bytes_sent, + sess->sess_params.max_data_seg_length, + scsi_cmd->trans_len - scsi_cmd->bytes_sent); + } else { + data.length = MIN( + sess->sess_params.max_data_seg_length, + scsi_cmd->trans_len - scsi_cmd->bytes_sent); + } + } else { + if (sess->sess_params.first_burst_length) { + data.length = MIN( + sess->sess_params.first_burst_length - scsi_cmd->bytes_sent, + scsi_cmd->trans_len - scsi_cmd->bytes_sent); + } else { + data.length = scsi_cmd->trans_len - scsi_cmd->bytes_sent; + } + } +#define FRAG_CLEANUP {if (fragment_flag) iscsi_free_atomic(sg_copy);} + RETURN_EQUAL("data.length", data.length, 0, FRAG_CLEANUP, -1); + + if (scsi_cmd->bytes_sent + data.length == scsi_cmd->trans_len) + data.final = 1; + data.tag = scsi_cmd->tag; + data.transfer_tag = 0xffffffff; + data.ExpStatSN = sess->ExpStatSN; + data.DataSN = DataSN++; + data.offset = scsi_cmd->bytes_sent; + + if (iscsi_write_data_encap(header, &data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_write_data_encap() failed\n"); + goto error; + } + if (data.length != scsi_cmd->trans_len) { + + /* + * Make copy of iovec and modify with offset + * and length + */ + + if (!fragment_flag) { + if ((sg_copy = iscsi_malloc_atomic(sg_len * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto error; + } + sg_copy_orig = sg_copy; + fragment_flag++; + } + sg_copy = sg_copy_orig; + memcpy(sg_copy, sg, sizeof(struct iovec) * sg_len); + sg_len_copy = sg_len; + if (modify_iov(&sg_copy, &sg_len_copy, scsi_cmd->bytes_sent, data.length) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + goto error; + } + sg_which = sg_copy; + sg_len_which = sg_len_copy; + + } else { + + /* + * Data was not fragmented; use the original + * iovec. + */ + + sg_which = sg; + sg_len_which = sg_len; + } + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending write data PDU (offset %u, len %u, sg_len %u)\n", + data.offset, data.length, sg_len_which); + + if ((unsigned)iscsi_sock_send_header_and_data(sess->sock, header, ISCSI_HEADER_LEN, sg_which, data.length, sg_len_which) + != ISCSI_HEADER_LEN + data.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + goto error; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sent write data PDU (offset %u, len %u)\n", data.offset, data.length); + scsi_cmd->bytes_sent += data.length; + } while ((scsi_cmd->bytes_sent < scsi_cmd->trans_len) + && ((scsi_cmd->bytes_sent < sess->sess_params.first_burst_length) + || (!sess->sess_params.first_burst_length))); + if (scsi_cmd->trans_len - scsi_cmd->bytes_sent) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "REACHED FIRST BURST\n"); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully sent %u of %u bytes write data\n", scsi_cmd->bytes_sent, scsi_cmd->trans_len); + } + if (scsi_cmd->output && (scsi_cmd->trans_len - scsi_cmd->bytes_sent)) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "expecting R2T for remaining %u bytes write data\n", scsi_cmd->trans_len - scsi_cmd->bytes_sent); + } + if (fragment_flag) + iscsi_free_atomic(sg_copy_orig); + sess->CmdSN++; + + return 0; + +error: + if (fragment_flag) + iscsi_free_atomic(sg_copy); + return -1; +} + +static int +reject_i(initiator_session_t * sess, uint8_t *header) +{ + initiator_cmd_t *cmd = NULL; + iscsi_reject_t reject; + uint8_t bad_header[ISCSI_HEADER_LEN]; + uint32_t tag; + + /* Get & check args */ + + if (iscsi_reject_decap(header, &reject) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_reject_decap() failed\n"); + return -1; + } + RETURN_NOT_EQUAL("reject.length", reject.length, ISCSI_HEADER_LEN, NO_CLEANUP, -1); + + /* Read bad header, extract tag, and get cmd from hash table */ + + if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, bad_header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + tag = ISCSI_NTOHL(*((uint32_t *) (bad_header + 16))); + iscsi_trace_error(__FILE__, __LINE__, "REJECT PDU: tag %#x (reason %#x)\n", tag, reject.reason); + if (tag != 0xffffffff) { + if ((cmd = hash_remove(&g_tag_hash, tag)) == NULL) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no cmd ptr associated with tag %#x\n", tag); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "cmd %p associated with tag %#x\n", cmd, tag); + ISCSI_LOCK(&sess->rx_worker.work_mutex, return -1); + if (!cmd->tx_done) + ISCSI_WAIT(&sess->rx_worker.work_cond, &sess->rx_worker.work_mutex, return -1); + ISCSI_UNLOCK(&sess->rx_worker.work_mutex, return -1); + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "no command associated with tag %#x\n", tag); + } + + /* Execute callback to complete initiator_cmd_t */ + + if (cmd) { + cmd->status = -1; + if (cmd->callback) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "issuing callback for cmd associated with tag %#x\n", tag); + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + return -1; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "no callback associated with tag %#x\n", tag); + } + } + return 0; +} + +static int +async_msg_i(initiator_session_t * sess, uint8_t *header) +{ + iscsi_async_msg_t msg; + + /* Get & check args */ + if (iscsi_amsg_decap(header, &msg) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_amsg_decap() failed\n"); + return -1; + } + sess->CmdSN = msg.ExpCmdSN; + sess->MaxCmdSN = msg.MaxCmdSN; + sess->ExpStatSN = msg.StatSN + 1; + + /* Read Sense Data */ + if (msg.length) { + uint8_t *sense_data = NULL; + if ((sense_data = iscsi_malloc(msg.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %d bytes sense data \n", msg.length); + if ((unsigned)iscsi_sock_msg(sess->sock, 0, msg.length, sense_data, 0) != msg.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + if (sense_data != NULL) + iscsi_free(sense_data); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "read %d bytes sense data ok (currently discarding)\n", msg.length); + if (sense_data != NULL) + iscsi_free(sense_data); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no sense data available\n"); + } + + switch (msg.AsyncEvent) { + case 0: + /* Ignore SCSI asyn messages for now */ + break; + case 1: + case 4: + /* Ignore Parameter Negotiation. Send Logout */ + logout_phase_i(sess); + /* FALLTHROUGH */ + case 2: + case 3: + if (iscsi_sock_shutdown(sess->sock, 1) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_shutdown() failed\n"); + } + return -1; + case 255: + break; + default: + break; + } + + return 0; +} + +static int +nop_in_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_nop_out_args_t *nop_out = NULL; + iscsi_nop_in_args_t nop_in; + uint8_t *ping_data = NULL; + unsigned i; + + if (cmd) { + nop_out = (iscsi_nop_out_args_t *) cmd->ptr; + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t associated with this NOP_IN\n"); + } + if (iscsi_nop_in_decap(header, &nop_in) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_nop_in() failed\n"); + return -1; + } + if (cmd) + RETURN_NOT_EQUAL("nop_in.length", nop_in.length, nop_out->length, NO_CLEANUP, -1); + if (nop_in.length) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %d bytes ping data\n", nop_in.length); + if ((ping_data = iscsi_malloc_atomic(nop_in.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } +#define NOI_CLEANUP {if (ping_data) iscsi_free_atomic(ping_data);} +#define NOI_ERROR {NOI_CLEANUP; return -1;} + if ((unsigned)iscsi_sock_msg(sess->sock, 0, nop_in.length, ping_data, 0) != nop_in.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + NOI_ERROR; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully read %d bytes ping data\n", nop_in.length); + if (cmd) { + for (i = 0; i < nop_in.length; i++) { + if (nop_out->data[i] != ping_data[i]) { + iscsi_trace_error(__FILE__, __LINE__, "Bad ping data[%d]. Got %#x, expected %#x\n", i, ping_data[i], nop_out->data[i]); + NOI_ERROR; + } + } + } + } + /* Send ping response (if initiated by target) */ + + if (nop_in.transfer_tag != 0xffffffff) { + + uint8_t nop_header[ISCSI_HEADER_LEN]; + iscsi_nop_out_args_t nop_out_args; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending %d byte ping response\n", nop_in.length); + (void) memset(&nop_out_args, 0x0, sizeof(nop_out_args)); + nop_out_args.tag = 0xffffffff; + nop_out_args.immediate = 0x40; + nop_out_args.transfer_tag = nop_in.transfer_tag; + nop_out_args.length = nop_in.length; + nop_out_args.lun = nop_in.lun; + nop_out_args.ExpStatSN = sess->ExpStatSN; + nop_out_args.CmdSN = sess->CmdSN; + if (iscsi_nop_out_encap(nop_header, &nop_out_args) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_nop_out_encap() failed\n"); + NOI_ERROR; + } + if ((unsigned)iscsi_sock_send_header_and_data(sess->sock, nop_header, nop_out_args.length, ping_data, nop_in.length, 0) != nop_in.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + NOI_ERROR; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully sent %d byte ping response\n", nop_in.length); + } + NOI_CLEANUP; + /* Check and update numbering */ + sess->ExpStatSN = nop_in.StatSN + 1; + /* + * RETURN_NOT_EQUAL("StatSN", nop_in.StatSN, sess->ExpStatSN++, + * NO_CLEANUP, -1); + */ + sess->CmdSN = nop_in.ExpCmdSN; + /* + * RETURN_NOT_EQUAL("ExpCmdSN", nop_in.ExpCmdSN, sess->CmdSN, + * NO_CLEANUP, -1); + */ + sess->MaxCmdSN = nop_in.MaxCmdSN; + + /* Callback */ + + if (cmd) { + cmd->status = 0; + if (cmd->callback) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "NOP_OUT_T done (cmd status %d)\n", cmd->status); + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + return -1; + } + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no callback associated with NOP_IN_T??\n"); + return -1; + } + } + return 0; +} + +static int +scsi_r2t_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_r2t_t r2t; + iscsi_scsi_cmd_args_t *scsi_cmd; + iscsi_write_data_t data; + uint32_t bytes_sent; + uint32_t DataSN; + struct iovec sg_singleton; + struct iovec *sg, *sg_copy, *sg_copy_orig, *sg_which; + int sg_len, sg_len_copy, sg_len_which; + int fragment_flag; + + /* Make sure an initiator_cmd_t was specified, that it has a + * callback function specified and that it also has a + * iscsi_scsi_cmd_args_t associated with it. */ + + if (cmd) { + if ((scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no iscsi_scsi_cmd_args_t associated with this initiator_cmd_t??\n"); + return -1; + } else if (cmd->callback == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no callback associated with this initiator_cmd_t??\n"); + return -1; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t associated with this iscsi_r2t_t??\n"); + return -1; + } + + sg = sg_copy = sg_copy_orig = sg_which = NULL; + sg_len = sg_len_copy = sg_len_which = 0; + if (iscsi_r2t_decap(header, &r2t) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_r2t_decap() failed\n"); + return -1; + } + /* Check args */ + + RETURN_EQUAL("r2t.length", r2t.length, 0, NO_CLEANUP, -1); + + /* Check and update numbering */ + + RETURN_NOT_EQUAL("StatSN", r2t.StatSN, sess->ExpStatSN, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("ExpCmdSN", r2t.ExpCmdSN, sess->CmdSN, NO_CLEANUP, -1); + sess->MaxCmdSN = r2t.MaxCmdSN; + + /* Send back requested data */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending %d bytes R2T write data (offset %u)\n", r2t.length, r2t.offset); + if (scsi_cmd->send_sg_len) { + sg = (struct iovec *) scsi_cmd->send_data; + sg_len = scsi_cmd->send_sg_len; + } else { + sg_singleton.iov_base = scsi_cmd->send_data; + sg_singleton.iov_len = scsi_cmd->trans_len; + sg = &sg_singleton; + sg_len = 1; + } + fragment_flag = 0; + bytes_sent = 0; + DataSN = 0; +#define FF_CLEANUP {if (fragment_flag) iscsi_free_atomic(sg_copy_orig);} + do { + (void) memset(&data, 0x0, sizeof(data)); + if (sess->sess_params.max_data_seg_length) { + data.length = MIN(sess->sess_params.max_data_seg_length, + r2t.length - bytes_sent); + } else { + data.length = r2t.length - bytes_sent; + } + if (bytes_sent + data.length == r2t.length) { + data.final = 1; + } + data.tag = r2t.tag; + data.transfer_tag = r2t.transfer_tag; + data.ExpStatSN = sess->ExpStatSN; + data.DataSN = DataSN++; + data.offset = r2t.offset + bytes_sent; + data.lun = scsi_cmd->lun; + if (iscsi_write_data_encap(header, &data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_write_data_encap() failed\n"); + FF_CLEANUP; + return -1; + } + if ((data.length < r2t.length) || (r2t.offset)) { + if (data.length < r2t.length) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "R2T data is being fragmented: sending %u bytes of %u requested\n", + data.length, r2t.length); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "R2T data starts at offset %u, desired length %u\n", + r2t.offset, r2t.length); + } + + /* Allocate space for a copy of the original iovec */ + + if (!fragment_flag) { + if ((sg_copy_orig = iscsi_malloc_atomic(sg_len * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + fragment_flag++; + } + /* + * Copy and modify original iovec with new offset and + * length + */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "modifying original iovec with offset %u length %u\n", + r2t.offset + bytes_sent, data.length); + sg_copy = sg_copy_orig; + sg_len_copy = sg_len; + memcpy(sg_copy, sg, sizeof(struct iovec) * sg_len); + if (modify_iov(&sg_copy, &sg_len_copy, r2t.offset + bytes_sent, data.length) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + FF_CLEANUP; + return -1; + } + sg_which = sg_copy; + sg_len_which = sg_len_copy; + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "using original iovec for R2T transfer (offset %u, length %u)\n", + r2t.offset, r2t.length); + sg_which = sg; + sg_len_which = sg_len; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending R2T write data PDU (offset %u, len %u, sg_len %u)\n", + data.offset, data.length, sg_len_which); + if ((unsigned)iscsi_sock_send_header_and_data(sess->sock, header, ISCSI_HEADER_LEN, sg_which, data.length, sg_len_which) + != ISCSI_HEADER_LEN + data.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + FF_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sent write data PDU OK (offset %u, len %u)\n", data.offset, data.length); + bytes_sent += data.length; + scsi_cmd->bytes_sent += data.length; + } while (bytes_sent < r2t.length); + FF_CLEANUP; + if (hash_insert(&g_tag_hash, cmd, scsi_cmd->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + return -1; + } + return 0; +} + +static int +scsi_response_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_scsi_cmd_args_t *scsi_cmd; + iscsi_scsi_rsp_t scsi_rsp; + + /* Make sure an initiator_cmd_t was specified, that it has a + * callback function specified and that it also has a + * iscsi_scsi_cmd_args_t associated with it. */ + + if (cmd) { + if ((scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no iscsi_scsi_cmd_args_t associated with this initiator_cmd_t??\n"); + return -1; + } else if (cmd->callback == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no callback associated with this initiator_cmd_t??\n"); + return -1; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t associated with this iscsi_scsi_rsp_t??\n"); + return -1; + } + + /* + * Read SCSI response and check return args. Those marked + * "FIX ME" are not yet implemented. */ + + if (iscsi_scsi_rsp_decap(header, &scsi_rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_scsi_rsp_decap() failed\n"); + return -1; + } + RETURN_NOT_EQUAL("o bit (FIX ME)", scsi_rsp.bidi_overflow, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("u bit (FIX ME)", scsi_rsp.bidi_underflow, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("O bit (FIX ME)", scsi_rsp.overflow, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("iSCSI Response (FIX ME)", scsi_rsp.response, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Tag", scsi_rsp.tag, scsi_cmd->tag, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Bidi Residual Count", scsi_rsp.bidi_res_cnt, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("StatSN", scsi_rsp.StatSN, sess->ExpStatSN, NO_CLEANUP, -1); + sess->ExpStatSN = scsi_rsp.StatSN + 1; + + if (sess->sess_params.max_data_seg_length) { + RETURN_GREATER("DataSegmentLength (FIX ME)", scsi_rsp.length, + sess->sess_params.max_data_seg_length, NO_CLEANUP, -1); + } + if ((scsi_rsp.status == 0) && (scsi_rsp.length != 0)) { + iscsi_trace_error(__FILE__, __LINE__, "Unexpected DataSegmentLength %u with GOOD SCSI status\n", scsi_rsp.length); + return -1; + } + /* + * Make sure all data was successfully transferred if command + * completed successfully, otherwise read sense data. */ + + if (scsi_rsp.status == 0) { + if (scsi_cmd->output) { + RETURN_NOT_EQUAL("scsi_cmd->bytes_sent", scsi_cmd->bytes_sent, scsi_cmd->trans_len, NO_CLEANUP, -1); + if (scsi_cmd->input) { + + RETURN_NOT_EQUAL("scsi_cmd->bytes_recv", scsi_cmd->bytes_recv, scsi_cmd->bidi_trans_len, NO_CLEANUP, -1); + } + } else if (scsi_cmd->input) { + + + } + } else if (scsi_rsp.length) { + uint8_t *sense_data = NULL; + + if ((sense_data = iscsi_malloc(scsi_rsp.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + iscsi_trace_error(__FILE__, __LINE__, "reading %d bytes sense data (recv_sg_len %u)\n", + scsi_rsp.length, scsi_cmd->recv_sg_len); + if ((unsigned)iscsi_sock_msg(sess->sock, 0, scsi_rsp.length, sense_data, 0) != scsi_rsp.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + if (sense_data != NULL) + iscsi_free(sense_data); + return -1; + } + iscsi_trace_error(__FILE__, __LINE__, "read %d bytes sense data ok (currently discarding)\n", scsi_rsp.length); + if (sense_data != NULL) + iscsi_free(sense_data); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no sense data available\n"); + } + + /* Check and update numbering */ + + /* + * RETURN_NOT_EQUAL("ExpCmdSN", scsi_rsp.ExpCmdSN, sess->CmdSN, + * NO_CLEANUP, -1); + */ + sess->MaxCmdSN = scsi_rsp.MaxCmdSN; + + /* Set initiator_cmd_t status, iscsi_scsi_cmd_args_t status */ + /* and execute callback function */ + + cmd->status = 0; + scsi_cmd->status = scsi_rsp.status; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "iscsi_scsi_cmd_args_t done (cmd status %d, iscsi status %d, scsi status %d)\n", + cmd->status, scsi_rsp.response, scsi_rsp.status); + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + return -1; + + } + return 0; +} + +static int +scsi_read_data_i(initiator_session_t * sess, initiator_cmd_t * cmd, uint8_t *header) +{ + iscsi_read_data_t data; + iscsi_scsi_cmd_args_t *scsi_cmd; + int rc; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "processing read data\n"); + + /* Make sure an initiator_cmd_t was specified, that it has a + * callback function specified and that it also has a + * iscsi_scsi_cmd_args_t associated with it. */ + + if (cmd) { + if (cmd->type != ISCSI_SCSI_CMD) { + iscsi_trace_error(__FILE__, __LINE__, "Invalid response from target for cmd type (%#x)\n", cmd->type); + cmd->status = -1; + if (cmd->callback) { + (*cmd->callback)(cmd); + } + return -1; + } + if ((scsi_cmd = (iscsi_scsi_cmd_args_t *) cmd->ptr) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no iscsi_scsi_cmd_args_t associated with this initiator_cmd_t??\n"); + return -1; + } else if (cmd->callback == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no callback associated with this initiator_cmd_t??\n"); + return -1; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "no initiator_cmd_t associated with this iscsi_read_data_t??\n"); + return -1; + } + if (iscsi_read_data_decap(header, &data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_scsi_rsp_decap() failed\n"); + return -1; + } + /* Check args */ + + RETURN_NOT_EQUAL("Overflow bit", data.overflow, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Underflow bit", data.underflow, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Tag", data.task_tag, scsi_cmd->tag, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Residual Count", data.res_count, 0, NO_CLEANUP, -1); + + if (sess->sess_params.max_data_seg_length) { + RETURN_GREATER("Length", data.length, sess->sess_params.max_data_seg_length, NO_CLEANUP, -1); + } + /* Check and update numbering */ + + WARN_NOT_EQUAL("ExpCmdSN", data.ExpCmdSN, sess->CmdSN); + sess->MaxCmdSN = data.MaxCmdSN; + + /* Need to optimize this section */ + + if (scsi_cmd->recv_sg_len) { + int sg_len = scsi_cmd->recv_sg_len; + struct iovec *sg; + struct iovec *sg_orig = NULL; + char *sgp; + uint32_t total_len, disp; + int i; + + if (data.length != scsi_cmd->trans_len) { + + /* Make a copy of the iovec */ + + if ((sg_orig = sg = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + + } + memcpy(sg, scsi_cmd->recv_data, sizeof(struct iovec) * sg_len); + + /* Find offset in iovecs */ + + total_len = 0; + disp = data.offset; + for (i = 0; i < sg_len; i++) { + total_len += sg[i].iov_len; + if (total_len > data.offset) { + break; + } + disp -= sg[i].iov_len; + } + sg[i].iov_len -= disp; + sgp = sg[i].iov_base; + sgp += disp; + sg[i].iov_base = sgp; + sg_len -= i; + sg = &sg[i]; + + /* Find last iovec needed for read */ + + total_len = 0; + for (i = 0; i < sg_len; i++) { + total_len += sg[i].iov_len; + if (total_len >= data.length) { + break; + } + } + sg[i].iov_len -= (total_len - data.length); + sg_len = i + 1; + } else { + sg = (struct iovec *) scsi_cmd->recv_data; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %d bytes into sg buffer (total offset %u)\n", data.length, data.offset); + if ((rc = iscsi_sock_msg(sess->sock, 0, data.length, (uint8_t *) sg, sg_len)) != (int)data.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed: got %u, expected %u\n", rc, data.length); + if (sg_orig) + iscsi_free_atomic(sg_orig); + return -1; + } + scsi_cmd->bytes_recv += data.length; + if (sg_orig) + iscsi_free_atomic(sg_orig); + } else { + if (data.length) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %d bytes into dest buffer (offset %u)\n", data.length, data.offset); + if (iscsi_sock_msg(sess->sock, 0, data.length, scsi_cmd->recv_data + data.offset, 0) != (int)data.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + scsi_cmd->bytes_recv += data.length; + } + } + + + /* Check for status */ + + if (data.S_bit) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "received status with final PDU\n"); + RETURN_NOT_EQUAL("Final Bit", data.final, 1, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("StatSN", data.StatSN, sess->ExpStatSN++, NO_CLEANUP, -1); + scsi_cmd->status = data.status = 0; + cmd->status = 0; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "scsi op %#x done (tag %u, status %d)\n", scsi_cmd->cdb[0], scsi_cmd->tag, scsi_cmd->status); + if ((*cmd->callback)(cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "callback() failed\n"); + return -1; + } + } else { + if (hash_insert(&g_tag_hash, cmd, scsi_cmd->tag) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_insert() failed\n"); + return -1; + } + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "read data processed\n"); + return 0; +} + +int +initiator_info(char *ptr, int size, int len) +{ + initiator_session_t *sess; + int i; + + ptr[0] = 0x0; + len += snprintf(ptr, size - len, " %3s %30s %25s\n\n", "TID", "TargetName", "TargetAddress"); + for (i = 0; i < CONFIG_INITIATOR_NUM_TARGETS; i++) { + len += snprintf(ptr + len, size - len, " %3i %30s %20s:%d (", + i, g_target[i].TargetName, g_target[i].ip, g_target[i].port); + if (g_target[i].has_session) { + sess = g_target[i].sess; + if (sess->state & INITIATOR_SESSION_STATE_INITIALIZING) + len += snprintf(ptr + len, size - len, "%s", "initializing"); + if (sess->state & INITIATOR_SESSION_STATE_INITIALIZED) + len += snprintf(ptr + len, size - len, "%s", "initialized"); + if (sess->state & INITIATOR_SESSION_STATE_CONNECTING) + len += snprintf(ptr + len, size - len, "%s", "connecting"); + if (sess->state & INITIATOR_SESSION_STATE_CONNECTED) + len += snprintf(ptr + len, size - len, "%s", "connected"); + if (sess->state & INITIATOR_SESSION_STATE_LOGGING_IN) + len += snprintf(ptr + len, size - len, "%s", "logging in"); + if (sess->state & INITIATOR_SESSION_STATE_LOGGED_IN_NORMAL) + len += snprintf(ptr + len, size - len, "%s", "Normal session"); + if (sess->state & INITIATOR_SESSION_STATE_LOGGED_IN_DISCOVERY) + len += snprintf(ptr + len, size - len, "%s", "Discovery session"); + if (sess->state & INITIATOR_SESSION_STATE_LOGGING_OUT) + len += snprintf(ptr + len, size - len, "%s", "logging out"); + if (sess->state & INITIATOR_SESSION_STATE_LOGGED_OUT) + len += snprintf(ptr + len, size - len, "%s", "logged out"); + if (sess->state & INITIATOR_SESSION_STATE_DESTROYING) + len += snprintf(ptr + len, size - len, "%s", "destroying"); + if (sess->tx_worker.state & ISCSI_WORKER_STATE_ERROR) + len += snprintf(ptr + len, size - len, "%s", " **Tx Error** "); + if (sess->rx_worker.state & ISCSI_WORKER_STATE_ERROR) + len += snprintf(ptr + len, size - len, "%s", " **Rx Error** "); + } else { + len += snprintf(ptr + len, size - len, "%s", "No Session"); + } + len += snprintf(ptr + len, size - len, ")\n"); + } + return len; +} + +int +initiator_discover(char *host, uint64_t target, int lun) +{ + iscsi_nop_out_args_t discover_cmd; + initiator_cmd_t cmd; + + cmd.type = ISCSI_NOP_OUT; + cmd.ptr = &discover_cmd; + cmd.isid = target; + (void) strlcpy(cmd.targetname, host, sizeof(cmd.targetname)); + (void) memset(&discover_cmd, 0x0, sizeof(iscsi_nop_out_args_t)); + discover_cmd.length = 1; + discover_cmd.data = (const uint8_t *) ""; + discover_cmd.lun = lun; + discover_cmd.tag = 0xffffffff; + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + return 0; +} + +void +get_target_info(uint64_t target, initiator_target_t *ip) +{ + (void) memcpy(ip, &g_target[target], sizeof(*ip)); +} + +int +ii_initiator_init(const char *hostname, int port, int address_family, const char *user, char *lun, int auth_type, int mutual_auth, int digest_type) +{ + initiator_session_t *sess = NULL; + +#define INIT_CLEANUP {if (sess != NULL) iscsi_free_atomic(sess);} +#define INIT_ERROR {INIT_CLEANUP; return -1;} + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initializing initiator\n"); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "target config filename to read from:%s\n", gfilename); + if (get_target_config(hostname, port) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "Error getting target configuration from config file\n"); + return -1; + } + (void) strlcpy(g_target[0].iqnwanted, lun, sizeof(g_target[0].iqnwanted)); + g_initiator_state = 0; + if (iscsi_queue_init(&g_session_q, CONFIG_INITIATOR_MAX_SESSIONS) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + return -1; + } + if ((sess = iscsi_malloc_atomic(sizeof(initiator_session_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + if (iscsi_queue_insert(&g_session_q, sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + INIT_CLEANUP; + return -1; + } + sess->sess_params.cred.user = strdup(user); + sess->sess_params.auth_type = auth_type; + sess->sess_params.mutual_auth = mutual_auth; + sess->sess_params.digest_wanted = digest_type; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "%d free sessions available\n", CONFIG_INITIATOR_MAX_SESSIONS); + + g_tag = 0xabc123; + if (hash_init(&g_tag_hash, CONFIG_INITIATOR_QUEUE_DEPTH) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "hash_init() failed\n"); + INIT_CLEANUP; + return -1; + } + iscsi_spin_init(&g_tag_spin); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "tag hash table initialized with queue depth %d\n", CONFIG_INITIATOR_QUEUE_DEPTH); + + /* + * Start enqueue worker. This thread accepts scsi commands + * from initiator_enqueue() and queues them onto one of the tx + * worker queues. + */ + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "starting enqueue worker\n"); + if (iscsi_queue_init(&g_enqueue_q, CONFIG_INITIATOR_QUEUE_DEPTH) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + INIT_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "about to initialize mutex\n"); + ISCSI_MUTEX_INIT(&g_enqueue_worker.work_mutex, INIT_ERROR); + ISCSI_COND_INIT(&g_enqueue_worker.work_cond, INIT_ERROR); + ISCSI_MUTEX_INIT(&g_enqueue_worker.exit_mutex, INIT_ERROR); + ISCSI_COND_INIT(&g_enqueue_worker.exit_cond, INIT_ERROR); + ISCSI_LOCK(&g_enqueue_worker.exit_mutex, INIT_ERROR); + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "spawning thread for enqueue worker\n"); + if (iscsi_thread_create(&g_enqueue_worker.thread, (void *) &enqueue_worker_proc, &g_enqueue_worker) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_threads_create() failed\n"); + INIT_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "thread spawned, waiting for signal\n"); + ISCSI_WAIT(&g_enqueue_worker.exit_cond, &g_enqueue_worker.exit_mutex, INIT_ERROR); + ISCSI_UNLOCK(&g_enqueue_worker.exit_mutex, INIT_ERROR); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully started enqueue worker\n"); + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "initiator initialization complete\n"); + return 0; +} diff --git a/external/bsd/iscsi/dist/src/install-sh b/external/bsd/iscsi/dist/src/install-sh new file mode 100755 index 000000000000..89fc9b098b8c --- /dev/null +++ b/external/bsd/iscsi/dist/src/install-sh @@ -0,0 +1,238 @@ +#! /bin/sh +# +# install - install a program, script, or datafile +# This comes from X11R5. +# +# Calling this script install-sh is preferred over install.sh, to prevent +# `make' implicit rules from creating a file called install from it +# when there is no Makefile. +# +# This script is compatible with the BSD install script, but was written +# from scratch. +# + + +# set DOITPROG to echo to test this script + +# Don't use :- since 4.3BSD and earlier shells don't like it. +doit="${DOITPROG-}" + + +# put in absolute paths if you don't have them in your path; or use env. vars. + +mvprog="${MVPROG-mv}" +cpprog="${CPPROG-cp}" +chmodprog="${CHMODPROG-chmod}" +chownprog="${CHOWNPROG-chown}" +chgrpprog="${CHGRPPROG-chgrp}" +stripprog="${STRIPPROG-strip}" +rmprog="${RMPROG-rm}" +mkdirprog="${MKDIRPROG-mkdir}" + +tranformbasename="" +transform_arg="" +instcmd="$mvprog" +chmodcmd="$chmodprog 0755" +chowncmd="" +chgrpcmd="" +stripcmd="" +rmcmd="$rmprog -f" +mvcmd="$mvprog" +src="" +dst="" +dir_arg="" + +while [ x"$1" != x ]; do + case $1 in + -c) instcmd="$cpprog" + shift + continue;; + + -d) dir_arg=true + shift + continue;; + + -m) chmodcmd="$chmodprog $2" + shift + shift + continue;; + + -o) chowncmd="$chownprog $2" + shift + shift + continue;; + + -g) chgrpcmd="$chgrpprog $2" + shift + shift + continue;; + + -s) stripcmd="$stripprog" + shift + continue;; + + -t=*) transformarg=`echo $1 | sed 's/-t=//'` + shift + continue;; + + -b=*) transformbasename=`echo $1 | sed 's/-b=//'` + shift + continue;; + + *) if [ x"$src" = x ] + then + src=$1 + else + # this colon is to work around a 386BSD /bin/sh bug + : + dst=$1 + fi + shift + continue;; + esac +done + +if [ x"$src" = x ] +then + echo "install: no input file specified" + exit 1 +else + true +fi + +if [ x"$dir_arg" != x ]; then + dst=$src + src="" + + if [ -d $dst ]; then + instcmd=: + else + instcmd=mkdir + fi +else + +# Waiting for this to be detected by the "$instcmd $src $dsttmp" command +# might cause directories to be created, which would be especially bad +# if $src (and thus $dsttmp) contains '*'. + + if [ -f $src -o -d $src ] + then + true + else + echo "install: $src does not exist" + exit 1 + fi + + if [ x"$dst" = x ] + then + echo "install: no destination specified" + exit 1 + else + true + fi + +# If destination is a directory, append the input filename; if your system +# does not like double slashes in filenames, you may need to add some logic + + if [ -d $dst ] + then + dst="$dst"/`basename $src` + else + true + fi +fi + +## this sed command emulates the dirname command +dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'` + +# Make sure that the destination directory exists. +# this part is taken from Noah Friedman's mkinstalldirs script + +# Skip lots of stat calls in the usual case. +if [ ! -d "$dstdir" ]; then +defaultIFS=' +' +IFS="${IFS-${defaultIFS}}" + +oIFS="${IFS}" +# Some sh's can't handle IFS=/ for some reason. +IFS='%' +set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'` +IFS="${oIFS}" + +pathcomp='' + +while [ $# -ne 0 ] ; do + pathcomp="${pathcomp}${1}" + shift + + if [ ! -d "${pathcomp}" ] ; + then + $mkdirprog "${pathcomp}" + else + true + fi + + pathcomp="${pathcomp}/" +done +fi + +if [ x"$dir_arg" != x ] +then + $doit $instcmd $dst && + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi +else + +# If we're going to rename the final executable, determine the name now. + + if [ x"$transformarg" = x ] + then + dstfile=`basename $dst` + else + dstfile=`basename $dst $transformbasename | + sed $transformarg`$transformbasename + fi + +# don't allow the sed command to completely eliminate the filename + + if [ x"$dstfile" = x ] + then + dstfile=`basename $dst` + else + true + fi + +# Make a temp file name in the proper directory. + + dsttmp=$dstdir/#inst.$$# + +# Move or copy the file name to the temp name + + $doit $instcmd $src $dsttmp && + + trap "rm -f ${dsttmp}" 0 && + +# and set any options; do chmod last to preserve setuid bits + +# If any of these fail, we abort the whole thing. If we want to +# ignore errors from any of these, just make sure not to ignore +# errors from the above "$doit $instcmd $src $dsttmp" command. + + if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi && + if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi && + if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi && + if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi && + +# Now rename the file to the real destination. + + $doit $rmcmd -f $dstdir/$dstfile && + $doit $mvcmd $dsttmp $dstdir/$dstfile + +fi && + + +exit 0 diff --git a/external/bsd/iscsi/dist/src/iscsi-harness.c b/external/bsd/iscsi/dist/src/iscsi-harness.c new file mode 100644 index 000000000000..f990aee63121 --- /dev/null +++ b/external/bsd/iscsi/dist/src/iscsi-harness.c @@ -0,0 +1,219 @@ +/* + * Copyright © 2007 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#define EXTERN + +#include +#include + +#ifdef HAVE_PWD_H +#include +#endif + +#include +#include +#include + + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#include "scsi_cmd_codes.h" + +#include "iscsi.h" +#include "initiator.h" +#include "tests.h" + + +int +main(int argc, char **argv) +{ + struct sigaction act; + struct passwd *pwp; + char hostname[1024]; + char lun[1024]; + char *host; + char *user; + int address_family; + int port; + int digest_type; + int mutual_auth; + int iterations; + int auth_type; + int i; + + /* Check args */ + + user = NULL; + (void) gethostname(host = hostname, sizeof(hostname)); + digest_type = DigestNone; + auth_type = AuthNone; + address_family = ISCSI_UNSPEC; + port = ISCSI_PORT; + mutual_auth = 0; + lun[0] = 0x0; + iterations = 1; + + while ((i = getopt(argc, argv, "46a:d:h:n:p:t:u:V")) != -1) { + switch(i) { + case '4': + address_family = ISCSI_IPv4; + break; + case '6': + address_family = ISCSI_IPv6; + break; + case 'a': + if (strcasecmp(optarg, "chap") == 0) { + auth_type = AuthCHAP; + } else if (strcasecmp(optarg, "kerberos") == 0) { + auth_type = AuthKerberos; + } else if (strcasecmp(optarg, "srp") == 0) { + auth_type = AuthSRP; + } + break; + case 'd': + if (strcasecmp(optarg, "header") == 0) { + digest_type = DigestHeader; + } else if (strcasecmp(optarg, "data") == 0) { + digest_type = DigestData; + } else if (strcasecmp(optarg, "both") == 0 || strcasecmp(optarg, "all") == 0) { + digest_type = (DigestHeader | DigestData); + } + break; + case 'h': + host = optarg; + break; + case 'n': + iterations = atoi(optarg); + break; + case 'p': + port = atoi(optarg); + break; + case 't': + (void) strlcpy(lun, optarg, sizeof(lun)); + break; + case 'u': + user = optarg; + break; + case 'V': + (void) printf("\"%s\" %s\nPlease send all bug reports to %s\n", PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_BUGREPORT); + exit(EXIT_SUCCESS); + /* NOTREACHED */ + default: + (void) fprintf(stderr, "%s: unknown option `%c'", *argv, i); + } + } + + if (user == NULL) { + if ((pwp = getpwuid(geteuid())) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "can't find user information\n"); + exit(EXIT_FAILURE); + } + user = pwp->pw_name; + } + + if (argc == 1) { + (void) fprintf(stderr, "usage: %s [-4] [-6] [-V] [-a auth-type] [-d digest-type] [-h hostname] [-l lun] [-p port] [-t target] [-u user]\n", *argv); + exit(EXIT_FAILURE); + } + + /* Ignore sigpipe */ + + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + + for (i = 0 ; i < iterations ; i++) { + /* Initialize Initiator */ + if (ii_initiator_init(host, port, address_family, user, lun, auth_type, mutual_auth, digest_type) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_init() failed\n"); + return -1; + } + /* Run tests for target */ + + if (ii_test_all() != 0) { + iscsi_trace_error(__FILE__, __LINE__, "test_all() failed\n"); + return -1; + } + + /* Shutdown Initiator */ + + if (initiator_shutdown() == -1) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_shutdown() failed\n"); + return -1; + } + } + + printf("\n"); + printf("************************************\n"); + printf("* ALL TESTS COMPLETED SUCCESSFULLY *\n"); + printf("************************************\n"); + printf("\n"); + + exit(EXIT_SUCCESS); +} diff --git a/external/bsd/iscsi/dist/src/iscsi-target.8 b/external/bsd/iscsi/dist/src/iscsi-target.8 new file mode 100644 index 000000000000..6f778769c1d8 --- /dev/null +++ b/external/bsd/iscsi/dist/src/iscsi-target.8 @@ -0,0 +1,124 @@ +.\" $NetBSD: iscsi-target.8,v 1.1 2009/06/21 21:20:31 agc Exp $ +.\" +.\" Copyright © 2006 Alistair Crooks. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. 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. +.\" +.Dd May 27, 2006 +.Dt ISCSI-TARGET 8 +.Os +.Sh NAME +.Nm iscsi-target +.Nd service remote iSCSI requests +.Sh SYNOPSIS +.Nm +.Op Fl 46DV +.Op Fl b Ar block length +.Op Fl f Ar configuration file +.Op Fl p Ar port number +.Op Fl s Ar maximum number of sessions +.Op Fl t Ar target name +.Op Fl v Ar verbose arg +.Sh DESCRIPTION +.Nm +is the server for +iSCSI +requests from iSCSI initiators. +.Nm +listens for discovery and login requests on the required port, +and responds to those requests appropriately. +.Pp +Options and operands available for +.Nm iscsi-target : +.Bl -tag -width Ds +.It Fl 4 +.Nm +will listen for IPv4 connections, +and respond back using IPv4. +This is the default address family. +.It Fl 6 +.Nm +will listen for IPv6 connections, +and respond back using IPv6. +.It Fl b Ar blocksize +Specify the underlying block size for iSCSI storage which will be served. +The possible sizes are: 512, 1024, 2048, and 4096 bytes, with the default +being 512 bytes. +.It Fl D +When this option is specified, +.Nm +will not detach itself from the controlling tty, and will +not become a daemon. +This can be useful for debugging purposes. +.It Fl f Ar configfile +Use the named file as the configuration file. +The default file can be found in +.Ar /etc/iscsi/targets . +See +.Xr targets 5 +for more information. +.It Fl p Ar port number +Use the port number provided as the argument as the port +on which to listen for iSCSI service requests from +initiators. +.It Fl s Ar maximum number of sessions +Allow the maximum number of sessions to be initiated when +connecting to the target. +.It Fl t Ar filename +The target name (as it appears to the iSCSI initiator) can be specified +using this flag. +.It Fl V +.Nm +will print the utility name and version number, +and the address for bug reports, and then exit. +.It Fl v Ar argument +The amount of information shown can be varied by using this command. +Possible values of +.Ar argument +are +.Ar net +to show network-related information, +.Ar iscsi +to show iSCSI protocol-related information, +.Ar scsi +to show SCSI protocol information, and +.Ar all +to show information from all of the above arguments. +.El +.Sh FILES +.Bl -tag -width /var/run/iscsi-target.pid -compact +.It Pa /etc/iscsi/targets +the list of exported storage +.It Pa /var/run/iscsi-target.pid +the PID of the currently running +.Nm +.El +.Sh SEE ALSO +.Xr targets 5 +.Sh HISTORY +The +.Nm +utility first appeared in +.Nx 4.0 . diff --git a/external/bsd/iscsi/dist/src/iscsi-target.c b/external/bsd/iscsi/dist/src/iscsi-target.c new file mode 100644 index 000000000000..58156db0459d --- /dev/null +++ b/external/bsd/iscsi/dist/src/iscsi-target.c @@ -0,0 +1,166 @@ +/* $NetBSD: iscsi-target.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include "config.h" + +#define EXTERN + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include "iscsi.h" +#include "iscsiutil.h" +#include "target.h" +#include "device.h" + +#include "conffile.h" +#include "storage.h" + +static int g_main_pid; + +static globals_t g; + +int +main(int argc, char **argv) +{ + targv_t tv; + devv_t dv; + extv_t ev; + char TargetName[1024]; + int detach_me_harder; + int i; + + (void) memset(&g, 0x0, sizeof(g)); + (void) memset(&tv, 0x0, sizeof(tv)); + (void) memset(&dv, 0x0, sizeof(dv)); + (void) memset(&ev, 0x0, sizeof(ev)); + + /* set defaults */ + (void) strlcpy(TargetName, DEFAULT_TARGET_NAME, sizeof(TargetName)); + detach_me_harder = 1; + g.port = ISCSI_PORT; + g.address_family = ISCSI_UNSPEC; + g.max_sessions = DEFAULT_TARGET_MAX_SESSIONS; + + (void) strlcpy(g.config_file, _PATH_ISCSI_TARGETS, sizeof(g.config_file)); + + while ((i = getopt(argc, argv, "46b:Df:p:s:t:Vv:")) != -1) { + switch (i) { + case '4': + g.address_family = ISCSI_IPv4; + break; + case '6': + g.address_family = ISCSI_IPv6; + break; + case 'b': + device_set_var("blocklen", optarg); + break; + case 'D': + detach_me_harder = 0; + break; + case 'f': + (void) strlcpy(g.config_file, optarg, sizeof(g.config_file)); + break; + case 'p': + g.port = (uint16_t) atoi(optarg); + break; + case 's': + if ((g.max_sessions = atoi(optarg)) <= 0) { + g.max_sessions = DEFAULT_TARGET_MAX_SESSIONS; + } + break; + case 't': + (void) strlcpy(TargetName, optarg, sizeof(TargetName)); + break; + case 'V': + (void) printf("\"%s\" %s\nPlease send all bug reports to %s\n", PACKAGE_NAME, PACKAGE_VERSION, PACKAGE_BUGREPORT); + exit(EXIT_SUCCESS); + /* NOTREACHED */ + case 'v': + if (strcmp(optarg, "net") == 0) { + set_debug("net"); + } else if (strcmp(optarg, "iscsi") == 0) { + set_debug("iscsi"); + } else if (strcmp(optarg, "scsi") == 0) { + set_debug("scsi"); + } else if (strcmp(optarg, "all") == 0) { + set_debug("all"); + } + break; + } + } + + if (!read_conf_file(g.config_file, &tv, &dv, &ev)) { + (void) fprintf(stderr, "Error: can't open `%s'\n", g.config_file); + return EXIT_FAILURE; + } + + (void) signal(SIGPIPE, SIG_IGN); + + g_main_pid = ISCSI_GETPID; + + if (tv.c == 0) { + (void) fprintf(stderr, "No targets to initialise\n"); + return EXIT_FAILURE; + } + /* Initialize target */ + if (target_init(&g, &tv, TargetName) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_init() failed\n"); + exit(EXIT_FAILURE); + } + +#ifdef HAVE_DAEMON + /* if we are supposed to be a daemon, detach from controlling tty */ + if (detach_me_harder && daemon(0, 0) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "daemon() failed\n"); + exit(EXIT_FAILURE); + } +#endif + + /* write pid to a file */ + write_pid_file(_PATH_ISCSI_PID_FILE); + + /* Wait for connections */ + if (target_listen(&g) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_listen() failed\n"); + } + + return EXIT_SUCCESS; +} diff --git a/external/bsd/iscsi/dist/src/iscsi.c b/external/bsd/iscsi/dist/src/iscsi.c new file mode 100644 index 000000000000..7ac338ee65be --- /dev/null +++ b/external/bsd/iscsi/dist/src/iscsi.c @@ -0,0 +1,1378 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include "iscsi.h" +#include "iscsiutil.h" + + +/* + * Task Command + */ + +int +iscsi_task_cmd_encap(uint8_t *header, iscsi_task_cmd_t * cmd) +{ + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Function: %u\n", cmd->function); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Ref Tag: %#x\n", cmd->ref_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "RefCmdSN: %u\n", cmd->RefCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpDataSN: %u\n", cmd->ExpDataSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= ISCSI_TASK_CMD; /* Opcode */ + if (cmd->immediate) { + header[0] |= 0x40; /* Immediate bit */ + } + header[1] = cmd->function & 0x80; /* Function */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->ref_tag); /* Reference Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN); /* CmdSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->RefCmdSN); /* RefCmdSN */ + *((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->ExpDataSN); /* ExpDataSN */ + + return 0; +} + +int +iscsi_task_cmd_decap(uint8_t *header, iscsi_task_cmd_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_TASK_CMD, NO_CLEANUP, -1); + + cmd->immediate = ((header[0] & 0x40) == 0x40); /* Immediate bit */ + cmd->function = header[1] & 0x80; /* Function */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->ref_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Reference Tag */ + cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* CmdSN */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + cmd->RefCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* RefCmdSN */ + cmd->ExpDataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36))); /* ExpDataSN */ + + RETURN_NOT_EQUAL("Byte 1, bit 0", header[1] & 0x80, 0x80, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 4-7", *((uint32_t *) (void *) (header + 4)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Function: %u\n", cmd->function); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Ref Tag: %#x\n", cmd->ref_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "RefCmdSN: %u\n", cmd->RefCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpDataSN: %u\n", cmd->ExpDataSN); + + return 0; +} + +/* + * Task Response + */ + +int +iscsi_task_rsp_encap(uint8_t *header, iscsi_task_rsp_t * rsp) +{ + + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Response: %u\n", rsp->response); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= ISCSI_TASK_RSP; /* Opcode */ + header[1] |= 0x80; /* Byte 1 bit 0 */ + header[2] = rsp->response; /* Response */ + length = (rsp->length & 0x00ffffff); /* Length */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* Length */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag); /* Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN); /* MaxCmdSN */ + + return 0; +} + +int +iscsi_task_rsp_decap(uint8_t *header, iscsi_task_rsp_t * rsp) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_TASK_RSP, NO_CLEANUP, 1); + + rsp->response = header[2]; /* Response */ + rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + + RETURN_NOT_EQUAL("Byte 0, bits 0-1", header[0] & 0x00, 0x00, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 1, bit 0", header[1] & 0x80, 0x80, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 4-7", *((uint32_t *) (void *) (header + 4)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 20-23", *((uint32_t *) (void *) (header + 23)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Response: %u\n", rsp->response); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + + return 0; +} + +/* + * NOP-Out + */ + +int +iscsi_nop_out_encap(uint8_t *header, iscsi_nop_out_args_t * cmd) +{ + + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] = ISCSI_NOP_OUT; /* Opcode */ + if (cmd->immediate) { + header[0] |= 0x40; /* Immediate bit */ + } + header[1] |= 0x80; /* Byte 1 bit 0 and Reserved */ + length = (cmd->length & 0x00ffffff); /* Length */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag); /* Target Transfer Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN); /* CmdSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + + return 0; +} + +int +iscsi_nop_out_decap(uint8_t *header, iscsi_nop_out_args_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_NOP_OUT, NO_CLEANUP, 1); + + cmd->immediate = ((header[0] & 0x40) == 0x40); /* Immediate bit */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Target Tranfer Tag */ + cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* CmdSN */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + + RETURN_NOT_EQUAL("Byte 1", header[1], 0x80, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 32-35", *((uint32_t *) (void *) (header + 32)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + return 0; +} + +/* + * NOP-In + */ + +int +iscsi_nop_in_encap(uint8_t *header, iscsi_nop_in_args_t * cmd) +{ + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] = 0x00 | ISCSI_NOP_IN; /* Opcode */ + header[1] |= 0x80; /* Reserved */ + length = (cmd->length & 0x00ffffff); /* Length */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag); /* Target Transfer Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN); /* MaxCmdSN */ + + return 0; +} + +int +iscsi_nop_in_decap(uint8_t *header, iscsi_nop_in_args_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_NOP_IN, NO_CLEANUP, 1); + + + + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Target Transfer Tag */ + cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + + RETURN_NOT_EQUAL("Byte 0, bits 0-1", header[0] & 0xc0, 0x00, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 1", header[1], 0x80, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + return 0; +} + +/* + * Text Command + */ + +int +iscsi_text_cmd_encap(uint8_t *header, iscsi_text_cmd_args_t * cmd) +{ + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", cmd->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= ISCSI_TEXT_CMD; /* Opcode */ + if (cmd->immediate) { + header[0] |= 0x40; /* Immediate bit */ + } + if (cmd->final) { + header[1] |= 0x80; /* Final bit */ + } + if (cmd->cont) { + header[1] |= 0x40; /* Continue bit */ + } + length = (cmd->length & 0x00ffffff); /* Length */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag); /* Transfer Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN); /* CmdSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + + return 0; +} + +int +iscsi_text_cmd_decap(uint8_t *header, iscsi_text_cmd_args_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_TEXT_CMD, NO_CLEANUP, 1); + + cmd->immediate = ((header[0] & 0x40) == 0x40); /* Immediate bit */ + cmd->final = ((header[1] & 0x80) == 0x80); /* Final bit */ + cmd->cont = ((header[1] & 0x40) == 0x40); /* Continue bit */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Transfer Tag */ + cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* CmdSN */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + + RETURN_NOT_EQUAL("Byte 1, Bits 2-7", header[1] & 0x00, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 32-35", *((uint32_t *) (void *) (header + 32)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", cmd->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + return 0; +} + +/* + * Text Response + */ + +int +iscsi_text_rsp_encap(uint8_t *header, iscsi_text_rsp_args_t * rsp) +{ + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", rsp->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", rsp->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", rsp->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", rsp->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + header[0] |= 0x00 | ISCSI_TEXT_RSP; /* Opcode */ + if (rsp->final) { + header[1] |= 0x80; /* Final bit */ + } + if (rsp->cont) { + header[1] |= 0x40; /* Continue */ + } + length = (rsp->length & 0x00ffffff); /* Length */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(rsp->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(rsp->transfer_tag); /* Transfer Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN); /* MaxCmdSN */ + + return 0; +} + +int +iscsi_text_rsp_decap(uint8_t *header, iscsi_text_rsp_args_t * rsp) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_TEXT_RSP, NO_CLEANUP, 1); + + rsp->final = ((header[1] & 0x80) == 0x80); /* Final bit */ + rsp->cont = ((header[1] & 0x40) == 0x40); /* Continue bit */ + rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + rsp->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + rsp->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Transfer Tag */ + rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + + RETURN_NOT_EQUAL("Byte 1, Bits 2-7", header[1] & 0x3f, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", rsp->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", rsp->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", rsp->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", rsp->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + + return 0; +} + +/* + * Login Command + */ + +int +iscsi_login_cmd_encap(uint8_t *header, iscsi_login_cmd_args_t * cmd) +{ + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transit: %d\n", cmd->transit); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", cmd->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CSG: %u\n", cmd->csg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "NSG: %u\n", cmd->nsg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_min: %u\n", cmd->version_min); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_max: %u\n", cmd->version_max); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", cmd->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ISID: %" PRIu64 "\n", cmd->isid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TSIH: %hu\n", cmd->tsih); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CID: %hu\n", cmd->cid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= 0x40 | ISCSI_LOGIN_CMD; /* Opcode */ + if (cmd->transit) { + header[1] |= 0x80; /* Transit */ + } + if (cmd->cont) { + header[1] |= 0x40; /* Continue */ + } + header[1] |= ((cmd->csg) << 2) & 0x0c; /* CSG */ + header[1] |= (cmd->nsg) & 0x03; /* NSG */ + header[2] = cmd->version_max; /* Version-Max */ + header[3] = cmd->version_min; /* Version-Min */ + header[4] = cmd->AHSlength; /* TotalAHSLength */ + length = (cmd->length & 0x00ffffff); /* Length */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->isid); /* ISID */ + *((uint16_t *) (void *) (header + 14)) = ISCSI_HTONS(cmd->tsih); /* TSIH */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Task Tag */ + *((uint16_t *) (void *) (header + 20)) = ISCSI_HTONS(cmd->cid); /* CID */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN); /* CmdSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + + return 0; +} + +int +iscsi_login_cmd_decap(uint8_t *header, iscsi_login_cmd_args_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_LOGIN_CMD, NO_CLEANUP, 1); + + cmd->transit = (header[1] & 0x80) ? 1 : 0; /* Transit */ + cmd->cont = (header[1] & 0x40) ? 1 : 0; /* Continue */ + cmd->csg = (header[1] & 0x0cU) >> 2; /* CSG */ + cmd->nsg = header[1] & 0x03; /* NSG */ + cmd->version_max = header[2]; /* Version-Max */ + cmd->version_min = header[3]; /* Version-Min */ + cmd->AHSlength = header[4]; /* TotalAHSLength */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->isid = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* ISID */ + cmd->tsih = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 14))); /* TSIH */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Task Tag */ + cmd->cid = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 20))); /* CID */ + cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* CmdSN */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transit: %d\n", cmd->transit); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", cmd->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CSG: %u\n", cmd->csg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "NSG: %u\n", cmd->nsg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_min: %u\n", cmd->version_min); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_max: %u\n", cmd->version_max); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", cmd->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ISID: %" PRIu64 "\n", cmd->isid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TSIH: %hu\n", cmd->tsih); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CID: %hu\n", cmd->cid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + RETURN_NOT_EQUAL("Byte 1, bits 2-3", (header[1] & 0x30U) >> 4U, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 22-23", *((uint16_t *) (void *) (header + 22)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 32-35", *((uint32_t *) (void *) (header + 32)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + if (cmd->transit) { + if (cmd->nsg <= cmd->csg) { + return -1; + } + if ((cmd->nsg != 0) && (cmd->nsg != 1) && (cmd->nsg != 3)) { + return -1; + } + } + return 0; +} + +/* + * Login Response + */ + +int +iscsi_login_rsp_encap(uint8_t *header, iscsi_login_rsp_args_t * rsp) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transit: %d\n", rsp->transit); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", rsp->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CSG: %u\n", rsp->csg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "NSG: %u\n", rsp->nsg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_max: %u\n", rsp->version_max); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_active: %u\n", rsp->version_active); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", rsp->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ISID: %" PRIu64 "\n", rsp->isid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TSIH: %u\n", rsp->tsih); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Status-Class: %u\n", rsp->status_class); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Status-Detail: %u\n", rsp->status_detail); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= 0x00 | ISCSI_LOGIN_RSP; /* Opcode */ + if (rsp->transit) { + header[1] |= 0x80; /* Transit */ + } + if (rsp->cont) { + header[1] |= 0x40; /* Continue */ + } + header[1] |= ((rsp->csg) << 2) & 0x0c; /* CSG */ + if (rsp->transit) { + header[1] |= (rsp->nsg) & 0x03; /* NSG */ + } + header[2] = rsp->version_max; /* Version-max */ + header[3] = rsp->version_active; /* Version-active */ + header[4] = rsp->AHSlength; /* TotalAHSLength */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(rsp->isid); /* ISID */ + *((uint16_t *) (void *) (header + 14)) = ISCSI_HTONS(rsp->tsih); /* TSIH */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag); /* Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN); /* StatRn */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN); /* MaxCmdSN */ + header[36] = rsp->status_class; /* Status-Class */ + header[37] = rsp->status_detail; /* Status-Detail */ + + return 0; +} + +int +iscsi_login_rsp_decap(uint8_t *header, iscsi_login_rsp_args_t * rsp) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_LOGIN_RSP, NO_CLEANUP, 1); + + rsp->transit = (header[1] & 0x80U) >> 7; /* Transit */ + rsp->cont = (header[1] & 0x40U) >> 6; /* Continue */ + rsp->csg = (header[1] & 0x0cU) >> 2; /* CSG */ + rsp->nsg = header[1] & 0x03; /* NSG */ + rsp->version_max = header[2]; /* Version-max */ + rsp->version_active = header[3]; /* Version-active */ + rsp->AHSlength = header[4]; /* TotalAHSLength */ + rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + rsp->isid = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* ISID */ + rsp->tsih = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 14))); /* TSIH */ + + rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + rsp->status_class = header[36]; /* Status-Class */ + rsp->status_detail = header[37]; /* Status-Detail */ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transit: %d\n", rsp->transit); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Continue: %d\n", rsp->cont); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CSG: %u\n", rsp->csg); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "NSG: %u\n", rsp->nsg); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_max: %u\n", rsp->version_max); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Version_active: %u\n", rsp->version_active); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", rsp->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ISID: %" PRIu64 "\n", rsp->isid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TSIH: %u\n", rsp->tsih); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Status-Class: %u\n", rsp->status_class); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Status-Detail: %u\n", rsp->status_detail); + + RETURN_NOT_EQUAL("Byte 1, bits 2-3", (header[1] & 0x30U) >> 4, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 20-23", *((uint32_t *) (void *) (header + 20)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 38", header[38], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 39", header[39], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + return 0; +} + +/* + * Logout Command + */ + +int +iscsi_logout_cmd_encap(uint8_t *header, iscsi_logout_cmd_args_t * cmd) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Reason: %u\n", cmd->reason); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CID: %hu\n", cmd->cid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] = ISCSI_LOGOUT_CMD; /* Opcode */ + if (cmd->immediate) { + header[0] |= 0x40; /* Immediate */ + } + header[1] = cmd->reason | 0x80; /* Reason */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint16_t *) (void *) (header + 20)) = ISCSI_HTONS(cmd->cid); /* CID */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN); /* CmdSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + + return 0; +} + +int +iscsi_logout_cmd_decap(uint8_t *header, iscsi_logout_cmd_args_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_LOGOUT_CMD, NO_CLEANUP, 1); + + cmd->immediate = (header[0] & 0x40) ? 1 : 0; /* Immediate */ + cmd->reason = header[1] & 0x7f; /* Reason */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->cid = ISCSI_NTOHS(*((uint16_t *) (void *) (header + 20))); /* CID */ + cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* CmdSN */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Reason: %u\n", cmd->reason); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CID: %hu\n", cmd->cid); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + + RETURN_NOT_EQUAL("Byte 0 bit 0", (unsigned)(header[0]) >> 7U, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 1 bit 0", (unsigned)(header[1]) >> 7U, 1, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 4-7", *((uint32_t *) (void *) (header + 4)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 22-23", *((uint16_t *) (void *) (header + 22)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 32-35", *((uint32_t *) (void *) (header + 32)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + return 0; +} + +/* + * Logout Response + */ + +int +iscsi_logout_rsp_encap(uint8_t *header, iscsi_logout_rsp_args_t * rsp) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Response: %u\n", rsp->response); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Time2Wait: %hu\n", rsp->Time2Wait); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Time2Retain: %hu\n", rsp->Time2Retain); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= 0x00 | ISCSI_LOGOUT_RSP; /* Opcode */ + header[1] |= 0x80; /* Reserved */ + header[2] = rsp->response; /* Response */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length); /* Length */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag); /* Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN); /* MaxCmdSN */ + *((uint16_t *) (void *) (header + 40)) = ISCSI_HTONS(rsp->Time2Wait); /* Time2Wait */ + *((uint16_t *) (void *) (header + 42)) = ISCSI_HTONS(rsp->Time2Retain); /* Time2Retain */ + + return 0; +} + +int +iscsi_logout_rsp_decap(uint8_t *header, iscsi_logout_rsp_args_t * rsp) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_LOGOUT_RSP, NO_CLEANUP, 1); + + rsp->response = header[2]; /* Response */ + rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + rsp->Time2Wait = ISCSI_NTOHS(*((uint32_t *) (void *) (header + 40))); /* Time2Wait */ + rsp->Time2Retain = ISCSI_NTOHS(*((uint32_t *) (void *) (header + 42))); /* Time2Retain */ + + RETURN_NOT_EQUAL("Byte 0 bits 0-1", (header[0] & 0x20), 0x20, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Byte 1 bit 0", header[1] & 0x80, 0x80, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Bytes 4-7", *((uint32_t *) (void *) (header + 4)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 20-23", *((uint32_t *) (void *) (header + 20)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 36-39", *((uint32_t *) (void *) (header + 36)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Response: %u\n", rsp->response); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Time2Wait: %hu\n", rsp->Time2Wait); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Time2Retain: %hu\n", rsp->Time2Retain); + + return 0; +} + +/* + * SCSI Command + */ + +int +iscsi_scsi_cmd_encap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Input: %d\n", cmd->input); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Output: %d\n", cmd->output); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ATTR: %d\n", cmd->attr); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", cmd->ahs_len); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Length: %u\n", cmd->trans_len); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CDB: %#x\n", cmd->cdb[0]); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= ISCSI_SCSI_CMD; /* Opcode */ + if (cmd->immediate) { + header[0] |= 0x40; /* Immediate */ + } + if (cmd->final) { + header[1] |= 0x80; /* Final */ + } + if (cmd->input) { + header[1] |= 0x40; /* Input bit */ + } + if (cmd->output) { + header[1] |= 0x20; /* Output bit */ + } + header[1] |= cmd->attr & 0x07; /* ATTR */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length); /* DataSegmentLength */ + header[4] = cmd->ahs_len; /* TotalAHSLength */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Task Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->trans_len); /* Expected Transfer + * Length */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->CmdSN); /* CmdSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + memcpy(header + 32, cmd->cdb, 16); /* CDB */ + + return 0; +} + +int +iscsi_scsi_cmd_decap(uint8_t *header, iscsi_scsi_cmd_args_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_SCSI_CMD, NO_CLEANUP, 1); + + cmd->immediate = (header[0] & 0x40) ? 1 : 0; /* Immediate */ + cmd->final = (header[1] & 0x80) ? 1 : 0; /* Final */ + cmd->input = (header[1] & 0x40) ? 1 : 0; /* Input */ + cmd->output = (header[1] & 0x20) ? 1 : 0; /* Output */ + cmd->attr = header[1] & 0x07; /* ATTR */ + cmd->ahs_len = header[4]; + header[4] = 0x00; + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* DataSegmentLength */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Task Tag */ + cmd->trans_len = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Expected Transfer + * Length */ + cmd->CmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* CmdSN */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + cmd->cdb = header + 32; /* CDB */ + + RETURN_NOT_EQUAL("Byte 1, Bits 3-4", header[1] & 0x18, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Immediate: %d\n", cmd->immediate); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Input: %d\n", cmd->input); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Output: %d\n", cmd->output); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ATTR: %d\n", cmd->attr); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", cmd->ahs_len); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Length: %u\n", cmd->trans_len); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CmdSN: %u\n", cmd->CmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "CDB: %#x\n", cmd->cdb[0]); + + return 0; +} + +/* + * SCSI Response + */ + +int +iscsi_scsi_rsp_encap(uint8_t *header, iscsi_scsi_rsp_t * rsp) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Bidi Overflow: %d\n", rsp->bidi_overflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Bidi Underflow: %d\n", rsp->bidi_underflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Overflow: %d\n", rsp->overflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Underflow: %d\n", rsp->underflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "iSCSI Response: %u\n", rsp->response); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "SCSI Status: %u\n", rsp->status); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpDataSN: %u\n", rsp->ExpDataSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Bidi Residual Count: %u\n", rsp->bidi_res_cnt); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Residual Count: %u\n", rsp->basic_res_cnt); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= 0x00 | ISCSI_SCSI_RSP; /* Opcode */ + header[1] |= 0x80; /* Byte 1 bit 7 */ + if (rsp->bidi_overflow) { + header[1] |= 0x10; /* Bidi overflow */ + } + if (rsp->bidi_underflow) { + header[1] |= 0x08; /* Bidi underflow */ + } + if (rsp->overflow) { + header[1] |= 0x04; /* Overflow */ + } + if (rsp->underflow) { + header[1] |= 0x02; /* Underflow */ + } + header[2] = rsp->response; /* iSCSI Response */ + header[3] = rsp->status;/* SCSI Status */ + header[4] = rsp->ahs_len; /* TotalAHSLength */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(rsp->length); /* DataSegmentLength */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(rsp->tag); /* Task Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(rsp->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(rsp->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(rsp->MaxCmdSN); /* MaxCmdSN */ + *((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(rsp->ExpDataSN); /* ExpDataSN */ + *((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(rsp->bidi_res_cnt); /* Bidi Residual Count */ + *((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(rsp->basic_res_cnt); /* Residual Count */ + + return 0; +} + +int +iscsi_scsi_rsp_decap(uint8_t *header, iscsi_scsi_rsp_t * rsp) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_SCSI_RSP, NO_CLEANUP, 1); + + rsp->bidi_overflow = (header[1] & 0x10) ? 1 : 0; /* Bidi overflow */ + rsp->bidi_underflow = (header[1] & 0x08) ? 1 : 0; /* Bidi underflow */ + rsp->overflow = (header[1] & 0x04) ? 1 : 0; /* Overflow */ + rsp->underflow = (header[1] & 0x02) ? 1 : 0; /* Underflow */ + + rsp->response = header[2]; /* iSCSI Response */ + rsp->status = header[3];/* SCSI Status */ + rsp->ahs_len = header[4]; /* TotalAHSLength */ + rsp->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* DataSegmentLength */ + rsp->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Task Tag */ + rsp->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + rsp->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + rsp->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + rsp->ExpDataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36))); /* ExpDataSN */ + rsp->bidi_res_cnt = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40))); /* Bidi Residual Count */ + rsp->basic_res_cnt = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44))); /* Residual Count */ + + RETURN_NOT_EQUAL("Byte 0 bits 0-1", header[0] & 0x00, 0x00, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 1 bit 0", header[1] & 0x80, 0x80, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("bidi_res_cnt", rsp->bidi_res_cnt, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("bidi_overflow", rsp->bidi_overflow, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("bidi_underflow", rsp->bidi_underflow, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("overflow", rsp->overflow, 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Bidi Overflow: %d\n", rsp->bidi_overflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Bidi Underflow: %d\n", rsp->bidi_underflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Overflow: %d\n", rsp->overflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Underflow: %d\n", rsp->underflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "iSCSI Response: %u\n", rsp->response); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "SCSI Status: %u\n", rsp->status); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", rsp->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", rsp->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Residual Count: %u\n", rsp->basic_res_cnt); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", rsp->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", rsp->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", rsp->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpDataSN: %u\n", rsp->ExpDataSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Bidi Residual Count: %u\n", rsp->bidi_res_cnt); + + return 0; +} + + +/* + * Ready To Transfer + */ + +int +iscsi_r2t_encap(uint8_t *header, iscsi_r2t_t * cmd) +{ + uint32_t length; + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", cmd->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "R2TSN: %u\n", cmd->R2TSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Offset: %u\n", cmd->offset); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= 0x00 | ISCSI_R2T; /* Opcode */ + header[1] |= 0x80; + length = (cmd->AHSlength & 0x00ffffff); /* AHSLength */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(length); /* AHSLength */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag); /* Transfer Tag */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN); /* MaxCmdSN */ + *((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->R2TSN); /* R2TSN */ + *((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset); /* Buffer Offset */ + *((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(cmd->length); /* Transfer Length */ + + return 0; +} + +int +iscsi_r2t_decap(uint8_t *header, iscsi_r2t_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_R2T, NO_CLEANUP, 1); + + cmd->AHSlength = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* TotalAHSLength */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Transfer Tag */ + cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + cmd->R2TSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36))); /* R2TSN */ + cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40))); /* Offset */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44))); /* Transfer Length */ + + RETURN_NOT_EQUAL("Byte 1, Bits 1-7", header[1] & 0x7f, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 4-7", *((uint32_t *) (void *) (header + 4)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "AHSLength: %u\n", cmd->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "R2TSN: %u\n", cmd->R2TSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Offset: %u\n", cmd->offset); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + return 0; +} + +/* + * SCSI Write Data + */ + +int +iscsi_write_data_encap(uint8_t *header, iscsi_write_data_t * cmd) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %u\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSN: %u\n", cmd->DataSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Buffer Offset: %u\n", cmd->offset); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + header[0] = 0x00 | ISCSI_WRITE_DATA; /* Opcode */ + if (cmd->final) { + header[1] |= 0x80; /* Final */ + } + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->tag); /* Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag); /* Transfer Tag */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpStatSN); /* ExpStatSN */ + *((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN); /* DataSN */ + *((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset); /* Buffer Offset */ + + return 0; +} + +int +iscsi_write_data_decap(uint8_t *header, iscsi_write_data_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_WRITE_DATA, NO_CLEANUP, 1); + + cmd->final = (header[1] & 0x80) ? 1 : 0; /* Final */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Tag */ + cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Transfer Tag */ + cmd->ExpStatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpStatSN */ + cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36))); /* DataSN */ + cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40))); /* Buffer Offset */ + + RETURN_NOT_EQUAL("Byte 1, Bits 1-7", header[1] & 0x7f, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 24-27", *((uint32_t *) (void *) (header + 24)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 32-35", *((uint32_t *) (void *) (header + 32)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %u\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpStatSN: %u\n", cmd->ExpStatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSN: %u\n", cmd->DataSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Buffer Offset: %u\n", cmd->offset); + + return 0; +} + +/* + * SCSI Read Data + */ + +int +iscsi_read_data_encap(uint8_t *header, iscsi_read_data_t * cmd) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Acknowledge: %d\n", cmd->ack); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Overflow: %d\n", cmd->overflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Underflow: %d\n", cmd->underflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "S_bit: %d\n", cmd->S_bit); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Status: %u\n", cmd->status); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", cmd->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->task_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Transfer Tag: %#x\n", cmd->transfer_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSN: %u\n", cmd->DataSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Buffer Offset %u\n", cmd->offset); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Residual Count: %u\n", cmd->res_count); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] = 0x00 | ISCSI_READ_DATA; /* Opcode */ + if (cmd->final) { + header[1] |= 0x80; /* Final */ + } + if (cmd->ack) { + header[1] |= 0x40; /* ACK */ + } + if (cmd->overflow) { + header[1] |= 0x04; /* Overflow */ + } + if (cmd->underflow) { + header[1] |= 0x02; /* Underflow */ + } + if (cmd->S_bit) { + header[1] |= 0x01; /* S Bit */ + } + if (cmd->S_bit) { + header[3] = cmd->status; /* Status */ + } + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length); /* Length */ + *((uint64_t *) (void *) (header + 8)) = ISCSI_HTONLL6(cmd->lun); /* LUN */ + *((uint32_t *) (void *) (header + 16)) = ISCSI_HTONL(cmd->task_tag); /* Task Tag */ + *((uint32_t *) (void *) (header + 20)) = ISCSI_HTONL(cmd->transfer_tag); /* Transfer Tag */ + if (cmd->S_bit) { + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN); /* StatSN */ + } + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN); /* MaxCmdSN */ + *((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN); /* DataSN */ + *((uint32_t *) (void *) (header + 40)) = ISCSI_HTONL(cmd->offset); /* Buffer Offset */ + if (cmd->S_bit) { + *((uint32_t *) (void *) (header + 44)) = ISCSI_HTONL(cmd->res_count); /* Residual Count */ + } + + return 0; +} + +int +iscsi_read_data_decap(uint8_t *header, iscsi_read_data_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_READ_DATA, NO_CLEANUP, 1); + + cmd->final = (header[1] & 0x80) ? 1 : 0; /* Final */ + cmd->ack = (header[1] & 0x40) ? 1 : 0; /* Acknowledge */ + cmd->overflow = (header[1] & 0x04) ? 1 : 0; /* Overflow */ + cmd->underflow = (header[1] & 0x02) ? 1 : 0; /* Underflow */ + cmd->S_bit = (header[1] & 0x01) ? 1 : 0; /* S Bit */ + cmd->status = header[3];/* Status */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + cmd->task_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 16))); /* Task Tag */ + cmd->transfer_tag = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 20))); /* Transfer Tag */ + cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36))); /* DataSN */ + cmd->offset = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 40))); /* Buffer Offset */ + cmd->res_count = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 44))); /* Residual Count */ + + RETURN_NOT_EQUAL("Byte 0, Bits 0-1", header[0] & 0xc0, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 1, Bits 2-4", header[1] & 0x38, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 2", header[2], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Final: %d\n", cmd->final); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Acknowledge: %d\n", cmd->ack); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Overflow: %d\n", cmd->overflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Underflow: %d\n", cmd->underflow); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "S_bit: %d\n", cmd->S_bit); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Status: %u\n", cmd->status); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Task Tag: %#x\n", cmd->task_tag); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Residual Count: %u\n", cmd->res_count); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSN: %u\n", cmd->DataSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Buffer Offset %u\n", cmd->offset); + return 0; +} + +/* + * Reject + */ + +int +iscsi_reject_encap(uint8_t *header, iscsi_reject_t * cmd) +{ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Reason: %u\n", cmd->reason); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSN: %u\n", cmd->DataSN); + + (void) memset(header, 0x0, ISCSI_HEADER_LEN); + + header[0] |= 0x00 | ISCSI_REJECT; /* Opcode */ + header[1] |= 0x80; + header[2] = cmd->reason;/* Reason */ + *((uint32_t *) (void *) (header + 4)) = ISCSI_HTONL(cmd->length); /* Length */ + *((uint32_t *) (void *) (header + 24)) = ISCSI_HTONL(cmd->StatSN); /* StatSN */ + *((uint32_t *) (void *) (header + 28)) = ISCSI_HTONL(cmd->ExpCmdSN); /* ExpCmdSN */ + *((uint32_t *) (void *) (header + 32)) = ISCSI_HTONL(cmd->MaxCmdSN); /* MaxCmdSN */ + *((uint32_t *) (void *) (header + 36)) = ISCSI_HTONL(cmd->DataSN); /* DataSN */ + + return 0; +} + +int +iscsi_reject_decap(uint8_t *header, iscsi_reject_t * cmd) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_REJECT, NO_CLEANUP, 1); + + cmd->reason = header[2];/* Reason */ + cmd->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + cmd->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + cmd->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + cmd->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + cmd->DataSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 36))); /* DataSN */ + + RETURN_NOT_EQUAL("Byte 0, Bits 0-1", header[0] & 0xc0, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 1, Bits 1-7", header[1] & 0x7f, 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 3", header[3], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Byte 4", header[4], 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 8-11", *((uint32_t *) (void *) (header + 8)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 12-15", *((uint32_t *) (void *) (header + 12)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 20-23", *((uint32_t *) (void *) (header + 20)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 40-43", *((uint32_t *) (void *) (header + 40)), 0, NO_CLEANUP, 1); + RETURN_NOT_EQUAL("Bytes 44-47", *((uint32_t *) (void *) (header + 44)), 0, NO_CLEANUP, 1); + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Reason: %u\n", cmd->reason); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "Length: %u\n", cmd->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", cmd->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", cmd->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", cmd->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSN: %u\n", cmd->DataSN); + return 0; +} + +int +iscsi_amsg_decap(uint8_t *header, iscsi_async_msg_t * msg) +{ + + RETURN_NOT_EQUAL("Opcode", ISCSI_OPCODE(header), ISCSI_ASYNC, NO_CLEANUP, 1); + + msg->AHSlength = header[4]; /* TotalAHSLength */ + msg->length = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 4))); /* Length */ + msg->lun = ISCSI_NTOHLL6(*((uint64_t *) (void *) (header + 8))); /* LUN */ + msg->StatSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 24))); /* StatSN */ + msg->ExpCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 28))); /* ExpCmdSN */ + msg->MaxCmdSN = ISCSI_NTOHL(*((uint32_t *) (void *) (header + 32))); /* MaxCmdSN */ + msg->AsyncEvent = header[36]; /* Async Event */ + msg->AsyncVCode = header[37]; /* Async Vendor Code */ + + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "TotalAHSLength: %u\n", msg->AHSlength); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "DataSegmentLength: %u\n", msg->length); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "LUN: %" PRIu64 "\n", msg->lun); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "StatSN: %u\n", msg->StatSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "ExpCmdSN: %u\n", msg->ExpCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "MaxCmdSN: %u\n", msg->MaxCmdSN); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "AsyncEvent: %u\n", msg->AsyncEvent); + iscsi_trace(TRACE_ISCSI_ARGS, __FILE__, __LINE__, "AsyncVCode: %u\n", msg->AsyncVCode); + + return 0; +} diff --git a/external/bsd/iscsi/dist/src/md5c.c b/external/bsd/iscsi/dist/src/md5c.c new file mode 100644 index 000000000000..a935677b0354 --- /dev/null +++ b/external/bsd/iscsi/dist/src/md5c.c @@ -0,0 +1,368 @@ +/* $NetBSD: md5c.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * This file is derived from the RSA Data Security, Inc. MD5 Message-Digest + * Algorithm and has been modifed by Jason R. Thorpe + * for portability and formatting. + */ + +/* + * Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All + * rights reserved. + * + * License to copy and use this software is granted provided that it + * is identified as the "RSA Data Security, Inc. MD5 Message-Digest + * Algorithm" in all material mentioning or referencing this software + * or this function. + * + * License is also granted to make and use derivative works provided + * that such works are identified as "derived from the RSA Data + * Security, Inc. MD5 Message-Digest Algorithm" in all material + * mentioning or referencing the derived work. + * + * RSA Data Security, Inc. makes no representations concerning either + * the merchantability of this software or the suitability of this + * software for any particular purpose. It is provided "as is" + * without express or implied warranty of any kind. + * + * These notices must be retained in any copies of any part of this + * documentation and/or software. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(_KERNEL) || defined(_STANDALONE) +#include +#include +#include +#define _DIAGASSERT(x) (void)0 +#else +/* #include "namespace.h" */ +#include +#include +#include "iscsi-md5.h" +#endif /* _KERNEL || _STANDALONE */ + +#if defined(HAVE_MEMSET) +#define ZEROIZE(d, l) memset((d), 0, (l)) +#else +# if defined(HAVE_BZERO) +#define ZEROIZE(d, l) bzero((d), (l)) +# else +#error You need either memset or bzero +# endif +#endif + +typedef unsigned char *POINTER; +typedef uint16_t UINT2; +typedef uint32_t UINT4; + +/* + * Constants for MD5Transform routine. + */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 + +#if 0 +#if !defined(_KERNEL) && !defined(_STANDALONE) && defined(__weak_alias) +__weak_alias(iSCSI_MD5Init,_MD5Init) +__weak_alias(iSCSI_MD5Update,_MD5Update) +__weak_alias(iSCSI_MD5Final,_MD5Final) +#endif +#endif + +#ifndef _DIAGASSERT +#define _DIAGASSERT(cond) assert(cond) +#endif + +static void iSCSI_MD5Transform(UINT4 [4], const unsigned char [64]); + +static void Encode(unsigned char *, UINT4 *, unsigned int); +static void Decode(UINT4 *, const unsigned char *, unsigned int); + +/* + * Encodes input (UINT4) into output (unsigned char). Assumes len is + * a multiple of 4. + */ +static void +Encode (output, input, len) + unsigned char *output; + UINT4 *input; + unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) { + output[j] = (unsigned char)(input[i] & 0xff); + output[j+1] = (unsigned char)((input[i] >> 8) & 0xff); + output[j+2] = (unsigned char)((input[i] >> 16) & 0xff); + output[j+3] = (unsigned char)((input[i] >> 24) & 0xff); + } +} + +/* + * Decodes input (unsigned char) into output (UINT4). Assumes len is + * a multiple of 4. + */ +static void +Decode (output, input, len) + UINT4 *output; + const unsigned char *input; + unsigned int len; +{ + unsigned int i, j; + + for (i = 0, j = 0; j < len; i++, j += 4) + output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) | + (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24); +} + +static const unsigned char PADDING[64] = { + 0x80, 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 +}; + +/* + * F, G, H and I are basic MD5 functions. + */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* + * ROTATE_LEFT rotates x left n bits. + */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* + * FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4. + * Rotation is separate from addition to prevent recomputation. + */ +#define FF(a, b, c, d, x, s, ac) { \ + (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define GG(a, b, c, d, x, s, ac) { \ + (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define HH(a, b, c, d, x, s, ac) { \ + (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +#define II(a, b, c, d, x, s, ac) { \ + (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \ + (a) = ROTATE_LEFT ((a), (s)); \ + (a) += (b); \ +} + +/* + * MD5 initialization. Begins an MD5 operation, writing a new context. + */ +void +iSCSI_MD5Init(iSCSI_MD5_CTX *context) +{ + + _DIAGASSERT(context != 0); + + context->count[0] = context->count[1] = 0; + + /* Load magic initialization constants. */ + context->state[0] = 0x67452301; + context->state[1] = 0xefcdab89; + context->state[2] = 0x98badcfe; + context->state[3] = 0x10325476; +} + +/* + * MD5 block update operation. Continues an MD5 message-digest + * operation, processing another message block, and updating the + * context. + */ +void +iSCSI_MD5Update(iSCSI_MD5_CTX *context, const uint8_t *input, size_t inputLen) +{ + unsigned int i, idx, partLen; + + _DIAGASSERT(context != 0); + _DIAGASSERT(input != 0); + + /* Compute number of bytes mod 64 */ + idx = (unsigned int)((context->count[0] >> 3) & 0x3F); + + /* Update number of bits */ + if ((context->count[0] += ((UINT4)inputLen << 3)) + < ((UINT4)inputLen << 3)) + context->count[1]++; + context->count[1] += ((UINT4)inputLen >> 29); + + partLen = 64 - idx; + + /* Transform as many times as possible. */ + if (inputLen >= partLen) { + /* LINTED const castaway ok */ + memcpy((POINTER)&context->buffer[idx], + input, partLen); + iSCSI_MD5Transform(context->state, context->buffer); + + for (i = partLen; i + 63 < inputLen; i += 64) + iSCSI_MD5Transform(context->state, &input[i]); + + idx = 0; + } else + i = 0; + + /* Buffer remaining input */ + /* LINTED const castaway ok */ + memcpy((POINTER)&context->buffer[idx], &input[i], + inputLen - i); +} + +/* + * MD5 finalization. Ends an MD5 message-digest operation, writing the + * message digest and zeroing the context. + */ +void +iSCSI_MD5Final(unsigned char digest[16], iSCSI_MD5_CTX *context) +{ + unsigned char bits[8]; + unsigned int idx; + size_t padLen; + + _DIAGASSERT(digest != 0); + _DIAGASSERT(context != 0); + + /* Save number of bits */ + Encode(bits, context->count, 8); + + /* Pad out to 56 mod 64. */ + idx = (unsigned int)((context->count[0] >> 3) & 0x3f); + padLen = (idx < 56) ? (56 - idx) : (120 - idx); + iSCSI_MD5Update (context, PADDING, padLen); + + /* Append length (before padding) */ + iSCSI_MD5Update(context, bits, 8); + + /* Store state in digest */ + Encode(digest, context->state, 16); + + /* Zeroize sensitive information. */ + ZEROIZE((POINTER)(void *)context, sizeof(*context)); +} + +/* + * MD5 basic transformation. Transforms state based on block. + */ +static void +iSCSI_MD5Transform(state, block) + UINT4 state[4]; + const unsigned char block[64]; +{ + UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16]; + + Decode(x, block, 64); + + /* Round 1 */ + FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */ + FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */ + FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */ + FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */ + FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */ + FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */ + FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */ + FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */ + FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */ + FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */ + FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */ + FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */ + FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */ + FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */ + FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */ + FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */ + + /* Round 2 */ + GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */ + GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */ + GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */ + GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */ + GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */ + GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */ + GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */ + GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */ + GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */ + GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */ + GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */ + GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */ + GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */ + GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */ + GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */ + GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */ + + /* Round 3 */ + HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */ + HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */ + HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */ + HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */ + HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */ + HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */ + HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */ + HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */ + HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */ + HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */ + HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */ + HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */ + HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */ + HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */ + HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */ + HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */ + + /* Round 4 */ + II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */ + II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */ + II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */ + II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */ + II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */ + II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */ + II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */ + II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */ + II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */ + II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */ + II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */ + II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */ + II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */ + II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */ + II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */ + II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */ + + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + + /* Zeroize sensitive information. */ + ZEROIZE((POINTER)(void *)x, sizeof (x)); +} diff --git a/external/bsd/iscsi/dist/src/md5hl.c b/external/bsd/iscsi/dist/src/md5hl.c new file mode 100644 index 000000000000..1bfde462db36 --- /dev/null +++ b/external/bsd/iscsi/dist/src/md5hl.c @@ -0,0 +1,122 @@ +/* $NetBSD: md5hl.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Written by Jason R. Thorpe , April 29, 1997. + * Public domain. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#define MDALGORITHM iSCSI_MD5 + +/* #include "namespace.h" */ +#include "iscsi-md5.h" + +#ifndef _DIAGASSERT +#define _DIAGASSERT(cond) assert(cond) +#endif + +/* $NetBSD: md5hl.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * ---------------------------------------------------------------------------- + * "THE BEER-WARE LICENSE" (Revision 42): + * wrote this file. As long as you retain this notice you + * can do whatever you want with this stuff. If we meet some day, and you think + * this stuff is worth it, you can buy me a beer in return. Poul-Henning Kamp + * ---------------------------------------------------------------------------- + * + * from FreeBSD Id: mdXhl.c,v 1.8 1996/10/25 06:48:12 bde Exp + */ + +/* + * Modifed April 29, 1997 by Jason R. Thorpe + */ + +#include +#ifdef HAVE_FCNTL_H +#include +#endif +#ifdef HAVE_ERRNO_H +#include +#endif +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#define CONCAT(x,y) __CONCAT(x,y) +#define MDNAME(x) CONCAT(MDALGORITHM,x) + +char * +MDNAME(End)(MDNAME(_CTX) *ctx, char *buf) +{ + int i; + unsigned char digest[16]; + static const char hex[]="0123456789abcdef"; + + _DIAGASSERT(ctx != 0); + + if (buf == NULL) + buf = malloc(33); + if (buf == NULL) + return (NULL); + + MDNAME(Final)(digest, ctx); + + for (i = 0; i < 16; i++) { + buf[i+i] = hex[(uint32_t)digest[i] >> 4]; + buf[i+i+1] = hex[digest[i] & 0x0f]; + } + + buf[i+i] = '\0'; + return (buf); +} + +char * +MDNAME(File)(filename, buf) + const char *filename; + char *buf; +{ + unsigned char buffer[BUFSIZ]; + MDNAME(_CTX) ctx; + int f, j; + size_t i; + + _DIAGASSERT(filename != 0); + /* buf may be NULL */ + + MDNAME(Init)(&ctx); + f = open(filename, O_RDONLY, 0666); + if (f < 0) + return NULL; + + while ((i = read(f, buffer, sizeof(buffer))) > 0) + MDNAME(Update)(&ctx, buffer, (size_t)i); + + j = errno; + close(f); + errno = j; + +#if 0 + if (i < 0) + return NULL; +#endif + + return (MDNAME(End)(&ctx, buf)); +} + +char * +MDNAME(Data)(const uint8_t *data, size_t len, char *buf) +{ + MDNAME(_CTX) ctx; + + _DIAGASSERT(data != 0); + + MDNAME(Init)(&ctx); + MDNAME(Update)(&ctx, data, len); + return (MDNAME(End)(&ctx, buf)); +} diff --git a/external/bsd/iscsi/dist/src/netmask.c b/external/bsd/iscsi/dist/src/netmask.c new file mode 100644 index 000000000000..a2f97687cd14 --- /dev/null +++ b/external/bsd/iscsi/dist/src/netmask.c @@ -0,0 +1,172 @@ +/* $NetBSD: netmask.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include "config.h" + +#include +#include + +#include +#include +#include +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#include "iscsiutil.h" + +enum { + NETMASK_BUFFER_SIZE = 256 +}; + +/* this struct is used to define a magic netmask value */ +typedef struct magic_t { + const char *magic; /* string to match */ + const char *xform; /* string to transform it into */ +} magic_t; + + +static magic_t magics[] = { + { "any", "0/0" }, + { "all", "0/0" }, + { "none", "0/32" }, + { NULL, NULL }, +}; + +#ifndef ISCSI_HTONL +#define ISCSI_HTONL(x) htonl(x) +#endif + +/* return 1 if address is in netmask's range */ +int +allow_netmask(const char *netmaskarg, const char *addr) +{ + struct in_addr a; + struct in_addr m; + const char *netmask; + magic_t *mp; + char maskaddr[NETMASK_BUFFER_SIZE]; + char *cp; + int slash; + int i; + + /* firstly check for any magic values in the netmask */ + netmask = netmaskarg; + for (mp = magics ; mp->magic ; mp++) { + if (strcmp(netmask, mp->magic) == 0) { + netmask = mp->xform; + break; + } + } + + /* find out if slash notation has been used */ + (void) memset(&a, 0x0, sizeof(a)); + if ((cp = strchr(netmask, '/')) == NULL) { + (void) strlcpy(maskaddr, netmask, sizeof(maskaddr)); + slash = 32; + } else { + (void) strlcpy(maskaddr, netmask, MIN(sizeof(maskaddr), (size_t)(cp - netmask) + 1)); + slash = atoi(cp + 1); + } + + /* if we have a wildcard "slash" netmask, then we allow it */ + if (slash == 0) { + return 1; + } + + /* canonicalise IPv4 address to dotted quad */ + for (i = 0, cp = maskaddr ; *cp ; cp++) { + if (*cp == '.') { + i += 1; + } + } + for ( ; i < 3 ; i++) { + (void) snprintf(cp, sizeof(maskaddr) - (int)(cp - maskaddr), ".0"); + cp += 2; + } + + /* translate netmask to in_addr */ + if (!inet_aton(maskaddr, &m)) { + (void) fprintf(stderr, "allow_netmask: can't interpret mask `%s' as an IPv4 address\n", maskaddr); + return 0; + } + + /* translate address to in_addr */ + if (!inet_aton(addr, &a)) { + (void) fprintf(stderr, "allow_netmask: can't interpret address `%s' as an IPv4 address\n", addr); + return 0; + } + +#ifdef ALLOW_NETMASK_DEBUG + printf("addr %s %08x, mask %s %08x, slash %d\n", addr, (ISCSI_HTONL(a.s_addr) >> (32 - slash)), maskaddr, (ISCSI_HTONL(m.s_addr) >> (32 - slash)), slash); +#endif + + /* and return 1 if address is in netmask */ + return (ISCSI_HTONL(a.s_addr) >> (32 - slash)) == (ISCSI_HTONL(m.s_addr) >> (32 - slash)); +} + +#ifdef ALLOW_NETMASK_DEBUG +int +main(int argc, char **argv) +{ + int i; + + for (i = 1 ; i < argc ; i+= 2) { + if (allow_netmask(argv[i], argv[i + 1])) { + printf("mask %s matches addr %s\n\n", argv[i], argv[i + 1]); + } else { + printf("No match for mask %s from addr %s\n\n", argv[i], argv[i + 1]); + } + } + exit(EXIT_SUCCESS); +} +#endif + +#if 0 +[11:33:02] agc@sys3 ...local/src/netmask 248 > ./n 10.4/16 10.4.0.29 10.4/16 10.5.0.29 10.4/0 10.4.0.19 10.4 10.4.0.19 10.4.3/8 10.4.3.7 10.4.3/24 10.4.3.7 +mask 10.4/16 matches addr 10.4.0.29 + +No match for mask 10.4/16 from addr 10.5.0.29 + +mask 10.4/0 matches addr 10.4.0.19 + +No match for mask 10.4 from addr 10.4.0.19 + +mask 10.4.3/8 matches addr 10.4.3.7 + +mask 10.4.3/24 matches addr 10.4.3.7 + +[14:44:52] agc@sys3 ...local/src/netmask 249 > +#endif diff --git a/external/bsd/iscsi/dist/src/osd-target.c b/external/bsd/iscsi/dist/src/osd-target.c new file mode 100644 index 000000000000..52e44206c683 --- /dev/null +++ b/external/bsd/iscsi/dist/src/osd-target.c @@ -0,0 +1,181 @@ +/* $NetBSD: osd-target.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include + +#ifndef lint +__COPYRIGHT("@(#) Copyright © 2006 \ + The NetBSD Foundation, Inc. All rights reserved."); +__RCSID("$NetBSD: osd-target.c,v 1.1 2009/06/21 21:20:31 agc Exp $"); +#endif +#include "config.h" + +#define EXTERN + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include "iscsi.h" +#include "iscsiutil.h" +#include "target.h" +#include "device.h" + +#include "conffile.h" +#include "storage.h" + +/* + * Globals + */ + +static int g_main_pid; +static globals_t g; + +/* + * Control-C handler + */ + +/* ARGSUSED0 */ +static void +handler(int s) +{ + if (ISCSI_GETPID != g_main_pid) + return; + if (target_shutdown(&g) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_shutdown() failed\n"); + return; + } + return; +} + +int +main(int argc, char **argv) +{ + const char *cf; + targv_t tv; + devv_t dv; + extv_t ev; + char TargetName[1024]; + int detach_me_harder; + int i; + + (void) memset(&g, 0x0, sizeof(g)); + (void) memset(&tv, 0x0, sizeof(tv)); + (void) memset(&dv, 0x0, sizeof(dv)); + (void) memset(&ev, 0x0, sizeof(ev)); + + /* set defaults */ + (void) strlcpy(TargetName, DEFAULT_TARGET_NAME, sizeof(TargetName)); + g.port = ISCSI_PORT; + detach_me_harder = 1; + + cf = _PATH_OSD_TARGETS; + + while ((i = getopt(argc, argv, "Dd:p:t:v:")) != -1) { + switch (i) { + case 'D': + detach_me_harder = 0; + break; + case 'd': + device_set_var("directory", optarg); + break; + case 'f': + cf = optarg; + break; + case 'p': + g.port = (uint16_t) atoi(optarg); + break; + case 't': + (void) strlcpy(TargetName, optarg, sizeof(TargetName)); + break; + case 'v': + if (strcmp(optarg, "net") == 0) { + set_debug("net"); + } else if (strcmp(optarg, "iscsi") == 0) { + set_debug("iscsi"); + } else if (strcmp(optarg, "scsi") == 0) { + set_debug("scsi"); + } else if (strcmp(optarg, "osd") == 0) { + set_debug("osd"); + } else if (strcmp(optarg, "all") == 0) { + set_debug("all"); + } + break; + } + } + + if (!read_conf_file(cf, &tv, &dv, &ev)) { + (void) fprintf(stderr, "Error: can't open `%s'\n", cf); + return EXIT_FAILURE; + } + + (void) signal(SIGPIPE, SIG_IGN); + + (void) signal(SIGINT, handler); + g_main_pid = ISCSI_GETPID; + + if (tv.c == 0) { + (void) fprintf(stderr, "No targets to initialise\n"); + return EXIT_FAILURE; + } + /* Initialize target */ + for (i = optind ; i < argc ; i++) { + if (target_init(&g, &tv, TargetName, i) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_init() failed\n"); + exit(EXIT_FAILURE); + } + } + +#ifdef HAVE_DAEMON + /* if we are supposed to be a daemon, detach from controlling tty */ + if (detach_me_harder && daemon(0, 0) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "daemon() failed\n"); + exit(EXIT_FAILURE); + } +#endif + + /* write pid to a file */ + write_pid_file(_PATH_OSD_PID_FILE); + + /* Wait for connections */ + if (target_listen(&g) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_listen() failed\n"); + } + + return EXIT_SUCCESS; +} diff --git a/external/bsd/iscsi/dist/src/osd.c b/external/bsd/iscsi/dist/src/osd.c new file mode 100644 index 000000000000..a488ae47ff4a --- /dev/null +++ b/external/bsd/iscsi/dist/src/osd.c @@ -0,0 +1,662 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_SYS_MMAN_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_VFS_H +#include +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#ifdef HAVE_ERRNO_H +#include +#endif + +#include + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_UTIME_H +#include +#endif + +#include "scsi_cmd_codes.h" + +#include "iscsi.h" +#include "iscsiutil.h" +#include "device.h" +#include "osd.h" + +/* + * Globals + */ + +static int osd_luns = CONFIG_OSD_LUNS_DFLT; +static uint64_t osd_capacity = CONFIG_OSD_CAPACITY_DFLT * 1048576; +static char base_dir[64] = CONFIG_OSD_BASEDIR_DFLT; + +#ifndef __KERNEL__ +void +device_set_var(const char *var, char *arg) +{ + if (strcmp(var, "capacity") == 0) { + osd_capacity = strtoll(arg, (char **) NULL, 10) * 1048576; + } else if (strcmp(var, "luns") == 0) { + osd_luns = atoi(arg); + } else if (strcmp(var, "directory") == 0) { + (void) strlcpy(base_dir, arg, sizeof(base_dir)); + } else { + (void) fprintf(stderr, "Unrecognised variable: `%s'\n", var); + } +} +#endif + +int +device_init(globals_t *gp, char *dev) +{ + struct stat st; + char FileName[1024]; + int i; + + if (stat(base_dir, &st) < 0) { + + /* Create directory for OSD */ + + if (mkdir(base_dir, 0755) != 0) { + if (errno != EEXIST) { + iscsi_trace_error(__FILE__, __LINE__, "error creating directory \"%s\" for OSD: errno %d\n", base_dir, errno); + return -1; + } + } + /* Create directory for LU */ + + for (i = 0; i < osd_luns; i++) { + sprintf(FileName, "%s/lun_%d", base_dir, i); + if (mkdir(FileName, 0755) != 0) { + if (errno != EEXIST) { + iscsi_trace_error(__FILE__, __LINE__, "error creating \"%s\" for LU %d: errno %d\n", FileName, i, errno); + return -1; + } + } + } + } + /* Display LU info */ + + return 0; +} + +int +osd_read_callback(void *arg) +{ + struct iovec *sg = (struct iovec *) arg; + int i = 0; + + while (sg[i].iov_base != NULL) { + iscsi_free_atomic(sg[i].iov_base); + i++; + } + return 0; +} + +int +device_command(target_session_t * sess, target_cmd_t * cmd) +{ + iscsi_scsi_cmd_args_t *args = cmd->scsi_cmd; + uint8_t *data; + char FileName[1024]; + uint8_t *write_data = NULL; + uint8_t *read_data = NULL; + uint8_t *set_list = NULL; + uint8_t *get_list = NULL; + struct iovec sg[3]; + int sg_len = 0; + int rc; + osd_args_t osd_args; + uint32_t GroupID = 0; + uint64_t UserID = 0; + char string[1024]; + uint8_t *get_data = NULL; + uint32_t page = 0; + uint32_t index = 0; + int attr_len = 0; + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "SCSI op 0x%x (lun %llu)\n", args->cdb[0], args->lun); + + if (args->lun >= osd_luns) { + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "invalid lun: %llu\n", args->lun); + args->status = 0x01; + return 0; + } + args->status = 1; + + switch (args->cdb[0]) { + + case TEST_UNIT_READY: + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "TEST_UNIT_READY(lun %llu)\n", args->lun); + args->status = 0; + args->length = 0; + break; + + case INQUIRY: + + iscsi_trace(TRACE_SCSI_CMD, __FILE__, __LINE__, "INQUIRY(lun %llu)\n", args->lun); + data = args->send_data; + memset(data, 0, args->cdb[4]); /* Clear allocated buffer */ + data[0] = 0x0e; /* Peripheral Device Type */ + /* data[1] |= 0x80; // Removable Bit */ + data[2] |= 0x02;/* ANSI-approved version */ + /* data[3] |= 0x80; // AENC */ + /* data[3] |= 0x40; // TrmIOP */ + /* data[3] |= 0x20; // NormACA */ + data[4] = args->cdb[4] - 4; /* Additional length */ + /* + * data[7] |= 0x80; // Relative + * addressing + */ + data[7] |= 0x40;/* WBus32 */ + data[7] |= 0x20;/* WBus16 */ + /* data[7] |= 0x10; // Sync */ + /* data[7] |= 0x08; // Linked Commands */ + /* data[7] |= 0x04; // TransDis */ + /* + * data[7] |= 0x02; // Tagged Command + * Queueing + */ + /* data[7] |= 0x01; // SftRe */ + (void) memset(data + 8, 0x0, 32); + strlcpy(data + 8, OSD_VENDOR, 8); /* Vendor */ + strlcpy(data + 16, OSD_PRODUCT, 16); /* Product ID */ + (void) snprintf(data + 32, 8, "%d", OSD_VERSION); /* Product Revision */ + args->input = 1; + args->length = args->cdb[4] + 1; + args->status = 0; + + break; + + case 0x7F: + + OSD_DECAP_CDB(args->cdb, args->ext_cdb, &osd_args); + /* OSD_PRINT_CDB(args->cdb, args->ext_cdb); */ + GroupID = osd_args.GroupID; + UserID = osd_args.UserID; + + /* + * Transfer all data + */ + + if (osd_args.set_attributes_list_length) { + if ((set_list = iscsi_malloc_atomic(osd_args.set_attributes_list_length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + sg[sg_len].iov_base = set_list; + sg[sg_len].iov_len = osd_args.set_attributes_list_length; + sg_len++; + } + if (osd_args.get_attributes_list_length) { + if ((get_list = iscsi_malloc_atomic(osd_args.get_attributes_list_length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + sg[sg_len].iov_base = get_list; + sg[sg_len].iov_len = osd_args.get_attributes_list_length; + sg_len++; + } + if (osd_args.service_action == OSD_WRITE) { + if ((write_data = iscsi_malloc_atomic(osd_args.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + sg[sg_len].iov_base = write_data; + sg[sg_len].iov_len = osd_args.length; + sg_len++; + } + if (sg_len) { + if (target_transfer_data(sess, args, sg, sg_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "target_transfer_data() failed\n"); + goto done; + } + } + /* + * Set any attributes + */ + + if (osd_args.set_attributes_list_length) { + uint32_t page, attr; + uint16_t len; + int i; + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_SET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", args->lun, osd_args.GroupID, osd_args.UserID); + for (i = 0; i < osd_args.set_attributes_list_length;) { + page = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i])))); + i += 4; + attr = ISCSI_NTOHL(*((uint32_t *) (&(set_list[i])))); + i += 4; + len = ISCSI_NTOHS(*((uint16_t *) (&(set_list[i])))); + i += 2; + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, attr); + if ((rc = open(FileName, O_WRONLY | O_CREAT, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + goto done; + } + if (write(rc, set_list + i, len) != len) { + iscsi_trace_error(__FILE__, __LINE__, "write() failed\n"); + } + close(rc); + i += len; + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "SET(0x%x,%u,%u>\n", page, attr, len); + } + } + args->send_sg_len = 0; + sg_len = 0; + + switch (osd_args.service_action) { + + case OSD_CREATE_GROUP: + + do { + GroupID = rand() % 1048576 * 1024 + 1; + sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, GroupID); + rc = mkdir(FileName, 0755); + } while (rc == -1 && errno == EEXIST); + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_CREATE_GROUP(lun %llu) --> 0x%x\n", args->lun, GroupID); + args->status = 0; + break; + + case OSD_REMOVE_GROUP: + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_REMOVE_GROUP(lun %llu, 0x%x)\n", args->lun, osd_args.GroupID); + sprintf(FileName, "%s/lun_%llu/0x%x", base_dir, args->lun, osd_args.GroupID); + if ((rc = rmdir(FileName)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "rmdir(\"%s\") failed: errno %d\n", FileName, errno); + goto done; + } + args->status = 0; + break; + + case OSD_CREATE: + + UserID = rand() % 1048576 * 1024 + 1; +create_user_again: + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, UserID); + rc = open(FileName, O_CREAT | O_EXCL | O_RDWR, 0644); + if ((rc == -1) && (errno == EEXIST)) { + UserID = rand() % 1048576 * 1024 + 1; + goto create_user_again; + } + close(rc); + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_CREATE(lun %llu, GroupID 0x%x) --> 0x%llx\n", args->lun, osd_args.GroupID, UserID); + args->status = 0; + + break; + + case OSD_REMOVE: + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_REMOVE(lun %llu, 0x%llx)\n", args->lun, osd_args.UserID); + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if ((rc = unlink(FileName)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "unlink(\"%s\") failed: errno %d\n", FileName, errno); + goto done; + } + sprintf(string, "rm -f %s/lun_%llu/0x%x/0x%llx.*", base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if (system(string) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "\"%s\" failed\n", string); + return -1; + } + args->status = 0; + break; + + case OSD_WRITE: + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_WRITE(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n", + args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset); + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if ((rc = open(FileName, O_WRONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + goto write_done; + } + if (lseek(rc, osd_args.offset, SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno); + goto write_done; + } + if (write(rc, write_data, osd_args.length) != osd_args.length) { + iscsi_trace_error(__FILE__, __LINE__, "write() failed\n"); + goto write_done; + } + close(rc); + args->status = 0; +write_done: + break; + + case OSD_READ: + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_READ(lun %llu, GroupID 0x%x, UserID 0x%llx, length %llu, offset %llu)\n", + args->lun, osd_args.GroupID, osd_args.UserID, osd_args.length, osd_args.offset); + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID); + if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + goto read_done; + } + if ((read_data = iscsi_malloc_atomic(osd_args.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto read_done; + } + if (lseek(rc, osd_args.offset, SEEK_SET) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error seeking \"%s\": errno %d\n", FileName, errno); + goto read_done; + } + if (read(rc, read_data, osd_args.length) != osd_args.length) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed\n"); + goto read_done; + } + close(rc); + args->status = 0; +read_done: + if (args->status == 0) { + args->input = 1; + sg[0].iov_base = read_data; + sg[0].iov_len = osd_args.length; + sg[1].iov_base = NULL; + sg[1].iov_len = 0; + args->send_data = (void *) sg; + args->send_sg_len = 1; + sg_len++; + cmd->callback = osd_read_callback; + cmd->callback_arg = sg; + } else { + if (read_data) + iscsi_free_atomic(read_data); + args->length = 0; /* Need a better way of + * specifying an error.. */ + } + break; + + case OSD_GET_ATTR: + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "OSD_GET_ATTR(lun %llu, GroupID 0x%x, UserID 0x%llx)\n", + args->lun, osd_args.GroupID, osd_args.UserID); + args->status = 0; + break; + + case OSD_SET_ATTR: + args->status = 0; + break; + } + + if (args->status) + goto done; + + /* + * Send back requested attributes + */ + + if (osd_args.get_attributes_list_length || osd_args.get_attributes_page) { + if ((get_data = iscsi_malloc_atomic(osd_args.get_attributes_allocation_length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + goto done; + } + } + if (osd_args.get_attributes_list_length) { + int i; + + for (i = 0; i < osd_args.get_attributes_list_length;) { + page = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i])))); + i += 4; + index = ISCSI_NTOHL(*((uint32_t *) (&(get_list[i])))); + i += 4; + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "GET(0x%x,%u)\n", page, index); + + switch (page) { + case 0x40000001: + switch (index) { + case 0x1: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); + attr_len += 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); + attr_len += 4; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown attr index %u\n", index); + goto done; + } + break; + case 0x00000001: + switch (index) { + case 0x1: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); + attr_len += 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); + attr_len += 4; + break; + case 0x2: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8); + attr_len += 2; + *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID); + attr_len += 8; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown attr index %u\n", index); + goto done; + } + break; + + /* Vendor-specific */ + + case 0x30000000: + switch (index) { + case 0x1: + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480); + attr_len += 2; + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index); + if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + } + if (read(rc, get_data + attr_len, 480) != 480) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed\n"); + goto done; + } + close(rc); + attr_len += 480; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown vendor attr index %u\n", index); + goto done; + } + break; + + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown page 0x%x\n", page); + goto done; + } + } + } + if (osd_args.get_attributes_page) { + + /* + * Right now, if we get a request for an entire page, + * we return only one attribute. + */ + + page = osd_args.get_attributes_page; + + switch (osd_args.get_attributes_page) { + case 0x40000001: + index = 1; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(4); + attr_len += 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(GroupID); + attr_len += 4; + break; + + case 0x00000001: + index = 2; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(8); + attr_len += 2; + *((uint64_t *) & get_data[attr_len]) = ISCSI_HTONLL(UserID); + attr_len += 8; + break; + + case 0x30000000: + index = 1; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(page); + attr_len += 4; + *((uint32_t *) & get_data[attr_len]) = ISCSI_HTONL(index); + attr_len += 4; + *((uint16_t *) & get_data[attr_len]) = ISCSI_HTONS(480); + attr_len += 2; + sprintf(FileName, "%s/lun_%llu/0x%x/0x%llx.0x%x.%u", + base_dir, args->lun, osd_args.GroupID, osd_args.UserID, page, index); + if ((rc = open(FileName, O_RDONLY, 0644)) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "error opening \"%s\": errno %d\n", FileName, errno); + } + if (read(rc, get_data + attr_len, 480) != 480) { + iscsi_trace_error(__FILE__, __LINE__, "read() failed\n"); + goto done; + } + close(rc); + attr_len += 480; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "page not yet supported\n"); + goto done; + } + } + if (attr_len) { + if (attr_len != osd_args.get_attributes_allocation_length) { + iscsi_trace_error(__FILE__, __LINE__, "allocation lengths differ: got %u, expected %u\n", + osd_args.get_attributes_allocation_length, attr_len); + goto done; + } + if (!args->status) { + args->input = 1; + sg[sg_len].iov_base = get_data; + sg[sg_len].iov_len = osd_args.get_attributes_allocation_length; + sg_len++; + sg[sg_len].iov_base = NULL; + sg[sg_len].iov_len = 0; + args->send_data = (void *) sg; + args->send_sg_len++; + cmd->callback = osd_read_callback; + cmd->callback_arg = sg; + } else { + if (get_data) + iscsi_free_atomic(get_data); + } + } + break; + + default: + iscsi_trace_error(__FILE__, __LINE__, "UNKNOWN OPCODE 0x%x\n", args->cdb[0]); + args->status = 0x01; + break; + } + + +done: + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "SCSI op 0x%x: done (status 0x%x)\n", args->cdb[0], args->status); + if (set_list) { + iscsi_free_atomic(set_list); + } + if (get_list) { + iscsi_free_atomic(get_list); + } + if (write_data) { + iscsi_free_atomic(write_data); + } + return 0; +} + +/* ARGSUSED */ +int +device_shutdown(target_session_t *sess) +{ + return 0; +} diff --git a/external/bsd/iscsi/dist/src/osd_ops.c b/external/bsd/iscsi/dist/src/osd_ops.c new file mode 100644 index 000000000000..ebeb13b46189 --- /dev/null +++ b/external/bsd/iscsi/dist/src/osd_ops.c @@ -0,0 +1,416 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2002, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Transport-independent Methods + */ +#include "config.h" + + +#include "osd.h" +#include "iscsiutil.h" +#include "compat.h" +#include "osd_ops.h" + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +static int +extract_attribute(uint32_t page, uint32_t n, uint16_t len, + uint8_t * data, unsigned length, void *val) +{ + int i = 0; + + for (i = 0; i < length;) { + if (ISCSI_NTOHL(*(uint32_t *) (data + i)) != page) { + iscsi_trace_error(__FILE__, __LINE__, "page mismatch: got 0x%x, expected 0x%x\n", ISCSI_NTOHL(*(uint32_t *) (data + i)), page); + return -1; + } + i += 4; + if (ISCSI_NTOHL(*(uint32_t *) (data + i)) != n) { + iscsi_trace_error(__FILE__, __LINE__, "index mismatch\n"); + return -1; + } + i += 4; + if (ISCSI_NTOHS(*(uint16_t *) (data + i)) != len) { + iscsi_trace_error(__FILE__, __LINE__, "len mismatch\n"); + return -1; + } + i += 2; + iscsi_trace(TRACE_DEBUG, __FILE__, __LINE__, "page 0x%x, index %u, len %u\n", page, n, len); + memcpy(val, data + i, len); + i += len; + } + iscsi_trace(TRACE_DEBUG, __FILE__, __LINE__, "parsed %i bytes\n", i); + return i; +} + + +int +osd_create_group(void *dev, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem), + uint32_t * GroupID) +{ + osd_args_t args; +#if 0 + uint8_t get_list[8]; +#endif + uint8_t get_data[14]; + OSD_OPS_MEM mem; + + mem.recv_data = get_data; + mem.recv_len = 14; + mem.recv_sg = 0; + + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_CREATE_GROUP; + +#if 0 + args.length = 8; + args.get_attributes_list_length = 8; + *((unsigned long *) get_list) = ISCSI_HTONL(0x40000001); + *((unsigned long *) (get_list + 4)) = ISCSI_HTONL(0x1); + mem.send_data = get_list; + mem.send_len = 8; + mem.send_sg = 0; +#else + args.get_attributes_page = 0x40000001; + mem.send_data = NULL; + mem.send_len = 0; + mem.send_sg = 0; +#endif + + args.get_attributes_allocation_length = 14; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + if (extract_attribute(0x40000001, 0x1, 4, get_data, 14, GroupID) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "extract_attributes() failed\n"); + return -1; + } + *GroupID = ISCSI_NTOHL(*GroupID); + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_create_group() OK --> GroupID 0x%x\n", *GroupID); + + return 0; +} + +int +osd_create(void *dev, uint32_t GroupID, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem), + uint64_t * UserID) +{ + osd_args_t args; +#if 0 + uint8_t get_list[8]; +#endif + uint8_t get_data[18]; + OSD_OPS_MEM mem; + + mem.recv_data = get_data; + mem.recv_len = 18; + mem.recv_sg = 0; + + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_CREATE; + args.GroupID = GroupID; + +#if 0 + args.length = 8; + args.get_attributes_list_length = 8; + *((unsigned long *) get_list) = ISCSI_HTONL(0x00000001); + *((unsigned long *) (get_list + 4)) = ISCSI_HTONL(0x2); + mem.send_data = get_list; + mem.send_len = 8; + mem.send_sg = 0; +#else + args.get_attributes_page = 0x000000001; + mem.send_data = NULL; + mem.send_len = 0; + mem.send_sg = 0; +#endif + + args.get_attributes_allocation_length = 18; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + if (extract_attribute(0x00000001, 0x2, 8, get_data, 18, UserID) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "extract_attributes() failed\n"); + return -1; + } + *UserID = ISCSI_NTOHLL(*UserID); + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_create(GroupID 0x%x) OK --> UserID 0x%llx\n", GroupID, *UserID); + + return 0; +} + +int +osd_remove_group(void *dev, uint32_t GroupID, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem)) +{ + osd_args_t args; + OSD_OPS_MEM mem; + + mem.send_data = NULL; + mem.send_len = 0; + mem.send_sg = 0; + mem.recv_data = NULL; + mem.recv_len = 0; + mem.recv_sg = 0; + + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_REMOVE_GROUP; + args.GroupID = GroupID; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_remove_group(Group ID 0x%x) OK\n", GroupID); + + return 0; +} + +int +osd_remove(void *dev, uint32_t GroupID, uint64_t UserID, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem)) +{ + osd_args_t args; + OSD_OPS_MEM mem; + + mem.send_data = NULL; + mem.send_len = 0; + mem.send_sg = 0; + mem.recv_data = NULL; + mem.recv_len = 0; + mem.recv_sg = 0; + + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_REMOVE; + args.UserID = UserID; + args.GroupID = GroupID; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_remove(GroupID 0x%x, UserID 0x%llx) OK\n", GroupID, UserID); + + return 0; +} + +int +osd_write(void *dev, + uint32_t GroupID, uint64_t UserID, uint64_t offset, uint64_t len, const void *send_data, int sg_len, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem)) +{ + osd_args_t args; + OSD_OPS_MEM mem; + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_write(GroupID 0x%x, UserID 0x%llx, Offset %llu, Len %llu)\n", GroupID, UserID, offset, len); + mem.send_data = send_data; + mem.send_len = len; + mem.send_sg = sg_len; + mem.recv_data = NULL; + mem.recv_len = 0; + mem.recv_sg = 0; + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_WRITE; + args.GroupID = GroupID; + args.UserID = UserID; + args.offset = offset; + args.length = len; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + return 0; +} + +int +osd_read(void *dev, + uint32_t GroupID, uint64_t UserID, uint64_t offset, uint64_t len, void *recv_data, int sg_len, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem)) +{ + osd_args_t args; + OSD_OPS_MEM mem; + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_read(GroupID 0x%x, UserID 0x%llx, Offset %llu, Len %llu)\n", GroupID, UserID, offset, len); + mem.send_data = NULL; + mem.send_len = 0; + mem.send_sg = 0; + mem.recv_data = recv_data; + mem.recv_len = len; + mem.recv_sg = sg_len; + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_READ; + args.GroupID = GroupID; + args.UserID = UserID; + args.offset = offset; + args.length = len; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + return 0; +} + +int +osd_set_one_attr(void *dev, + uint32_t GroupID, uint64_t UserID, uint32_t page, uint32_t n, uint32_t len, void *value, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem)) +{ + osd_args_t args; + OSD_OPS_MEM mem; + uint8_t list[10]; +#if 0 + struct iovec sg[2]; +#else + uint8_t *buffer = NULL; +#endif + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_set_one_attr(GroupID 0x%x, UserID 0x%llx, Page 0x%x, Index %u, Len %u)\n", + GroupID, UserID, page, n, len); + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_SET_ATTR; + args.GroupID = GroupID; + args.UserID = UserID; + args.length = 10 + len; + args.set_attributes_list_length = 10 + len; + *((uint32_t *) (list + 0)) = ISCSI_HTONL(page); + *((uint32_t *) (list + 4)) = ISCSI_HTONL(n); + *((uint16_t *) (list + 8)) = ISCSI_HTONS(len); +#if 0 + sg[0].iov_base = list; + sg[0].iov_len = 10; + sg[1].iov_base = value; + sg[1].iov_len = len; + mem.send_data = sg; + mem.send_len = 10 + len; + mem.send_sg = 2; +#else + if ((buffer = iscsi_malloc_atomic(10 + len)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + memcpy(buffer, list, 10); + memcpy(buffer + 10, value, len); + mem.send_data = buffer; + mem.send_len = 10 + len; + mem.send_sg = 0; +#endif + mem.recv_data = NULL; + mem.recv_len = 0; + mem.recv_sg = 0; + + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + if (buffer) + iscsi_free_atomic(buffer); + + return 0; +} + +int +osd_get_one_attr(void *dev, + uint32_t GroupID, uint64_t UserID, uint32_t page, uint32_t n, uint32_t alloc_len, + int (*osd_exec) (void *dev, osd_args_t * args, OSD_OPS_MEM * mem), + uint16_t * len, void *value) +{ + osd_args_t args; + OSD_OPS_MEM mem; + uint8_t list_out[8]; +#if 0 + uint8_t list_in[10]; + struct iovec sg[2]; +#else + uint8_t *buffer; +#endif + + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "osd_get_one_attr(GroupID 0x%x, UserID 0x%llx, Page 0x%x, Index %u, Alloc Len %u)\n", + GroupID, UserID, page, n, alloc_len); + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7F; + args.service_action = OSD_GET_ATTR; + args.GroupID = GroupID; + args.UserID = UserID; + if (n) { + args.length = 8; + *((uint32_t *) (list_out + 0)) = ISCSI_HTONL(page); + *((uint32_t *) (list_out + 4)) = ISCSI_HTONL(n); + args.get_attributes_list_length = 8; + mem.send_data = list_out; + mem.send_len = 8; + mem.send_sg = 0; + } else { + iscsi_trace(TRACE_OSD, __FILE__, __LINE__, "requesting entire page or reference page\n"); + mem.send_data = NULL; + mem.send_len = 0; + mem.send_sg = 0; + args.get_attributes_page = page; + } +#if 0 + sg[0].iov_base = list_in; + sg[0].iov_len = 10; + sg[1].iov_base = value; + sg[1].iov_len = alloc_len; + mem.recv_data = sg; + mem.recv_len = 10 + alloc_len; + mem.recv_sg = 2; +#else + if ((buffer = iscsi_malloc_atomic(10 + alloc_len)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + mem.recv_data = buffer; + mem.recv_len = 10 + alloc_len; + mem.recv_sg = 0; +#endif + args.get_attributes_allocation_length = 10 + alloc_len; + if (osd_exec(dev, &args, &mem) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_exec() failed\n"); + return -1; + } + memcpy(value, buffer + 10, alloc_len); + if (buffer) + iscsi_free_atomic(buffer); + return 0; +} diff --git a/external/bsd/iscsi/dist/src/osdfs.c b/external/bsd/iscsi/dist/src/osdfs.c new file mode 100644 index 000000000000..c3b0fa4be36c --- /dev/null +++ b/external/bsd/iscsi/dist/src/osdfs.c @@ -0,0 +1,1076 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2002, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Object-Based Storage Devices (OSD) Filesystem for Linux + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "osd.h" +#include "osd_ops.h" +#include "iscsiutil.h" +#include "util.c" + + +/* + * Contants + */ + + +#define OSDFS_MAGIC 0xabcdef01 +#define MAX_INODES 32768 +#define MAX_NAME_LEN 32 + + +/* + * Types + */ + + +typedef struct osdfs_link_t { + char name[MAX_NAME_LEN]; + struct osdfs_link_t* next; +} osdfs_link_t; + +typedef struct osdfs_inode_t { + osdfs_link_t *link; +} osdfs_inode_t; + +typedef struct osdfs_metadata_t { + uint64_t ObjectID; + int used; +} osdfs_metadata_t; + + +/* + * Prototypes + */ + +static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev); + + +/* + * Globals + */ + + +static struct super_operations osdfs_ops; +static struct address_space_operations osdfs_aops; +static struct file_operations osdfs_dir_operations; +static struct file_operations osdfs_file_operations; +static struct inode_operations osdfs_dir_inode_operations; +static uint32_t root_gid; +static uint64_t root_uid; +static iscsi_mutex_t g_mutex; + + +/* + * SCSI transport function for OSD + */ + + +int osd_exec_via_scsi(void *dev, osd_args_t *args, OSD_OPS_MEM *m) { + Scsi_Request *SRpnt; + Scsi_Device *SDpnt; + unsigned char cdb[256]; + kdev_t kdev = *((kdev_t *) dev); + void *ptr = NULL; + int len = 0; + + if (m->send_sg||m->recv_sg) { + iscsi_trace_error("scatter/gather not yet implemented!\n"); + return -1; + } + + SDpnt = blk_dev[MAJOR(kdev)].queue(kdev)->queuedata; + SRpnt = scsi_allocate_request(SDpnt); + SRpnt->sr_cmd_len = CONFIG_OSD_CDB_LEN; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + switch(args->service_action) { + case OSD_WRITE: + case OSD_SET_ATTR: + len = m->send_len; + ptr = m->send_data; + SRpnt->sr_data_direction = SCSI_DATA_WRITE; + break; + case OSD_CREATE: + case OSD_CREATE_GROUP: + case OSD_READ: + case OSD_GET_ATTR: + len = m->recv_len; + ptr = m->recv_data; + SRpnt->sr_data_direction = SCSI_DATA_READ; + break; + case OSD_REMOVE: + case OSD_REMOVE_GROUP: + SRpnt->sr_data_direction = 0; + break; + default: + iscsi_trace_error("unsupported OSD service action 0x%x\n", args->service_action); + return -1; + } + OSD_ENCAP_CDB(args, cdb); + + /* Exec SCSI command */ + + scsi_wait_req(SRpnt, cdb, ptr, len, 5*HZ, 5); + if (SRpnt->sr_result!=0) { + iscsi_trace_error("SCSI command failed (result %u)\n", SRpnt->sr_result); + scsi_release_request(SRpnt); + SRpnt = NULL; + return -1; + } + scsi_release_request(SRpnt); + SRpnt = NULL; + + return 0; +} + +/* + * Internal OSDFS functions + */ + + +/* Directory operations */ + +static int entries_get(kdev_t dev, uint64_t uid, char **entries, uint32_t *num, uint64_t *size) { + struct inode inode; + uint16_t len; + + if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, (void *) &inode)!=0) { + iscsi_trace_error("osd_get_one_attr() failed\n"); + return -1; + } + *num = 0; + if ((*size=inode.i_size)) { + char *ptr, *ptr2; + int n = 0; + + if ((*entries=vmalloc(*size+1))==NULL) { + iscsi_trace_error("vmalloc() failed\n"); + return -1; + } + if (osd_read((void *)&dev, root_gid, uid, 0, *size, *entries, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_read() failed\n"); + vfree(*entries); + return -1; + } + (*entries)[*size] = 0x0; + ptr = *entries; + do { + n++; + if ((ptr2=strchr(ptr, '\n'))!=NULL) { + n++; + if ((ptr2 = strchr(ptr2+1, '\n'))==NULL) { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", uid, n); + return -1; + } + (*num)++; + } else { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", uid, n); + return -1; + } + ptr = ptr2+1; + } while (*ptr); + } + + return 0; +} + +static int entry_add(kdev_t dev, ino_t dir_ino, ino_t entry_ino, + const char *name, uint64_t *new_size) { + char entry[MAX_NAME_LEN+16]; + uint64_t uid = dir_ino; + struct inode inode; + uint16_t len; + + /* Get size of directory */ + + if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, (void *) &inode)!=0) { + iscsi_trace_error("osd_get_one_attr() failed\n"); + return -1; + } + + /* Write entry at end */ + + sprintf(entry, "%s\n", name); + sprintf(entry+strlen(entry), "%li\n", entry_ino); + if (osd_write((void *)&dev, root_gid, uid, inode.i_size, strlen(entry), entry, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_write() failed\n"); + return -1; + } + *new_size += strlen(entry); + + return 0; +} + +static int entry_del(kdev_t dev, ino_t dir_ino, ino_t ino, const char *name, uint64_t *new_size) { + char *entries; + uint32_t num_entries; + uint64_t size; + uint64_t dir_uid = (unsigned) dir_ino; + + /* Read */ + + if (entries_get(dev, dir_ino, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + return -1; + } + entries[size] = 0x0; + + iscsi_trace(TRACE_OSDFS, "dir_ino 0x%llx has %u entries\n", dir_uid, num_entries); + if (num_entries) { + char *ptr = entries; + char *tmp = NULL; + char *nl; + int n = 0; + + do { + n++; + if ((nl=strchr(ptr, '\n'))==NULL) { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", dir_uid, n); + return -1; + } + *nl = 0x0; + if (!strcmp(ptr, name)) { + tmp = ptr; + } + *nl = '\n'; + n++; + if ((ptr=strchr(nl+1, '\n'))==NULL) { + iscsi_trace_error("directory 0x%llx corrupted (line %i)\n", dir_uid, n); + return -1; + } + ptr++; + } while (!tmp && *ptr); + + if (!tmp) { + iscsi_trace_error("entry \"%s\" not found in dir 0x%llx\n", name, dir_uid); + return -1; + } + if (entries+size-ptr) { + iscsi_trace(TRACE_OSDFS, "writing remaining %u directory bytes at offset %u\n", + entries+size-ptr, tmp-entries); + if (osd_write((void *)&dev, root_gid, dir_uid, tmp-entries, entries+size-ptr, ptr, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_write() failed\n"); + return -1; + } + } + *new_size = size-(ptr-tmp); + vfree(entries); + } else { + iscsi_trace_error("dir 0x%llx has no entries\n", dir_uid); + return -1; + } + + return 0; +} + +static int entry_num(kdev_t dev, ino_t ino) { + char *entries; + uint32_t num_entries; + uint64_t size; + + if (entries_get(dev, ino, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", ino, num_entries); + if (num_entries) vfree(entries); + return num_entries; +} + +/* Inode operations */ + +static void osdfs_set_ops(struct inode *inode) { + switch (inode->i_mode & S_IFMT) { + case S_IFREG: + inode->i_fop = &osdfs_file_operations; + break; + case S_IFDIR: + inode->i_op = &osdfs_dir_inode_operations; + inode->i_fop = &osdfs_dir_operations; + break; + case S_IFLNK: + inode->i_op = &page_symlink_inode_operations; + break; + default: + iscsi_trace_error("UNKNOWN MODE\n"); + } + inode->i_mapping->a_ops = &osdfs_aops; +} + +static struct inode *osdfs_get_inode(struct super_block *sb, int mode, int dev, const char *name, + uint64_t ObjectID) { + struct inode *inode; + ino_t ino = ObjectID; + + iscsi_trace(TRACE_OSDFS, "osdfs_get_inode(\"%s\", mode %i (%s))\n", name, mode, + S_ISDIR(mode)?"DIR":(S_ISREG(mode)?"REG":"LNK")); + + /* iget() gets a free VFS inode and subsequently call */ + /* osdfds_read_inode() to fill the inode structure. */ + + if ((inode=iget(sb, ino))==NULL) { + iscsi_trace_error("iget() failed\n"); + return NULL; + } + + return inode; +} + + +/* + * Super Operations + */ + + +static void osdfs_read_inode(struct inode *inode) { + ino_t ino = inode->i_ino; + kdev_t dev = inode->i_sb->s_dev; + uint64_t uid = ino; + unsigned char *attr; + uint16_t len; + + iscsi_trace(TRACE_OSDFS, "osdfs_read_inode(ino 0x%x, major %i, minor %i)\n", + (unsigned) ino, MAJOR(dev), MINOR(dev)); + + /* Get object attributes for rest of inode */ + + if ((attr=iscsi_malloc_atomic(sizeof(struct inode)))==NULL) { + iscsi_trace_error("iscsi_malloc_atomic() failed\n"); + } + if (osd_get_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x0, sizeof(struct inode), &osd_exec_via_scsi, &len, attr)!=0) { + iscsi_trace_error("osd_get_one_attr() failed\n"); + return; + } + + inode->i_size = ((struct inode *)(attr))->i_size; + inode->i_mode = ((struct inode *)(attr))->i_mode; + inode->i_nlink = ((struct inode *)(attr))->i_nlink; + inode->i_gid = ((struct inode *)(attr))->i_gid; + inode->i_uid = ((struct inode *)(attr))->i_uid; + inode->i_ctime = ((struct inode *)(attr))->i_ctime; + inode->i_atime = ((struct inode *)(attr))->i_atime; + inode->i_mtime = ((struct inode *)(attr))->i_mtime; + + iscsi_free_atomic(attr); + + osdfs_set_ops(inode); +} + +void osdfs_dirty_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_dirty_inode(ino 0x%x)\n", (unsigned) inode->i_ino); +} + +void osdfs_write_inode(struct inode *inode, int sync) { + ino_t ino = inode->i_ino; + kdev_t dev = inode->i_sb->s_dev; + uint64_t uid = ino; + + iscsi_trace(TRACE_OSDFS, "osdfs_write_inode(0x%llx)\n", uid); + + if (osd_set_one_attr((void *)&dev, root_gid, uid, 0x30000000, 0x1, sizeof(struct inode), (void *) inode, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_set_one_attr() failed\n"); + } + inode->i_state &= ~I_DIRTY; +} + +void osdfs_put_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_put_inode(0x%x)\n", (unsigned) inode->i_ino); +} + +void osdfs_delete_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_delete_inode(%lu)\n", inode->i_ino); + clear_inode(inode); +} + +void osdfs_put_super(struct super_block *sb) { + iscsi_trace_error("osdfs_put_super() not implemented\n"); +} + +void osdfs_write_super(struct super_block *sb) { + iscsi_trace_error("osdfs_write_super() not implemented\n"); +} + +void osdfs_write_super_lockfs(struct super_block *sb) { + iscsi_trace_error("osdfs_write_super_lockfs() not implemented\n"); +} + +void osdfs_unlockfs(struct super_block *sb) { + iscsi_trace_error("osdfs_unlockfs() not implemented\n"); +} + +int osdfs_statfs(struct super_block *sb, struct statfs *buff) { + iscsi_trace(TRACE_OSDFS, "statfs()\n"); + buff->f_type = OSDFS_MAGIC; + buff->f_bsize = PAGE_CACHE_SIZE; + buff->f_blocks = 256; + buff->f_bfree = 128; + buff->f_bavail = 64; + buff->f_files = 0; + buff->f_ffree = 0; + buff->f_namelen = MAX_NAME_LEN; + + return 0; +} + +int osdfs_remount_fs(struct super_block *sb, int *i, char *c) { + iscsi_trace_error("osdfs_remount_fs() not implemented\n"); + + return -1; +} + +void osdfs_clear_inode(struct inode *inode) { + iscsi_trace(TRACE_OSDFS, "osdfs_clear_inode(ino %lu)\n", inode->i_ino); +} + +void osdfs_umount_begin(struct super_block *sb) { + iscsi_trace_error("osdfs_unmount_begin() not implemented\n"); +} + +static struct super_operations osdfs_ops = { + read_inode: osdfs_read_inode, + dirty_inode: osdfs_dirty_inode, + write_inode: osdfs_write_inode, + put_inode: osdfs_put_inode, + delete_inode: osdfs_delete_inode, + put_super: osdfs_put_super, + write_super: osdfs_write_super, + write_super_lockfs: osdfs_write_super_lockfs, + unlockfs: osdfs_unlockfs, + statfs: osdfs_statfs, + remount_fs: osdfs_remount_fs, + clear_inode: osdfs_clear_inode, + umount_begin: osdfs_umount_begin +}; + + +/* + * Inode operations for directories + */ + + +static int osdfs_create(struct inode *dir, struct dentry *dentry, int mode) { + + iscsi_trace(TRACE_OSDFS, "osdfs_create(\"%s\")\n", dentry->d_name.name); + if (osdfs_mknod(dir, dentry, mode | S_IFREG, 0)!=0) { + iscsi_trace_error("osdfs_mknod() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSDFS, "file \"%s\" is inode 0x%x\n", dentry->d_name.name, (unsigned) dentry->d_inode->i_ino); + + return 0; +} + +static struct dentry * osdfs_lookup(struct inode *dir, struct dentry *dentry) { + const char *name = dentry->d_name.name; + struct inode *inode = NULL; + ino_t ino; + kdev_t dev = dir->i_sb->s_dev; + uint64_t uid = dir->i_ino; + char *entries; + uint32_t num_entries; + uint64_t size; + + iscsi_trace(TRACE_OSDFS, "osdfs_lookup(\"%s\" in dir ino %lu)\n", name, dir->i_ino); + + /* Get directory entries */ + + ISCSI_LOCK(&g_mutex, return NULL); + if (entries_get(dev, uid, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + ISCSI_UNLOCK(&g_mutex, return NULL); + return NULL; + } + ISCSI_UNLOCK(&g_mutex, return NULL); + iscsi_trace(TRACE_OSDFS, "ino %li has %i entries\n", dir->i_ino, num_entries); + + /* Search for this entry */ + + if (num_entries) { + char *ptr = entries; + char *ptr2; + + do { + if ((ptr2=strchr(ptr, '\n'))!=NULL) { + *ptr2 = 0x0; + ptr2 = strchr(ptr2+1, '\n'); + if (!strcmp(ptr, name)) { + sscanf(ptr+strlen(ptr)+1, "%li", &ino); + iscsi_trace(TRACE_OSDFS, "found \"%s\" at ino %li\n", name, ino); + if ((inode=iget(dir->i_sb, ino))==NULL) { + iscsi_trace_error("iget() failed\n"); + return NULL; + } + } + } + } while (ptr2&&(ptr=ptr2+1)); + vfree(entries); + } + if (!inode) { + iscsi_trace(TRACE_OSDFS, "\"%s\" not found\n", name); + } + d_add(dentry, inode); + + return NULL; +} + +static int osdfs_link(struct dentry *old_dentry, struct inode * dir, struct dentry * dentry) { + struct inode *inode = old_dentry->d_inode; + kdev_t dev = dir->i_sb->s_dev; + ino_t dir_ino = dir->i_ino; + ino_t ino = inode->i_ino; + const char *name = dentry->d_name.name; + + if (S_ISDIR(inode->i_mode)) return -EPERM; + iscsi_trace(TRACE_OSDFS, "osdfs_link(%lu, \"%s\")\n", ino, name); + ISCSI_LOCK(&g_mutex, return -1); + if (entry_add(dev, dir_ino, ino, name, &dir->i_size)!=0) { + iscsi_trace_error("entry_add() failed\n"); + return -1; + } + inode->i_nlink++; + atomic_inc(&inode->i_count); + osdfs_write_inode(inode, 0); + osdfs_write_inode(dir, 0); + d_instantiate(dentry, inode); + ISCSI_UNLOCK(&g_mutex, return -1); + + return 0; +} + +static int osdfs_unlink(struct inode * dir, struct dentry *dentry) { + kdev_t dev = dir->i_sb->s_dev; + struct inode *inode = dentry->d_inode; + ino_t dir_ino = dir->i_ino; + ino_t ino = dentry->d_inode->i_ino; + const char *name = dentry->d_name.name; + + iscsi_trace(TRACE_OSDFS, "osdfs_unlink(\"%s\", ino 0x%x)\n", name, (unsigned) ino); + ISCSI_LOCK(&g_mutex, return -1); + switch (inode->i_mode & S_IFMT) { + case S_IFREG: + case S_IFLNK: + break; + case S_IFDIR: + if (entry_num(dev, ino)) { + iscsi_trace_error("directory 0x%x still has %i entries\n", + (unsigned) ino, entry_num(dev, ino)); + ISCSI_UNLOCK(&g_mutex, return -1); + return -ENOTEMPTY; + } + } + if (entry_del(dev, dir_ino, ino, name, &(dir->i_size))!=0) { + iscsi_trace_error("entry_del() failed\n"); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + osdfs_write_inode(dir, 0); + if (--inode->i_nlink) { + iscsi_trace(TRACE_OSDFS, "ino 0x%x still has %i links\n", (unsigned) ino, inode->i_nlink); + osdfs_write_inode(inode, 0); + } else { + iscsi_trace(TRACE_OSDFS, "ino 0x%x link count reached 0, removing object\n", (unsigned) ino); + if (osd_remove((void *)&dev, root_gid, ino, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_remove() failed\n"); + return -1; + } + } + ISCSI_UNLOCK(&g_mutex, return -1); + + return 0; +} + +static int osdfs_symlink(struct inode * dir, struct dentry *dentry, const char * symname) { + struct inode *inode; + + iscsi_trace(TRACE_OSDFS, "osdfs_symlink(\"%s\"->\"%s\")\n", dentry->d_name.name, symname); + if (osdfs_mknod(dir, dentry, S_IRWXUGO | S_IFLNK, 0)!=0) { + iscsi_trace_error("osdfs_mknod() failed\n"); + return -1; + } + inode = dentry->d_inode; + if (block_symlink(inode, symname, strlen(symname)+1)!=0) { + iscsi_trace_error("block_symlink() failed\n"); + return -1; + } + iscsi_trace(TRACE_OSDFS, "symbolic link \"%s\" is inode %lu\n", dentry->d_name.name, inode->i_ino); + + return 0; +} + +static int osdfs_mkdir(struct inode * dir, struct dentry * dentry, int mode) { + + iscsi_trace(TRACE_OSDFS, "osdfs_mkdir(\"%s\")\n", dentry->d_name.name); + if (osdfs_mknod(dir, dentry, mode | S_IFDIR, 0)!=0) { + iscsi_trace_error("osdfs_mkdir() failed\n"); + } + + return 0; +} + +static int osdfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev_in) { + struct inode *inode = NULL; + uint64_t uid; + struct inode attr; + kdev_t dev = dir->i_sb->s_dev; + const char *name = dentry->d_name.name; + + iscsi_trace(TRACE_OSDFS, "osdfs_mknod(\"%s\")\n", dentry->d_name.name); + + /* Create object */ + + if (osd_create((void *)&dev, root_gid, &osd_exec_via_scsi, &uid)!=0) { + iscsi_trace_error("osd_create() failed\n"); + return -1; + } + + /* Initialize object attributes */ + + memset(&attr, 0, sizeof(struct inode)); + attr.i_mode = mode; + attr.i_uid = current->fsuid; + attr.i_gid = current->fsgid; + attr.i_ctime = CURRENT_TIME; + attr.i_atime = CURRENT_TIME; + attr.i_mtime = CURRENT_TIME; + attr.i_nlink = 1; + if (osd_set_one_attr((void *)&dir->i_sb->s_dev, root_gid, uid, 0x30000000, 0x1, sizeof(struct inode), + &attr, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_set_one_attr() failed\n"); + return -1; + } + + /* Assign to an inode */ + + if ((inode = osdfs_get_inode(dir->i_sb, mode, dev, name, uid))==NULL) { + iscsi_trace_error("osdfs_get_inode() failed\n"); + return -ENOSPC; + } + d_instantiate(dentry, inode); + + /* Add entry to parent directory */ + + if (inode->i_ino != 1) { + ISCSI_LOCK(&g_mutex, return -1); + if (entry_add(dev, dir->i_ino, inode->i_ino, name, &dir->i_size)!=0) { + iscsi_trace_error("entry_add() failed\n"); + return -1; + } + osdfs_write_inode(dir, 0); + ISCSI_UNLOCK(&g_mutex, return -1); + } + + return 0; +} + +static int osdfs_rename(struct inode *old_dir, struct dentry *old_dentry, struct inode *new_dir, struct dentry *new_dentry) { + kdev_t dev = old_dir->i_sb->s_dev; + ino_t old_dir_ino = old_dir->i_ino; + ino_t new_dir_ino = new_dir->i_ino; + ino_t old_ino = old_dentry->d_inode->i_ino; + ino_t new_ino = new_dentry->d_inode?new_dentry->d_inode->i_ino:old_ino; + const char *old_name = old_dentry->d_name.name; + const char *new_name = new_dentry->d_name.name; + + iscsi_trace(TRACE_OSDFS, "old_dir = 0x%p (ino 0x%x)\n", old_dir, (unsigned) old_dir_ino); + iscsi_trace(TRACE_OSDFS, "new_dir = 0x%p (ino 0x%x)\n", new_dir, (unsigned) new_dir_ino); + iscsi_trace(TRACE_OSDFS, "old_dentry = 0x%p (ino 0x%x)\n", old_dentry, (unsigned) old_ino); + iscsi_trace(TRACE_OSDFS, "new_dentry = 0x%p (ino 0x%x)\n", new_dentry, (unsigned) new_ino); + + /* + * If we return -1, the VFS will implement a rename with a combination + * of osdfs_unlink() and osdfs_create(). + */ + + /* Delete entry from old directory */ + + ISCSI_LOCK(&g_mutex, return -1); + if (entry_del(dev, old_dir_ino, old_ino, old_name, &old_dir->i_size)!=0) { + iscsi_trace_error("error deleting old entry \"%s\"\n", old_name); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + osdfs_write_inode(old_dir, 0); + ISCSI_UNLOCK(&g_mutex, return -1); + + /* Unlink entry from new directory */ + + if (new_dentry->d_inode) { + iscsi_trace(TRACE_OSDFS, "unlinking existing file\n"); + if (osdfs_unlink(new_dir, new_dentry)!=0) { + iscsi_trace_error("osdfs_unlink() failed\n"); + return -1; + } + } + + /* Add entry to new directory (might be the same dir) */ + + ISCSI_LOCK(&g_mutex, return -1); + if (entry_add(dev, new_dir_ino, new_ino, new_name, &new_dir->i_size)!=0) { + iscsi_trace_error("error adding new entry \"%s\"\n", new_name); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + osdfs_write_inode(new_dir, 0); + ISCSI_UNLOCK(&g_mutex, return -1); + + return 0; +} + +static struct inode_operations osdfs_dir_inode_operations = { + create: osdfs_create, + lookup: osdfs_lookup, + link: osdfs_link, + unlink: osdfs_unlink, + symlink: osdfs_symlink, + mkdir: osdfs_mkdir, + rmdir: osdfs_unlink, + mknod: osdfs_mknod, + rename: osdfs_rename, +}; + + +/* + * File operations (regular files) + */ + + +static int osdfs_sync_file(struct file * file, struct dentry *dentry, int datasync) { + iscsi_trace_error("osdfs_syncfile() not implemented\n"); + return -1; +} + +static struct file_operations osdfs_file_operations = { + read: generic_file_read, + write: generic_file_write, + mmap: generic_file_mmap, + fsync: osdfs_sync_file, +}; + + +/* + * File operations (directories) + */ + + +static int osdfs_readdir(struct file * filp, void * dirent, filldir_t filldir) { + struct dentry *dentry = filp->f_dentry; + const char *name; + ino_t ino = dentry->d_inode->i_ino; + kdev_t dev = dentry->d_inode->i_sb->s_dev; + int offset = filp->f_pos; + char *entries, *ptr, *ptr2; + uint32_t num_entries; + uint64_t size; + uint64_t uid = ino; + + name = dentry->d_name.name; + iscsi_trace(TRACE_OSDFS, "osdfs_readdir(\"%s\", ino 0x%x, offset %i)\n", + name, (unsigned) ino, offset); + ISCSI_LOCK(&g_mutex, return -1); + if (entries_get(dev, uid, &entries, &num_entries, &size)!=0) { + iscsi_trace_error("entries_get() failed\n"); + ISCSI_UNLOCK(&g_mutex, return -1); + return -1; + } + ISCSI_UNLOCK(&g_mutex, return -1); + + /* Update the offset if our number of entries has changed since the last */ + /* call to osdfs_readdir(). filp->private_data stores the number of */ + /* entries this directory had on the last call. */ + + if (offset) { + if (((int)filp->private_data)>num_entries) { + filp->f_pos = offset -= (((int)filp->private_data)-num_entries); + filp->private_data = (void *) num_entries; + } + } else { + filp->private_data = (void *) num_entries; + } + + switch (offset) { + + case 0: + + iscsi_trace(TRACE_OSDFS, "adding \".\" (ino 0x%x)\n", (unsigned) ino); + if (filldir(dirent, ".", 1, filp->f_pos++, ino, DT_DIR) < 0) { + iscsi_trace_error("filldir() failed for \".\"??\n"); + vfree(entries); + return -1; + } + + case 1: + + iscsi_trace(TRACE_OSDFS, "adding \"..\" (ino 0x%x)\n", (unsigned) dentry->d_parent->d_inode->i_ino); + if (filldir(dirent, "..", 2, filp->f_pos++, dentry->d_parent->d_inode->i_ino, DT_DIR) < 0) { + iscsi_trace_error("filldir() failed for \"..\"??\n"); + vfree(entries); + return -1; + } + + default: + + if (!num_entries) return 0; + ptr = entries; + offset -= 2; + do { + if ((ptr2=strchr(ptr, '\n'))!=NULL) { + *ptr2 = 0x0; + ptr2 = strchr(ptr2+1, '\n'); + if (offset>0) { + offset--; + } else { + sscanf(ptr+strlen(ptr)+1, "%li", &ino); + iscsi_trace(TRACE_OSDFS, "adding \"%s\" (ino 0x%x)\n", ptr, (unsigned) ino); + if (filldir(dirent, ptr, strlen(ptr), filp->f_pos++, ino, DT_UNKNOWN) < 0) { + vfree(entries); + return 0; + } + } + } + } while (ptr2&&(ptr=ptr2+1)); + } + if (num_entries) vfree(entries); + + return 0; +} + +static struct file_operations osdfs_dir_operations = { + read: generic_read_dir, + readdir: osdfs_readdir, + fsync: osdfs_sync_file, +}; + + +/* + * Address space operations + */ + + +static int osdfs_readpage(struct file *file, struct page * page) { + uint64_t Offset = page->index<mapping->host; + kdev_t dev = inode->i_sb->s_dev; + ino_t ino = inode->i_ino; + uint64_t len; + uint64_t uid = ino; + + iscsi_trace(TRACE_OSDFS, "osdfs_readpage(ino %lu, Offset %llu, Length %llu)\n", ino, Offset, Length); + if (Offset+Length>inode->i_size) { + len = inode->i_size-Offset; + } else { + len = Length; + } + if (!Page_Uptodate(page)) { + memset(kmap(page), 0, PAGE_CACHE_SIZE); + if (osd_read((void *)&dev, root_gid, uid, Offset, len, page->virtual, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_read() failed\n"); + UnlockPage(page); + return -1;; + } + kunmap(page); + flush_dcache_page(page); + SetPageUptodate(page); + } else { + iscsi_trace_error("The page IS up to date???\n"); + } + UnlockPage(page); + + return 0; +} + +static int osdfs_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) { + iscsi_trace(TRACE_OSDFS, "osdfs_prepare_write(ino %lu, offset %u, to %u)\n", page->mapping->host->i_ino, offset, to); + return 0; +} + +static int osdfs_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) { + uint64_t Offset = (page->index<mapping->host; + kdev_t dev = inode->i_sb->s_dev; + ino_t ino = inode->i_ino; + uint64_t uid = ino; + + iscsi_trace(TRACE_OSDFS, "osdfs_commit_write(ino %lu, offset %u, to %u, Offset %llu, Length %llu)\n", + ino, offset, to, Offset, Length); + if (osd_write((void *)&dev, root_gid, uid, Offset, Length, page->virtual+offset, 0, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_write() failed\n"); + return -1; + } + if (Offset+Length>inode->i_size) { + inode->i_size = Offset+Length; + } + osdfs_write_inode(inode, 0); + + return 0; +} + +static struct address_space_operations osdfs_aops = { + readpage: osdfs_readpage, + writepage: NULL, + prepare_write: osdfs_prepare_write, + commit_write: osdfs_commit_write +}; + + +/* + * Superblock operations + */ + + +static struct super_block *osdfs_read_super(struct super_block *sb, void *data, int silent) { + char opt[64]; + char *ptr, *ptr2; + struct inode attr; + struct inode *inode; + + iscsi_trace(TRACE_OSDFS, "osdfs_read_super(major %i minor %i)\n", MAJOR(sb->s_dev), MINOR(sb->s_dev)); + + root_gid = root_uid = 0; + + /* Parse options */ + + ptr = (char *)data; + while (ptr&&strlen(ptr)) { + if ((ptr2=strchr(ptr, ','))) { + strncpy(opt, ptr, ptr2-ptr); + opt[ptr2-ptr] = 0x0; + ptr = ptr2+1; + } else { + strcpy(opt, ptr); + ptr = 0x0; + } + if (!strncmp(opt, "uid=", 3)) { + if (sscanf(opt, "uid=0x%Lx", &root_uid)!=1) { + iscsi_trace_error("malformed option \"%s\"\n", opt); + return NULL; + } + } else if (!strncmp(opt, "gid=", 3)) { + if (sscanf(opt, "gid=0x%x", &root_gid)!=1) { + iscsi_trace_error("malformed option \"%s\"\n", opt); + return NULL; + } + } else { + iscsi_trace_error("unknown option \"%s\"\n", opt); + return NULL; + } + } + + /* Initialize superblock */ + + sb->s_blocksize = PAGE_CACHE_SIZE; + sb->s_blocksize_bits = PAGE_CACHE_SHIFT; + sb->s_magic = OSDFS_MAGIC; + sb->s_op = &osdfs_ops; + + if ((root_uid==0)||(root_gid==0)) { + + /* Create group object for root directory */ + + if (osd_create_group((void *)&sb->s_dev, &osd_exec_via_scsi, &root_gid)!=0) { + iscsi_trace_error("osd_create_group() failed\n"); + return NULL; + } + printf("** ROOT DIRECTORY GROUP OBJECT IS 0x%x **\n", root_gid); + + /* Create user object for root directory */ + + if (osd_create((void *)&sb->s_dev, root_gid, &osd_exec_via_scsi, &root_uid)!=0) { + iscsi_trace_error("osd_create() failed\n"); + return NULL; + } + printf("** ROOT DIRECTORY USER OBJECT IS 0x%llx **\n", root_uid); + + /* Initialize Attributes */ + + memset(&attr, 0, sizeof(struct inode)); + attr.i_mode = S_IFDIR | 0755; + if (osd_set_one_attr((void *)&sb->s_dev, root_gid, root_uid, 0x30000000, 0x1, sizeof(struct inode), (void *) &attr, &osd_exec_via_scsi)!=0) { + iscsi_trace_error("osd_set_one_attr() failed\n"); + return NULL; + } + } else { + iscsi_trace(TRACE_OSDFS, "using root directory in 0x%x:0x%llx\n", root_gid, root_uid); + } + + /* Create inode for root directory */ + + if ((inode=osdfs_get_inode(sb, S_IFDIR | 0755, 0, "/", root_uid))==NULL) { + iscsi_trace_error("osdfs_get_inode() failed\n"); + return NULL; + } + if ((sb->s_root=d_alloc_root(inode))==NULL) { + iscsi_trace_error("d_alloc_root() failed\n"); + iput(inode); + return NULL; + } + + return sb; +} + +static DECLARE_FSTYPE_DEV(osdfs_fs_type, "osdfs", osdfs_read_super); + + +/* + * Module operations + */ + + +static int __init init_osdfs_fs(void) { + iscsi_trace(TRACE_OSDFS, "init_osdfs_fs()\n"); + ISCSI_MUTEX_INIT(&g_mutex, return -1); + return register_filesystem(&osdfs_fs_type); +} + +static void __exit exit_osdfs_fs(void) { + iscsi_trace(TRACE_OSDFS, "exit_osdfs_fs()\n"); + ISCSI_MUTEX_DESTROY(&g_mutex, printk("mutex_destroy() failed\n")); + unregister_filesystem(&osdfs_fs_type); +} + +module_init(init_osdfs_fs) +module_exit(exit_osdfs_fs) diff --git a/external/bsd/iscsi/dist/src/parameters.c b/external/bsd/iscsi/dist/src/parameters.c new file mode 100644 index 000000000000..7a4bfc4150ce --- /dev/null +++ b/external/bsd/iscsi/dist/src/parameters.c @@ -0,0 +1,1291 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" +#include "compat.h" + +#ifdef HAVE_CTYPE_H +#include +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#include "iscsi-md5.h" +#include "iscsiutil.h" +#include "parameters.h" +#include "conffile.h" + + +int +param_list_add(iscsi_parameter_t ** head, int type, const char *key, const char *dflt, const char *valid) +{ + iscsi_parameter_t *param; + + /* Allocated new parameter type */ + + if (*head == NULL) { + if ((*head = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + param = *head; + } else { + for (param = *head; param->next != NULL; param = param->next) { + } + if ((param->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + param = param->next; + } + + /* Initilized parameter */ + + param->type = type; /* type */ + (void) strlcpy(param->key, key, sizeof(param->key));/* key */ + (void) strlcpy(param->dflt, dflt, sizeof(param->dflt)); /* default value */ + (void) strlcpy(param->valid, valid, sizeof(param->valid)); /* list of valid values */ + param->tx_offer = 0; /* sent offer */ + param->rx_offer = 0; /* received offer */ + param->tx_answer = 0; /* sent answer */ + param->rx_answer = 0; /* received answer */ + param->reset = 0; /* used to erase value_l on next parse */ + param->next = NULL; /* terminate list */ + + /* Allocated space for value list and set first item to default; and */ + /* set offer and answer lists to NULL */ + + if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + param->value_l->next = NULL; + (void) strlcpy(param->value_l->value, dflt, sizeof(param->value_l->value)); + + /* Arg check */ + + switch (type) { + case ISCSI_PARAM_TYPE_DECLARATIVE: + break; + case ISCSI_PARAM_TYPE_DECLARE_MULTI: + break; + case ISCSI_PARAM_TYPE_BINARY_OR: + if (strcmp(valid, "Yes,No") != 0 && + strcmp(valid, "No,Yes") != 0 && + strcmp(valid, "No") != 0 && + strcmp(valid, "Yes") != 0 && + strcmp(valid, "yes,no") != 0 && + strcmp(valid, "no,yes") != 0 && + strcmp(valid, "no") != 0 && + strcmp(valid, "yes") != 0) { + iscsi_trace_error(__FILE__, __LINE__, "bad field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid); + return -1; + } + break; + case ISCSI_PARAM_TYPE_BINARY_AND: + if (strcmp(valid, "Yes,No") != 0 && + strcmp(valid, "No,Yes") != 0 && + strcmp(valid, "No") != 0 && + strcmp(valid, "Yes") != 0 && + strcmp(valid, "yes,no") != 0 && + strcmp(valid, "no,yes") != 0 && + strcmp(valid, "no") != 0 && + strcmp(valid, "yes") != 0) { + iscsi_trace_error(__FILE__, __LINE__, "bad field \"%s\" for ISCSI_PARAM_TYPE_BINARY\n", valid); + return -1; + } + break; + case ISCSI_PARAM_TYPE_NUMERICAL: + break; + case ISCSI_PARAM_TYPE_NUMERICAL_Z: + break; + case ISCSI_PARAM_TYPE_LIST: + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown parameter type %d\n", type); + return -1; + } + + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "\"%s\": valid \"%s\", default \"%s\", current \"%s\"\n", + param->key, param->valid, param->dflt, param->value_l->value); + return 0; +} + +int +param_list_destroy(iscsi_parameter_t * head) +{ + iscsi_parameter_t *ptr, *tmp; + iscsi_parameter_value_t *item_ptr, *next; + + for (ptr = head; ptr != NULL;) { + tmp = ptr; + ptr = ptr->next; + if (tmp->value_l) { + for (item_ptr = tmp->value_l; item_ptr != NULL; item_ptr = next) { + next = item_ptr->next; + /* + * iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "freeing \"%s\" + * (%p)\n", item_ptr->value, item_ptr); + */ + iscsi_free_atomic(item_ptr); + } + } + /* iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "freeing %p\n", tmp); */ + iscsi_free_atomic(tmp); + } + return 0; +} + + +iscsi_parameter_t * +param_get(iscsi_parameter_t * head, const char *key) +{ + iscsi_parameter_t *ptr; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + return ptr; + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return NULL; +} + +char * +param_val(iscsi_parameter_t * head, const char *key) +{ + return param_val_which(head, key, 0); +} + +char * +param_val_which(iscsi_parameter_t * head, const char *key, int which) +{ + iscsi_parameter_t *ptr; + iscsi_parameter_value_t *item_ptr; + int i = 0; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + item_ptr = ptr->value_l; + for (i = 0; i != which; i++) { + if (item_ptr == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "item %d in value list is NULL\n", i); + return NULL; + } + item_ptr = item_ptr->next; + } + if (item_ptr == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "item %d in value list is NULL\n", which); + return NULL; + } + return item_ptr->value; + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return NULL; +} + +static int +param_val_delete_all(iscsi_parameter_t * head, char *key) +{ + iscsi_parameter_t *ptr; + iscsi_parameter_value_t *item_ptr, *next; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = next) { + next = item_ptr->next; + iscsi_free_atomic(item_ptr); + } + ptr->value_l = NULL; + return 0; + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return -1; +} + +int +param_val_reset(iscsi_parameter_t * head, const char *key) +{ + iscsi_parameter_t *ptr; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + ptr->reset = 1; + return 0; + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return -1; +} + +int +param_atoi(iscsi_parameter_t * head, const char *key) +{ + iscsi_parameter_t *ptr; + char *value; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + if (ptr->value_l) { + if ((value = param_val(head, key)) != NULL) { + return iscsi_atoi(value); + } else { + iscsi_trace_error(__FILE__, __LINE__, "value is NULL\n"); + return 0; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key); + return 0; + } + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return 0; +} + +int +param_equiv(iscsi_parameter_t * head, const char *key, const char *val) +{ + iscsi_parameter_t *ptr; + char *value; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + if (ptr->value_l == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "param \"%s\" has NULL value list\n", key); + return 0; + } + if ((value = param_val(head, key)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" value is NULL\n", key); + return 0; + } + return (strcmp(value, val) == 0); + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return -1; +} + +int +param_num_vals(iscsi_parameter_t * head, char *key) +{ + iscsi_parameter_t *ptr; + iscsi_parameter_value_t *item_ptr; + int num = 0; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + if (strcmp(ptr->key, key) == 0) { + for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = item_ptr->next) { + num++; + } + return num; + } + } + iscsi_trace_error(__FILE__, __LINE__, "key \"%s\" not found in param list\n", key); + return -1; +} + +int +param_list_print(iscsi_parameter_t * head) +{ + iscsi_parameter_t *ptr; + iscsi_parameter_value_t *item_ptr; + + for (ptr = head; ptr != NULL; ptr = ptr->next) { + for (item_ptr = ptr->value_l; item_ptr != NULL; item_ptr = item_ptr->next) { + printf("\"%s\"=\"%s\"\n", ptr->key, item_ptr->value); + } + } + return 0; +} + +int +param_text_print(char *text, uint32_t text_len) +{ + char key[256]; + char *ptr, *eq, *value; + + for (ptr = text; (uint32_t)(ptr - text) < text_len; ptr += (strlen(ptr) + 1)) { + + /* Skip over any NULLs */ + + while (!(*ptr) && ((uint32_t)(ptr - text) < text_len)) + ptr++; + if ((uint32_t)(ptr - text) >= text_len) + break; + + if ((eq = strchr(ptr, '=')) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr); + return -1; + } + strncpy(key, ptr, (unsigned)(eq - ptr)); + key[(int)(eq - ptr)] = 0x0; + value = eq + 1; + printf("\"%s\"=\"%s\"\n", key, value); + } + return 0; +} + +/* ARGSUSED */ +int +param_text_add(iscsi_parameter_t * head, const char *key, const char *value, char *text, int *len, int size, int offer) +{ + int cc; + + cc = snprintf(text + *len, (unsigned)(size - *len), "%s=%s", key, value); + *len += cc + 1; + return 0; +} + +int +driver_atoi(const char *s) +{ + int k = 0; + + while (*s != 0x0 && *s >= '0' && *s <= '9') { + k = 10 * k + (*s - '0'); + s++; + } + return k; +} + +/* find the credentials for `user' and put them in `cred' */ +static int +find_credentials(iscsi_cred_t *cred, char *user, const char *auth) +{ + conffile_t conf; + const char *authtype; + unsigned cc; + ent_t e; + + (void) memset(&conf, 0x0, sizeof(conf)); + (void) memset(&e, 0x0, sizeof(e)); + + if (!conffile_open(&conf, _PATH_ISCSI_PASSWD, "r", ":", "#")) { + iscsi_trace_error(__FILE__, __LINE__, "can't open `%s'\n", _PATH_ISCSI_PASSWD); + exit(EXIT_FAILURE); + } + while (conffile_getent(&conf, &e)) { + if (strcasecmp(e.sv.v[0], user) == 0) { + authtype = (e.sv.c == 1) ? "none" : e.sv.v[1]; + cc = strlen(authtype); + if (auth == NULL || (strncasecmp(authtype, auth, cc) == 0 && cc == strlen(auth))) { + cred->user = strdup(e.sv.v[0]); + cred->auth_type = strdup(authtype); + cred->shared_secret = (e.sv.c == 3) ? strdup(e.sv.v[2]) : NULL; + conffile_close(&conf); + return 1; + } + } + } + conffile_close(&conf); + (void) fprintf(stderr, "No matching user configuration entry for `%s' was found\n", user); + (void) fprintf(stderr, "Please add an entry for `%s' to `%s'\n", user, _PATH_ISCSI_PASSWD); + return 0; +} + +#if 0 +/* free any storage allocated in `cred' */ +static void +free_cred(iscsi_cred_t *cred) +{ + if (cred) { + if (cred->user) { + iscsi_free_atomic(cred->user); + } + if (cred->auth_type) { + iscsi_free_atomic(cred->auth_type); + } + if (cred->shared_secret) { + iscsi_free_atomic(cred->shared_secret); + } + } +} +#endif + +/* Security offering and check */ +/* + * ret values: =0: succeed or no security >0: security negotiation in process + * <0: failed + */ +static int +param_parse_security(iscsi_parameter_t * head, + iscsi_parameter_t * param_in, + iscsi_cred_t *cred, + char *text_out, int *text_len_out, int textsize) +{ + + static uint8_t idData; + static uint8_t chapdata[ISCSI_CHAP_DATA_LENGTH]; + static uint8_t respdata[ISCSI_CHAP_DATA_LENGTH]; + char *chapstring = NULL; + iSCSI_MD5_CTX *context = NULL; + iscsi_parameter_t *param = NULL; + int ret = 1; + + if ((chapstring = iscsi_malloc(ISCSI_CHAP_STRING_LENGTH)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + if ((context = iscsi_malloc(sizeof(*context))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (chapstring != NULL) + iscsi_free(chapstring); + return -1; + } +#define PPS_CLEANUP { if (chapstring != NULL) iscsi_free(chapstring);if (context != NULL) iscsi_free(context); } +#define PPS_ERROR { PPS_CLEANUP; return (-1); }; + + if (strcmp(param_in->key, "AuthMethod") == 0) { + if (param_in->rx_answer && strcmp(param_in->answer_rx, "None") == 0) { + PPS_CLEANUP; + return 0; /* Proposed None for + * Authentication */ + } + if (param_in->rx_offer && strcmp(param_in->offer_rx, "None") == 0) { + PPS_CLEANUP; + return 0; + } + if (!param_in->rx_offer) { + param = param_get(head, "CHAP_A"); + if (param == NULL) + PPS_ERROR; + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + (void) strlcpy(param->offer_tx, param->valid, sizeof(param->offer_tx)); + PARAM_TEXT_ADD(head, param->key, param->valid, + text_out, text_len_out, textsize, 0, PPS_ERROR); + ret++; + } + } else if (strcmp(param_in->key, "CHAP_A") == 0) { + if (param_in->rx_offer) { + PARAM_TEXT_ADD(head, param_in->key, param_in->offer_rx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + + if ((param = param_get(head, "CHAP_I")) == NULL) { + PPS_ERROR; + } + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + GenRandomData(&idData, 1); + (void) snprintf(chapstring, ISCSI_CHAP_STRING_LENGTH, "%d", idData); + (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx)); + PARAM_TEXT_ADD(head, param->key, param->offer_tx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + + if ((param = param_get(head, "CHAP_C")) == NULL) { + PPS_ERROR; + } + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + GenRandomData(chapdata, ISCSI_CHAP_DATA_LENGTH); + HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH, + chapstring, ISCSI_CHAP_STRING_LENGTH); + (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx)); + PARAM_TEXT_ADD(head, param->key, param->offer_tx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + ret++; + } + } else if (strcmp(param_in->key, "CHAP_I") == 0) { + + idData = driver_atoi((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx); + ret++; + + } else if (strcmp(param_in->key, "CHAP_C") == 0) { + + HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH, + chapdata, ISCSI_CHAP_DATA_LENGTH); + + if ((param = param_get(head, "CHAP_N")) == NULL) { + PPS_ERROR; + } + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + + if (cred->shared_secret == NULL && !find_credentials(cred, cred->user, "chap")) { + iscsi_trace_error(__FILE__, __LINE__, "Unknown user `%s'\n", param_in->offer_rx); + PPS_ERROR; + } + + if (cred->user) { + (void) strlcpy(param->offer_tx, cred->user, sizeof(param->offer_tx)); + } else { + iscsi_trace_error(__FILE__, __LINE__, "no valid user credentials\n"); + PPS_ERROR; + } + + PARAM_TEXT_ADD(head, param->key, param->offer_tx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + + if ((param = param_get(head, "CHAP_R")) == NULL) { + PPS_ERROR; + } + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + iSCSI_MD5Init(context); + iSCSI_MD5Update(context, &idData, 1); + + if (cred->shared_secret == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "null shared secret\n"); + PPS_ERROR; + } else { + iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret)); + } + + HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH, + param->offer_tx, ISCSI_CHAP_STRING_LENGTH); + iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH); + iSCSI_MD5Final(chapdata, context); + HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH, + param->offer_tx, ISCSI_CHAP_STRING_LENGTH); + + PARAM_TEXT_ADD(head, param->key, param->offer_tx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + + if (param_in->rx_offer) { + + if ((param = param_get(head, "CHAP_I")) == NULL) { + PPS_ERROR; + } + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + GenRandomData(&idData, 1); + (void) snprintf(chapstring, ISCSI_CHAP_STRING_LENGTH, "%d", idData); + (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx)); + PARAM_TEXT_ADD(head, param->key, param->offer_tx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + + if ((param = param_get(head, "CHAP_C")) == NULL) { + PPS_ERROR; + } + param->tx_offer = 1; /* sending an offer */ + param->rx_offer = 0; /* reset */ + GenRandomData(chapdata, ISCSI_CHAP_DATA_LENGTH); + HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH, + chapstring, ISCSI_CHAP_STRING_LENGTH); + (void) strlcpy(param->offer_tx, chapstring, sizeof(param->offer_tx)); + PARAM_TEXT_ADD(head, param->key, param->offer_tx, + text_out, text_len_out, textsize, 0, PPS_ERROR); + } + ret++; + + } else if (strcmp(param_in->key, "CHAP_N") == 0) { + char *user; + + user = (param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx; + if (!find_credentials(cred, user, "chap")) { + iscsi_trace_error(__FILE__, __LINE__, "Unknown user `%s'\n", user); + PPS_ERROR; + } + ret++; + + } else if (strcmp(param_in->key, "CHAP_R") == 0) { + + iSCSI_MD5Init(context); + + iSCSI_MD5Update(context, &idData, 1); + + HexDataToText(&idData, 1, param_in->offer_tx, ISCSI_CHAP_STRING_LENGTH); + HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH, + chapstring, ISCSI_CHAP_STRING_LENGTH); + + if (cred->shared_secret == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "Null shared secret in initiator\n"); + PPS_ERROR; + } else { + iSCSI_MD5Update(context, (const uint8_t *)cred->shared_secret, strlen(cred->shared_secret)); + } + + iSCSI_MD5Update(context, chapdata, ISCSI_CHAP_DATA_LENGTH); + iSCSI_MD5Final(chapdata, context); + + HexTextToData((param_in->rx_offer) ? param_in->offer_rx : param_in->answer_rx, ISCSI_CHAP_STRING_LENGTH, + respdata, ISCSI_CHAP_DATA_LENGTH); + + HexDataToText(chapdata, ISCSI_CHAP_DATA_LENGTH, + param_in->offer_rx, ISCSI_CHAP_STRING_LENGTH); + + if (memcmp(respdata, chapdata, ISCSI_CHAP_DATA_LENGTH) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "Initiator authentication failed %x %x\n", *chapdata, *respdata); + PPS_ERROR; + } else { + PPS_CLEANUP; + } + return 0; + } + PPS_CLEANUP; + return (ret); +} + +int +param_text_parse(iscsi_parameter_t * head, + iscsi_cred_t *cred, + char *text_in, int text_len_in, + char *text_out, int *text_len_out, + int textsize, + int outgoing) +{ + static char *key = NULL; + char *value = NULL; + char *ptr, *eq; + iscsi_parameter_t *param; + iscsi_parameter_value_t *item_ptr; + int offer_i, answer_i, max_i, val1_i, val2_i, negotiated_i; + char *p1, *p2, *p3, *p4; + char *offer = NULL; + char *valid = NULL; + char *val1 = NULL; + char *val2 = NULL; + char *tmp_key = NULL; + char c; + int ret; + + /* + * Whether incoming or outgoing, some of the params might be offers + * and some answers. Incoming + */ + /* + * text has the potential for creating outgoing text - and this will + * happen when the incoming + */ + /* text has offers that need an answer. */ + + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "parsing %d %s bytes of text parameters\n", text_len_in, outgoing ? "outgoing" : "incoming"); + + if ((key = iscsi_malloc(ISCSI_PARAM_KEY_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + if ((offer = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (key != NULL) { + iscsi_free(key); + } + return -1; + } + if ((valid = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (key != NULL) { + iscsi_free(key); + } + if (offer != NULL) { + iscsi_free(offer); + } + return -1; + } + if ((val1 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (key != NULL) { + iscsi_free(key); + } + if (offer != NULL) { + iscsi_free(offer); + } + if (valid != NULL) { + iscsi_free(valid); + } + return -1; + } + if ((val2 = iscsi_malloc(ISCSI_PARAM_MAX_LEN)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + if (key != NULL) { + iscsi_free(key); + } + if (offer != NULL) { + iscsi_free(offer); + } + if (valid != NULL) { + iscsi_free(valid); + } + if (val1 != NULL) { + iscsi_free(val1); + } + return -1; + } +#define PTP_CLEANUP { if (key != NULL) iscsi_free(key); \ + if (offer != NULL) iscsi_free(offer); \ + if (valid != NULL) iscsi_free(valid); \ + if (val1 != NULL) iscsi_free(val1); \ + if (val2 != NULL) iscsi_free(val2); \ + if (tmp_key != NULL) iscsi_free(tmp_key); } +#define PTP_ERROR {PTP_CLEANUP; return -1;} + + if (!outgoing) { + *text_len_out = 0; + } + +#if ISCSI_DEBUG + printf("**************************************************\n"); + printf("* PARAMETERS NEGOTIATED *\n"); + printf("* *\n"); +#endif + + for (ptr = text_in; ptr - text_in < text_len_in; ptr += (strlen(ptr) + 1)) { + + /* Skip over any NULLs */ + + while (!(*ptr) && ((ptr - text_in) < text_len_in)) { + ptr++; + } + if ((ptr - text_in) >= text_len_in) { + break; + } + + /* Extract = token from text_in */ + + if ((eq = strchr(ptr, '=')) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "delimiter \'=\' not found in token \"%s\"\n", ptr); + } else { + if ((int)(eq - ptr) >= (ISCSI_PARAM_KEY_LEN - 1)) { + if (!outgoing) { + tmp_key = iscsi_malloc((unsigned)(eq - ptr)); + if (tmp_key) { + strncpy(tmp_key, ptr, (unsigned)(eq - ptr)); + tmp_key[(int)(eq - ptr)] = 0x0; + /* Key not understood. */ + PARAM_TEXT_ADD(head, tmp_key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR); + } + } else { + printf("ignoring \"%s\"\n", key); + } + goto next; + } + strncpy(key, ptr, (unsigned)(eq - ptr)); + key[(int)(eq - ptr)] = 0x0; + value = eq + 1; + } + + /* Find key in param list */ + + for (param = head; param != NULL; param = param->next) { + if (strcmp(param->key, key) == 0) { + break; + } + } + if (param == NULL) { + if (!outgoing) { + /* Key not understood. */ + PARAM_TEXT_ADD(head, key, "NotUnderstood", text_out, text_len_out, textsize, 0, PTP_ERROR); + } else { + printf("ignoring \"%s\"\n", key); + } + goto next; + } + RETURN_GREATER("strlen(value)", strlen(value), ISCSI_PARAM_MAX_LEN, PTP_CLEANUP, -1); + + /* We're sending|receiving an offer|answer */ + + if (outgoing) { + if (param->rx_offer) { + param->tx_answer = 1; /* sending an answer */ + param->rx_answer = 0; /* reset */ + param->tx_offer = 0; /* reset */ + param->rx_offer = 0; /* reset */ + (void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx)); + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "sending answer \"%s\"=\"%s\" for offer \"%s\"\n", + param->key, param->answer_tx, param->offer_rx); + goto negotiate; + } else { + param->tx_offer = 1; /* sending an offer */ + param->tx_answer = 0; + param->rx_answer = 0; + (void) strlcpy(param->offer_tx, value, sizeof(param->offer_tx)); + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "sending offer \"%s\"=\"%s\"\n", param->key, param->offer_tx); + if ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) || + (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI)) { + goto negotiate; + } + goto next; + } + } else { + if (param->tx_offer) { + param->rx_answer = 1; /* received an answer */ + param->tx_answer = 0; + param->rx_offer = 0; + param->tx_offer = 0; /* reset */ + (void) strlcpy(param->answer_rx, value, sizeof(param->answer_rx)); + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "received answer \"%s\"=\"%s\" for offer \"%s\"\n", + param->key, param->answer_rx, param->offer_tx); + + if ((ret = param_parse_security(head, param, cred, + text_out, text_len_out, textsize)) > 1) { + goto next; + } else if (ret == 0) { + /* + * FIX ME Happens in initiator code + * currently we ignore initiator + * authentication status See comments + * at the beginning of parse_security + */ + goto negotiate; + } else if (ret == 1) { + goto negotiate; + } else { + PTP_CLEANUP; + } + return ISCSI_PARAM_STATUS_AUTH_FAILED; + } else { + param->rx_offer = 1; /* received an offer */ + param->rx_answer = 0; + param->tx_answer = 0; + (void) strlcpy(param->offer_rx, value, sizeof(param->offer_rx)); + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "received offer \"%s\"=\"%s\"\n", param->key, param->offer_rx); + + if ((ret = param_parse_security(head, param, cred, + text_out, text_len_out, textsize)) > 1) { + goto next; + } else if (ret < 0) { + iscsi_parameter_t *auth_result; + if ((auth_result = param_get(head, "AuthResult")) != 0) { + (void) strlcpy(auth_result->value_l->value, "Fail", sizeof(auth_result->value_l->value)); + } + PTP_CLEANUP; + return (ISCSI_PARAM_STATUS_AUTH_FAILED); + } else if (ret == 0) { + iscsi_parameter_t *auth_result; + if ((auth_result = param_get(head, "AuthResult")) != 0) { + (void) strlcpy(auth_result->value_l->value, "Yes", sizeof(auth_result->value_l->value)); + } + } + /* + * Answer the offer if it is an inquiry or + * the type is not DECLARATIVE + */ + + if ((strcmp(param->offer_rx, "?") != 0) && ((param->type == ISCSI_PARAM_TYPE_DECLARATIVE) || (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI))) { + goto negotiate; + } else { + goto answer; + } + } + } + +answer: + + /* Answer with current value if this is an inquiry (=?) */ + + if (strcmp(value, "?") == 0) { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "got inquiry for param \"%s\"\n", param->key); + if (param->value_l) { + if (param->value_l->value) { + (void) strlcpy(param->answer_tx, param->value_l->value, sizeof(param->answer_tx)); + } else { + iscsi_trace_error(__FILE__, __LINE__, "param \"%s\" has NULL value_l->value\n", param->key); + param->answer_tx[0] = 0x0; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "param \"%s\" has NULL value_l\n", param->key); + param->answer_tx[0] = 0x0; + } + goto add_answer; + } + /* Generate answer according to the parameter type */ + + switch (param->type) { + + case ISCSI_PARAM_TYPE_BINARY_AND: + goto binary_or; + + case ISCSI_PARAM_TYPE_BINARY_OR: +binary_or: + if (strcmp(value, "yes") != 0 && + strcmp(value, "no") != 0 && + strcmp(value, "Yes") != 0 && + strcmp(value, "No") != 0) { + iscsi_trace_error(__FILE__, __LINE__, "\"%s\" is not a valid binary value\n", value); + (void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx)); + goto add_answer; + } + if (strchr(param->valid, ',') != NULL) { + (void) strlcpy(param->answer_tx, value, sizeof(param->answer_tx)); /* we accept both yes + * and no, so answer w/ + * their offer */ + } else { + (void) strlcpy(param->answer_tx, param->valid, sizeof(param->answer_tx)); /* answer with the only + * value we support */ + } + break; + + case ISCSI_PARAM_TYPE_LIST: + + /* + * Use our default value if it's offered as one of the option + * in the parameter list. + * + * We need to do this at least for CHAP because cisco's initiator + * could be sending us a parameter value list with "CHAP,None", + * even when it doesn't set username/password in its configration + * file, in which case we should pick "None" as for no security instead + * of pick the first one on the value list. "None" is the default value + * for AuthMethod + * + * This fix is working well now, though is arguable. We should keep + * this just to make us work with Cisco for now. + */ + if (strlen(param->dflt)) { + for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) { + + if ((p2 = strchr(p1, ',')) != NULL) { + strncpy(offer, p1, (unsigned)(p2 - p1)); + offer[(int)(p2 - p1)] = 0x0; + } else { + (void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN); + } + + if (strcmp(param->dflt, offer) == 0) { + (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx)); + goto add_answer; + } + } + } + /* Find the first valid offer that we support */ + + for (p1 = p2 = param->offer_rx; p2; p1 = p2 + 1) { + if ((p2 = strchr(p1, ',')) != NULL) { + strncpy(offer, p1, (unsigned)(p2 - p1)); + offer[p2 - p1] = 0x0; + } else { + (void) strlcpy(offer, p1, ISCSI_PARAM_MAX_LEN); + } + if (strlen(param->valid)) { + for (p3 = p4 = param->valid; p4; p3 = p4 + 1) { + if ((p4 = strchr(p3, ',')) != NULL) { + strncpy(valid, p3, (unsigned)(p4 - p3)); + valid[(int)(p4 - p3)] = 0x0; + } else { + (void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN); + } + if (strcmp(valid, offer) == 0) { + (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx)); + goto add_answer; + } + } + } else { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "Valid list empty. Answering with first in offer list\n"); + (void) strlcpy(param->answer_tx, offer, sizeof(param->answer_tx)); + goto add_answer; + } + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "\"%s\" is not a valid offer for key \"%s\" (must choose from \"%s\")\n", offer, param->key, param->valid); + } + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "No Valid offers: \"%s\" is added as value for key \"%s\")\n", "Reject", param->key); + (void) strlcpy(param->answer_tx, "Reject", sizeof(param->answer_tx)); + break; + + case ISCSI_PARAM_TYPE_NUMERICAL_Z: + goto numerical; + + case ISCSI_PARAM_TYPE_NUMERICAL: +numerical: + offer_i = iscsi_atoi(param->offer_rx); + max_i = iscsi_atoi(param->valid); + if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) { + if (max_i == 0) { + answer_i = offer_i; /* we support anything, + * so return whatever + * they offered */ + } else if (offer_i == 0) { + answer_i = max_i; /* return only what we + * can support */ + } else if (offer_i > max_i) { + answer_i = max_i; /* we are the lower of + * the two */ + } else { + answer_i = offer_i; /* they are the lower of + * the two */ + } + } else { + if (offer_i > max_i) { + answer_i = max_i; /* we are the lower of + * the two */ + } else { + answer_i = offer_i; /* they are the lower of + * the two */ + } + } + (void) snprintf(param->answer_tx, sizeof(param->answer_tx), "%d", answer_i); + goto add_answer; + + default: + goto next; + } +add_answer: PARAM_TEXT_ADD(head, key, param->answer_tx, text_out, text_len_out, textsize, 0, PTP_ERROR); + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "answering \"%s\"=\"%s\"\n", param->key, param->answer_tx); + goto next; + + + /* Negotiate after receiving|sending an answer */ + +negotiate: + switch (param->type) { + case ISCSI_PARAM_TYPE_DECLARE_MULTI: + goto declarative_negotiate; + case ISCSI_PARAM_TYPE_DECLARATIVE: +declarative_negotiate: + if (param->tx_answer) { + (void) strlcpy(param->negotiated, param->answer_tx, sizeof(param->negotiated)); + } else if (param->tx_offer) { + (void) strlcpy(param->negotiated, param->offer_tx, sizeof(param->negotiated)); + } else if (param->rx_answer) { + (void) strlcpy(param->negotiated, param->answer_rx, sizeof(param->negotiated)); + } else if (param->rx_offer) { + (void) strlcpy(param->negotiated, param->offer_rx, sizeof(param->negotiated)); + } else { + iscsi_trace_error(__FILE__, __LINE__, "Invalid negotiation!?!?\n"); + } + break; + case ISCSI_PARAM_TYPE_BINARY_AND: + goto binary_or_negotiate; + case ISCSI_PARAM_TYPE_BINARY_OR: +binary_or_negotiate: + if (outgoing) { + (void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN); + (void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN); + } else { + (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN); + (void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN); + /* Make sure the answer is valid */ + if (strcmp(val1, "Yes") != 0 && + strcmp(val1, "No") != 0 && + strcmp(val1, "yes") != 0 && + strcmp(val1, "no") != 0 && + strcmp(val1, "Irrelevant") != 0) { + /* Invalid value returned as answer. */ + iscsi_trace_error(__FILE__, __LINE__, "Invalid answer (%s) for key (%s)\n", + val1, key); + PTP_ERROR; + } + } + if (param->type == ISCSI_PARAM_TYPE_BINARY_OR) { + if (strcmp(val1, "yes") == 0 || strcmp(val2, "yes") == 0 || strcmp(val1, "Yes") == 0 || strcmp(val2, "Yes") == 0) { + (void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated)); + } else { + (void) strlcpy(param->negotiated, "No", sizeof(param->negotiated)); + } + } else { + if ((strcmp(val1, "yes") == 0 && strcmp(val2, "yes") == 0) || (strcmp(val1, "Yes") == 0 && strcmp(val2, "Yes") == 0)) { + (void) strlcpy(param->negotiated, "Yes", sizeof(param->negotiated)); + } else { + (void) strlcpy(param->negotiated, "No", sizeof(param->negotiated)); + } + } + break; + case ISCSI_PARAM_TYPE_NUMERICAL_Z: + goto numerical_negotiate; + case ISCSI_PARAM_TYPE_NUMERICAL: +numerical_negotiate: + if (outgoing) { + (void) strlcpy(val1, param->offer_rx, ISCSI_PARAM_MAX_LEN); + (void) strlcpy(val2, param->answer_tx, ISCSI_PARAM_MAX_LEN); + } else { + (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN); + (void) strlcpy(val2, param->offer_tx, ISCSI_PARAM_MAX_LEN); + } + val1_i = iscsi_atoi(val1); + val2_i = iscsi_atoi(val2); + if (param->type == ISCSI_PARAM_TYPE_NUMERICAL_Z) { + if (val1_i == 0) { + negotiated_i = val2_i; + } else if (val2_i == 0) { + negotiated_i = val1_i; + } else if (val1_i > val2_i) { + negotiated_i = val2_i; + } else { + negotiated_i = val1_i; + } + } else { + if (val1_i > val2_i) { + negotiated_i = val2_i; + } else { + negotiated_i = val1_i; + } + } + (void) snprintf(param->negotiated, sizeof(param->negotiated), "%d", negotiated_i); + break; + case ISCSI_PARAM_TYPE_LIST: + if (outgoing) { + if (param->tx_offer) { + iscsi_trace_error(__FILE__, __LINE__, "we should not be here\n"); /* error - we're sending + * an offer */ + PTP_ERROR; + } else if (param->tx_answer) { + (void) strlcpy(val1, param->answer_tx, ISCSI_PARAM_MAX_LEN); /* we're sending an + * answer */ + } else { + iscsi_trace_error(__FILE__, __LINE__, "unexpected error\n"); + PTP_ERROR; + } + } else { + if (param->rx_offer) { + iscsi_trace_error(__FILE__, __LINE__, "we should not be here\n"); /* error - we received + * an offer */ + PTP_ERROR; + } else if (param->rx_answer) { + (void) strlcpy(val1, param->answer_rx, ISCSI_PARAM_MAX_LEN); /* we received an answer */ + } else { + iscsi_trace_error(__FILE__, __LINE__, "unexpected error\n"); + PTP_ERROR; + } + } + + /* Make sure incoming or outgoing answer is valid */ + /* + * None, Reject, Irrelevant and NotUnderstood are + * valid + */ + if ((strcmp(val1, "None") == 0) || (strcmp(val1, "Reject") == 0) || + (strcmp(val1, "Irrelevant") == 0) || (strcmp(val1, "NotUnderstood") == 0)) { + goto value_ok; + } + if (strlen(param->valid) > 0) { + for (p3 = p4 = param->valid; p4; p3 = p4 + 1) { + if ((p4 = strchr(p3, ',')) != NULL) { + strncpy(valid, p3, (unsigned)(p4 - p3)); + valid[(int)(p4 - p3)] = 0x0; + } else { + (void) strlcpy(valid, p3, ISCSI_PARAM_MAX_LEN); + } + if (strcmp(valid, val1) == 0) { + goto value_ok; + } + } + } else { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "Valid list empty??\n"); + PTP_ERROR; + } + iscsi_trace_error(__FILE__, __LINE__, "\"%s\" is not a valid value (must choose from \"%s\")\n", val1, param->valid); + PTP_ERROR; +value_ok: + (void) strlcpy(param->negotiated, val1, sizeof(param->negotiated)); + break; + } + + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "negotiated \"%s\"=\"%s\"\n", param->key, param->negotiated); + + /* For inquiries, we don't commit the value. */ + + if (param->tx_offer && strcmp(param->offer_tx, "?") == 0) { + /* we're offering an inquiry */ + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "sending an inquiry for \"%s\"\n", param->key); + goto next; + } else if (param->rx_offer && strcmp(param->offer_rx, "?") == 0) { + /* we're receiving an inquiry */ + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "received an inquiry for \"%s\"\n", param->key); + goto next; + } else if (param->tx_answer && strcmp(param->offer_rx, "?") == 0) { + /* we're answering an inquiry */ + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "answering an inquiry for \"%s\"\n", param->key); + goto next; + } else if (param->rx_answer && strcmp(param->offer_tx, "?") == 0) { + /* we're receiving an answer for our inquiry */ + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "received an answer for inquiry on \"%s\"\n", param->key); + goto next; + } + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "automatically committing \"%s\"=\"%s\"\n", param->key, param->negotiated); + + c = param->negotiated[19]; + param->negotiated[19] = 0x0; +#if ISCSI_DEBUG + printf("* %25s:%20s *\n", param->key, param->negotiated); +#endif + param->negotiated[19] = c; + + if (param->reset) { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "deleting value list for \"%s\"\n", param->key); + if (param_val_delete_all(head, param->key) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "param_val_delete_all() failed\n"); + PTP_ERROR; + } + param->reset = 0; + } + if (param->value_l) { + if (param->type == ISCSI_PARAM_TYPE_DECLARE_MULTI) { + for (item_ptr = param->value_l; item_ptr->next != NULL; item_ptr = item_ptr->next) { + } + if ((item_ptr->next = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + PTP_ERROR; + } + item_ptr = item_ptr->next; + item_ptr->next = NULL; + } else { + item_ptr = param->value_l; + } + } else { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "allocating value ptr\n"); + if ((param->value_l = iscsi_malloc_atomic(sizeof(iscsi_parameter_value_t))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + PTP_ERROR; + } + item_ptr = param->value_l; + item_ptr->next = NULL; + } + (void) strlcpy(item_ptr->value, param->negotiated, sizeof(item_ptr->value)); +next: + continue; + } + if (!outgoing) { + iscsi_trace(TRACE_ISCSI_PARAM, __FILE__, __LINE__, "generated %d bytes response\n", *text_len_out); + } +#if ISCSI_DEBUG + printf("**************************************************\n"); +#endif + + PTP_CLEANUP; + return 0; +} + +void +set_session_parameters(iscsi_parameter_t * head, + iscsi_sess_param_t * sess_params) +{ + /* These parameters are standard and assuming that they are always */ + /* present in the list (head). */ + memset(sess_params, 0, sizeof(iscsi_sess_param_t)); + sess_params->max_burst_length = param_atoi(head, "MaxBurstLength"); + sess_params->first_burst_length = param_atoi(head, "FirstBurstLength"); + sess_params->max_data_seg_length = + param_atoi(head, "MaxRecvDataSegmentLength"); + sess_params->header_digest = (param_equiv(head, "HeaderDigest", "Yes")) ? 1 : 0; + sess_params->data_digest = (param_equiv(head, "DataDigest", "Yes")) ? 1 : 0; + sess_params->initial_r2t = (param_equiv(head, "InitialR2T", "Yes")); + sess_params->immediate_data = (param_equiv(head, "ImmediateData", "Yes")); +} diff --git a/external/bsd/iscsi/dist/src/snprintf.c b/external/bsd/iscsi/dist/src/snprintf.c new file mode 100644 index 000000000000..e4ebdc483343 --- /dev/null +++ b/external/bsd/iscsi/dist/src/snprintf.c @@ -0,0 +1,665 @@ +/* + * Copyright (c) 1995-2001 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +/* From heimdal lib/roken/snprintf.c. */ + +#include "config.h" + +#if HAVE_NBTOOL_CONFIG_H +#include "nbtool_config.h" +#endif + +#if 0 +RCSID("$Id: snprintf.c,v 1.1 2009/06/21 21:20:31 agc Exp $"); +#endif +#include +#include +#include +#include +#include +#if 0 +#include +#endif + +#undef min +#define min(a,b) ((a) < (b) ? (a) : (b)) +#undef max +#define max(a,b) ((a) > (b) ? (a) : (b)) + +enum format_flags { + minus_flag = 1, + plus_flag = 2, + space_flag = 4, + alternate_flag = 8, + zero_flag = 16 +}; + +/* + * Common state + */ + +struct state { + unsigned char *str; + unsigned char *s; + unsigned char *theend; + size_t sz; + size_t max_sz; + void (*append_char)(struct state *, unsigned char); + /* XXX - methods */ +}; + +#if TEST_SNPRINTF +#include "snprintf-test.h" +#endif /* TEST_SNPRINTF */ + +#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) +static int +sn_reserve (struct state *state, size_t n) +{ + return state->s + n > state->theend; +} + +static void +sn_append_char (struct state *state, unsigned char c) +{ + if (!sn_reserve (state, 1)) + *state->s++ = c; +} +#endif + +static int +as_reserve (struct state *state, size_t n) +{ + if (state->s + n > state->theend) { + int off = state->s - state->str; + unsigned char *tmp; + + if (state->max_sz && state->sz >= state->max_sz) + return 1; + + state->sz = max(state->sz * 2, state->sz + n); + if (state->max_sz) + state->sz = min(state->sz, state->max_sz); + tmp = realloc (state->str, state->sz); + if (tmp == NULL) + return 1; + state->str = tmp; + state->s = state->str + off; + state->theend = state->str + state->sz - 1; + } + return 0; +} + +static void +as_append_char (struct state *state, unsigned char c) +{ + if(!as_reserve (state, 1)) + *state->s++ = c; +} + +/* longest integer types */ + +#ifdef HAVE_LONG_LONG +typedef unsigned long long u_longest; +typedef long long longest; +#else +typedef unsigned long u_longest; +typedef long longest; +#endif + +/* + * is # supposed to do anything? + */ + +static int +use_alternative (int flags, u_longest num, unsigned base) +{ + return flags & alternate_flag && (base == 16 || base == 8) && num != 0; +} + +static int +append_number(struct state *state, + u_longest num, unsigned base, char *rep, + int width, int prec, int flags, int minusp) +{ + int len = 0; + int i; + u_longest n = num; + + /* given precision, ignore zero flag */ + if(prec != -1) + flags &= ~zero_flag; + else + prec = 1; + /* zero value with zero precision -> "" */ + if(prec == 0 && n == 0) + return 0; + do{ + (*state->append_char)(state, rep[n % base]); + ++len; + n /= base; + } while(n); + prec -= len; + /* pad with prec zeros */ + while(prec-- > 0){ + (*state->append_char)(state, '0'); + ++len; + } + /* add length of alternate prefix (added later) to len */ + if(use_alternative(flags, num, base)) + len += base / 8; + /* pad with zeros */ + if(flags & zero_flag){ + width -= len; + if(minusp || (flags & space_flag) || (flags & plus_flag)) + width--; + while(width-- > 0){ + (*state->append_char)(state, '0'); + len++; + } + } + /* add alternate prefix */ + if(use_alternative(flags, num, base)){ + if(base == 16) + (*state->append_char)(state, rep[10] + 23); /* XXX */ + (*state->append_char)(state, '0'); + } + /* add sign */ + if(minusp){ + (*state->append_char)(state, '-'); + ++len; + } else if(flags & plus_flag) { + (*state->append_char)(state, '+'); + ++len; + } else if(flags & space_flag) { + (*state->append_char)(state, ' '); + ++len; + } + if(flags & minus_flag) + /* swap before padding with spaces */ + for(i = 0; i < len / 2; i++){ + char c = state->s[-i-1]; + state->s[-i-1] = state->s[-len+i]; + state->s[-len+i] = c; + } + width -= len; + while(width-- > 0){ + (*state->append_char)(state, ' '); + ++len; + } + if(!(flags & minus_flag)) + /* swap after padding with spaces */ + for(i = 0; i < len / 2; i++){ + char c = state->s[-i-1]; + state->s[-i-1] = state->s[-len+i]; + state->s[-len+i] = c; + } + return len; +} + +/* + * return length + */ + +static int +append_string (struct state *state, + const unsigned char *arg, + int width, + int prec, + int flags) +{ + int len = 0; + + if(arg == NULL) + arg = (const unsigned char*)"(null)"; + + if(prec != -1) + width -= prec; + else + width -= strlen((const char *)arg); + if(!(flags & minus_flag)) + while(width-- > 0) { + (*state->append_char) (state, ' '); + ++len; + } + if (prec != -1) { + while (*arg && prec--) { + (*state->append_char) (state, *arg++); + ++len; + } + } else { + while (*arg) { + (*state->append_char) (state, *arg++); + ++len; + } + } + if(flags & minus_flag) + while(width-- > 0) { + (*state->append_char) (state, ' '); + ++len; + } + return len; +} + +static int +append_char(struct state *state, + unsigned char arg, + int width, + int flags) +{ + int len = 0; + + while(!(flags & minus_flag) && --width > 0) { + (*state->append_char) (state, ' ') ; + ++len; + } + (*state->append_char) (state, arg); + ++len; + while((flags & minus_flag) && --width > 0) { + (*state->append_char) (state, ' '); + ++len; + } + return 0; +} + +/* + * This can't be made into a function... + */ + +#ifdef HAVE_LONG_LONG + +#define PARSE_INT_FORMAT(res, arg, unsig) \ +if (long_long_flag) \ + res = (unsig long long)va_arg(arg, unsig long long); \ +else if (long_flag) \ + res = (unsig long)va_arg(arg, unsig long); \ +else if (short_flag) \ + res = (unsig short)va_arg(arg, unsig int); \ +else \ + res = (unsig int)va_arg(arg, unsig int) + +#else + +#define PARSE_INT_FORMAT(res, arg, unsig) \ +if (long_flag) \ + res = (unsig long)va_arg(arg, unsig long); \ +else if (short_flag) \ + res = (unsig short)va_arg(arg, unsig int); \ +else \ + res = (unsig int)va_arg(arg, unsig int) + +#endif + +/* + * zyxprintf - return length, as snprintf + */ + +static int +xyzprintf (struct state *state, const char *char_format, va_list ap) +{ + const unsigned char *format = (const unsigned char *)char_format; + unsigned char c; + int len = 0; + + while((c = *format++)) { + if (c == '%') { + int flags = 0; + int width = 0; + int prec = -1; + int long_long_flag = 0; + int long_flag = 0; + int short_flag = 0; + + /* flags */ + while((c = *format++)){ + if(c == '-') + flags |= minus_flag; + else if(c == '+') + flags |= plus_flag; + else if(c == ' ') + flags |= space_flag; + else if(c == '#') + flags |= alternate_flag; + else if(c == '0') + flags |= zero_flag; + else + break; + } + + if((flags & space_flag) && (flags & plus_flag)) + flags ^= space_flag; + + if((flags & minus_flag) && (flags & zero_flag)) + flags ^= zero_flag; + + /* width */ + if (isdigit(c)) + do { + width = width * 10 + c - '0'; + c = *format++; + } while(isdigit(c)); + else if(c == '*') { + width = va_arg(ap, int); + c = *format++; + } + + /* precision */ + if (c == '.') { + prec = 0; + c = *format++; + if (isdigit(c)) + do { + prec = prec * 10 + c - '0'; + c = *format++; + } while(isdigit(c)); + else if (c == '*') { + prec = va_arg(ap, int); + c = *format++; + } + } + + /* size */ + + if (c == 'h') { + short_flag = 1; + c = *format++; + } else if (c == 'l') { + long_flag = 1; + c = *format++; + if (c == 'l') { + long_long_flag = 1; + c = *format++; + } + } + + switch (c) { + case 'c' : + append_char(state, va_arg(ap, int), width, flags); + ++len; + break; + case 's' : + len += append_string(state, + va_arg(ap, unsigned char*), + width, + prec, + flags); + break; + case 'd' : + case 'i' : { + longest arg; + u_longest num; + int minusp = 0; + + PARSE_INT_FORMAT(arg, ap, signed); + + if (arg < 0) { + minusp = 1; + num = -arg; + } else + num = arg; + + len += append_number (state, num, 10, "0123456789", + width, prec, flags, minusp); + break; + } + case 'u' : { + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 10, "0123456789", + width, prec, flags, 0); + break; + } + case 'o' : { + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 010, "01234567", + width, prec, flags, 0); + break; + } + case 'x' : { + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 0x10, "0123456789abcdef", + width, prec, flags, 0); + break; + } + case 'X' :{ + u_longest arg; + + PARSE_INT_FORMAT(arg, ap, unsigned); + + len += append_number (state, arg, 0x10, "0123456789ABCDEF", + width, prec, flags, 0); + break; + } + case 'p' : { + unsigned long arg = (unsigned long)va_arg(ap, void*); + + len += append_number (state, arg, 0x10, "0123456789ABCDEF", + width, prec, flags, 0); + break; + } + case 'n' : { + int *arg = va_arg(ap, int*); + *arg = state->s - state->str; + break; + } + case '\0' : + --format; + /* FALLTHROUGH */ + case '%' : + (*state->append_char)(state, c); + ++len; + break; + default : + (*state->append_char)(state, '%'); + (*state->append_char)(state, c); + len += 2; + break; + } + } else { + (*state->append_char) (state, c); + ++len; + } + } + return len; +} + +#if !defined(HAVE_SNPRINTF) || defined(TEST_SNPRINTF) +int +snprintf (char *str, size_t sz, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + ret = vsnprintf (str, sz, format, args); + va_end(args); + +#ifdef PARANOIA + { + int ret2; + char *tmp; + + tmp = malloc (sz); + if (tmp == NULL) + abort (); + + va_start(args, format); + ret2 = vsprintf (tmp, format, args); + va_end(args); + if (ret != ret2 || strcmp(str, tmp)) + abort (); + free (tmp); + } +#endif + + return ret; +} +#endif + +#if !defined(HAVE_ASPRINTF) || defined(TEST_SNPRINTF) +int +asprintf (char **ret, const char *format, ...) +{ + va_list args; + int val; + + va_start(args, format); + val = vasprintf (ret, format, args); + +#ifdef PARANOIA + { + int ret2; + char *tmp; + tmp = malloc (val + 1); + if (tmp == NULL) + abort (); + + ret2 = vsprintf (tmp, format, args); + if (val != ret2 || strcmp(*ret, tmp)) + abort (); + free (tmp); + } +#endif + + va_end(args); + return val; +} +#endif + +#if !defined(HAVE_VASPRINTF) || defined(TEST_SNPRINTF) +int +vasprintf (char **ret, const char *format, va_list args) +{ + return vasnprintf (ret, 0, format, args); +} +#endif + + +#if !defined(HAVE_VASNPRINTF) || defined(TEST_SNPRINTF) +int +vasnprintf (char **ret, size_t max_sz, const char *format, va_list args) +{ + int st; + struct state state; + + state.max_sz = max_sz; + state.sz = 1; + state.str = malloc(state.sz); + if (state.str == NULL) { + *ret = NULL; + return -1; + } + state.s = state.str; + state.theend = state.s + state.sz - 1; + state.append_char = as_append_char; + + st = xyzprintf (&state, format, args); + if (st > state.sz) { + free (state.str); + *ret = NULL; + return -1; + } else { + char *tmp; + + *state.s = '\0'; + tmp = realloc (state.str, st+1); + if (tmp == NULL) { + free (state.str); + *ret = NULL; + return -1; + } + *ret = tmp; + return st; + } +} +#endif + +#if !defined(HAVE_VSNPRINTF) || defined(TEST_SNPRINTF) +int +vsnprintf (char *str, size_t sz, const char *format, va_list args) +{ + struct state state; + int ret; + unsigned char *ustr = (unsigned char *)str; + + state.max_sz = 0; + state.sz = sz; + state.str = ustr; + state.s = ustr; + state.theend = ustr + sz - (sz > 0); + state.append_char = sn_append_char; + + ret = xyzprintf (&state, format, args); + if (state.s != NULL) + *state.s = '\0'; + return ret; +} +#endif + +#if !defined(HAVE_ASNPRINTF) || defined(TEST_SNPRINTF) +int +asnprintf (char **ret, size_t max_sz, const char *format, ...) +{ + va_list args; + int val; + + va_start(args, format); + val = vasnprintf (ret, max_sz, format, args); + +#ifdef PARANOIA + { + int ret2; + char *tmp; + tmp = malloc (val + 1); + if (tmp == NULL) + abort (); + + ret2 = vsprintf (tmp, format, args); + if (val != ret2 || strcmp(*ret, tmp)) + abort (); + free (tmp); + } +#endif + + va_end(args); + return val; +} +#endif diff --git a/external/bsd/iscsi/dist/src/so.c b/external/bsd/iscsi/dist/src/so.c new file mode 100644 index 000000000000..e88e39fd0126 --- /dev/null +++ b/external/bsd/iscsi/dist/src/so.c @@ -0,0 +1,1060 @@ + +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2002, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Linux SCSI upper layer driver for OSD + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "scsi.h" +#include "hosts.h" +#include "so.h" +#include +#include "constants.h" +#include +#include +#include "iscsiutil.h" +#include "osd.h" + +/* + * Macros + */ + +#define SCSI_OSD_MAJOR 232 /* major.h */ +#define MAJOR_NR SCSI_OSD_MAJOR /* hosts.h */ +#define DEVICE_NAME "scsiosd" /* blk.h */ +#define TIMEOUT_VALUE (2*HZ) /* blk.h */ +#define DEVICE_NR(device) MINOR(device) /* blk.h */ +#define SCSI_OSDS_PER_MAJOR 256 +#define MAX_RETRIES 5 +#define SO_TIMEOUT (30 * HZ) +#define SO_MOD_TIMEOUT (75 * HZ) + +/* + * Globals + */ + +struct hd_struct *so; +static Scsi_Osd *rscsi_osds; +static int *so_sizes; +static int *so_blocksizes; +static int *so_hardsizes; +static int check_scsiosd_media_change(kdev_t); +static int so_init_oneosd(int); + +/* + * Function prototypes + */ + +static int so_init(void); +static void so_finish(void); +static int so_attach(Scsi_Device *); +static int so_detect(Scsi_Device *); +static void so_detach(Scsi_Device *); +static int so_init_command(Scsi_Cmnd *); +static void rw_intr(Scsi_Cmnd * SCpnt); +static int fop_revalidate_scsiosd(kdev_t); +static int revalidate_scsiosd(kdev_t dev, int maxusage); + + +/* + * Templates + */ + +static struct Scsi_Device_Template so_template = { + name: "osd", + tag: "so", + scsi_type: TYPE_OSD, + major: SCSI_OSD_MAJOR, + blk: 1, + detect: so_detect, + init: so_init, + finish: so_finish, + attach: so_attach, + detach: so_detach, + init_command: so_init_command, +}; + +/* + * Functions + */ + +static int so_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) +{ + kdev_t dev = inode->i_rdev; + struct Scsi_Host * host; + Scsi_Device * SDev; + int osdinfo[4]; + + iscsi_trace(TRACE_OSDSO, "so_ioctl()\n"); + + SDev = rscsi_osds[DEVICE_NR(dev)].device; + /* + * If we are in the middle of error recovery, don't let anyone + * else try and use this device. Also, if error recovery fails, it + * may try and take the device offline, in which case all further + * access to the device is prohibited. + */ + + if( !scsi_block_when_processing_errors(SDev) ) + { + return -ENODEV; + } + + switch (cmd) + { + case HDIO_GETGEO: /* Return BIOS osd parameters */ + { + struct hd_geometry *loc = (struct hd_geometry *) arg; + if(!loc) + return -EINVAL; + + host = rscsi_osds[DEVICE_NR(dev)].device->host; + + /* default to most commonly used values */ + + osdinfo[0] = 0x40; + osdinfo[1] = 0x20; + osdinfo[2] = rscsi_osds[DEVICE_NR(dev)].capacity >> 11; + + /* override with calculated, extended default, or driver values */ + +#if 0 + if(host->hostt->bios_param != NULL) + host->hostt->bios_param(&rscsi_osds[DEVICE_NR(dev)], dev, &osdinfo[0]); + else scsicam_bios_param(&rscsi_osds[DEVICE_NR(dev)], dev, &osdinfo[0]); + + if (put_user(osdinfo[0], &loc->heads) || + put_user(osdinfo[1], &loc->sectors) || + put_user(osdinfo[2], &loc->cylinders) || + put_user(so[MINOR(inode->i_rdev)].start_sect, &loc->start)) + return -EFAULT; + return 0; +#else + return -1; +#endif + } + case HDIO_GETGEO_BIG: + { + struct hd_big_geometry *loc = (struct hd_big_geometry *) arg; + + if(!loc) + return -EINVAL; + + host = rscsi_osds[DEVICE_NR(dev)].device->host; + + /* default to most commonly used values */ + + osdinfo[0] = 0x40; + osdinfo[1] = 0x20; + osdinfo[2] = rscsi_osds[DEVICE_NR(dev)].capacity >> 11; + + /* override with calculated, extended default, or driver values */ + +#if 0 + if(host->hostt->bios_param != NULL) + host->hostt->bios_param(&rscsi_osds[DEVICE_NR(dev)], dev, &osdinfo[0]); + else scsicam_bios_param(&rscsi_osds[DEVICE_NR(dev)], dev, &osdinfo[0]); + + if (put_user(osdinfo[0], &loc->heads) || + put_user(osdinfo[1], &loc->sectors) || + put_user(osdinfo[2], (unsigned int *) &loc->cylinders) || + put_user(so[MINOR(inode->i_rdev)].start_sect, &loc->start)) + return -EFAULT; + return 0; +#else + return -1; +#endif + } + case BLKGETSIZE: /* Return device size */ + if (!arg) + return -EINVAL; + return put_user(so[MINOR(inode->i_rdev)].nr_sects, (long *) arg); + + case BLKROSET: + case BLKROGET: + case BLKRASET: + case BLKRAGET: + case BLKFLSBUF: + case BLKSSZGET: + case BLKPG: + case BLKELVGET: + case BLKELVSET: + return blk_ioctl(inode->i_rdev, cmd, arg); + + case BLKRRPART: /* Re-read partition tables */ + if (!capable(CAP_SYS_ADMIN)) + return -EACCES; + return revalidate_scsiosd(dev, 1); + + default: + return scsi_ioctl(rscsi_osds[DEVICE_NR(dev)].device , cmd, (void *) arg); + } +} + +static void so_devname(unsigned int index, char *buffer) { + iscsi_trace(TRACE_OSDSO, "so_devname(%i)\n", index); + sprintf(buffer, "so%i", index); +} + +static request_queue_t *so_find_queue(kdev_t dev) +{ + Scsi_Osd *dpnt; + int target; + + iscsi_trace(TRACE_OSDSO, "so_find_queue()\n"); + + target = DEVICE_NR(dev); + + dpnt = &rscsi_osds[target]; + if (!dpnt) { + iscsi_trace_error("no such device\n"); + return NULL; + } + return &dpnt->device->request_queue; +} + +static int so_init_command(Scsi_Cmnd * SCpnt) +{ + int block, this_count; + Scsi_Osd *dpnt; + char nbuff[6]; + osd_args_t args; + int index; + + iscsi_trace(TRACE_OSDSO, "so_init_command(MAJOR %i, MINOR %i)\n", + MAJOR(SCpnt->request.rq_dev), MINOR(SCpnt->request.rq_dev)); + index = MINOR(SCpnt->request.rq_dev); + so_devname(index, nbuff); + block = SCpnt->request.sector; + this_count = SCpnt->request_bufflen >> 9; + dpnt = &rscsi_osds[index]; + + if (index >= so_template.dev_max || !dpnt || !dpnt->device->online || + block + SCpnt->request.nr_sectors > so[index].nr_sects) { + iscsi_trace_error("index %i: request out of range: %i offset + %li count > %li total sectors\n", + index, block, SCpnt->request.nr_sectors, so[index].nr_sects); + return 0; + } + + block += so[index].start_sect; + if (dpnt->device->changed) { + iscsi_trace_error("SCSI osd has been changed. Prohibiting further I/O\n"); + return 0; + } + + switch (SCpnt->request.cmd) { + case WRITE: + + iscsi_trace(TRACE_OSDSO, "Translating BLOCK WRITE to OBJECT WRITE\n"); + if (!dpnt->device->writeable) { + iscsi_trace_error("device is not writable\n"); + return 0; + } + iscsi_trace(TRACE_OSDSO, "Translating BLOCK WRITE (sector %i, len %i) to OBJECT WRITE\n", block, this_count); + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7f; + args.add_cdb_len = CONFIG_OSD_CDB_LEN-7; + args.service_action = OSD_WRITE; + args.GroupID = 0; args.UserID = 0; + args.length = 512*this_count; + args.offset = 512*block; + OSD_ENCAP_CDB(&args, SCpnt->cmnd); + SCpnt->sc_data_direction = SCSI_DATA_WRITE; + SCpnt->cmd_len = CONFIG_OSD_CDB_LEN; + SCpnt->result = 0; + break; + + case READ: + + iscsi_trace(TRACE_OSDSO, "Translating BLOCK READ (sector %i, len %i) to OBJECT READ\n", block, this_count); + memset(&args, 0, sizeof(osd_args_t)); + args.opcode = 0x7f; + args.add_cdb_len = CONFIG_OSD_CDB_LEN-7; + args.service_action = OSD_READ; + args.GroupID = 0; args.UserID = 0; + args.length = 512*this_count; + args.offset = 512*block; + OSD_ENCAP_CDB(&args, SCpnt->cmnd); + SCpnt->sc_data_direction = SCSI_DATA_READ; + SCpnt->cmd_len = CONFIG_OSD_CDB_LEN; + SCpnt->result = 0; + break; + + default: + panic("Unknown so command %d\n", SCpnt->request.cmd); + } + + /* + * We shouldn't disconnect in the middle of a sector, so with a dumb + * host adapter, it's safe to assume that we can at least transfer + * this many bytes between each connect / disconnect. + */ + + SCpnt->transfersize = dpnt->device->sector_size; + SCpnt->underflow = this_count << 9; + SCpnt->allowed = MAX_RETRIES; + SCpnt->timeout_per_command = (SCpnt->device->type == TYPE_OSD ? + SO_TIMEOUT : SO_MOD_TIMEOUT); + + /* + * This is the completion routine we use. This is matched in terms + * of capability to this function. + */ + + SCpnt->done = rw_intr; + + /* + * This indicates that the command is ready from our end to be + * queued. + */ + + return 1; +} + +static int so_open(struct inode *inode, struct file *filp) +{ + int target; + Scsi_Device * SDev; + target = DEVICE_NR(inode->i_rdev); + + iscsi_trace(TRACE_OSDSO, "so_open()\n"); + + SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, so_template.dev_max)); + + if (target >= so_template.dev_max || !rscsi_osds[target].device) + return -ENXIO; /* No such device */ + + /* + * If the device is in error recovery, wait until it is done. + * If the device is offline, then disallow any access to it. + */ + if (!scsi_block_when_processing_errors(rscsi_osds[target].device)) { + return -ENXIO; + } + /* + * Make sure that only one process can do a check_change_osd at one time. + * This is also used to lock out further access when the partition table + * is being re-read. + */ + + while (rscsi_osds[target].device->busy) + barrier(); + if (rscsi_osds[target].device->removable) { + check_disk_change(inode->i_rdev); + + /* + * If the drive is empty, just let the open fail. + */ + if (!rscsi_osds[target].ready) + return -ENXIO; + + /* + * Similarly, if the device has the write protect tab set, + * have the open fail if the user expects to be able to write + * to the thing. + */ + if ((rscsi_osds[target].write_prot) && (filp->f_mode & 2)) + return -EROFS; + } + SDev = rscsi_osds[target].device; + /* + * It is possible that the osd changing stuff resulted in the device + * being taken offline. If this is the case, report this to the user, + * and don't pretend that + * the open actually succeeded. + */ + if (!SDev->online) { + return -ENXIO; + } + /* + * See if we are requesting a non-existent partition. Do this + * after checking for osd change. + */ + if (so_sizes[MINOR(inode->i_rdev)] == 0) + return -ENXIO; + + if (SDev->removable) + if (!SDev->access_count) + if (scsi_block_when_processing_errors(SDev)) + scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, NULL); + + SDev->access_count++; + if (SDev->host->hostt->module) + __MOD_INC_USE_COUNT(SDev->host->hostt->module); + if (so_template.module) + __MOD_INC_USE_COUNT(so_template.module); + return 0; +} + +static int so_release(struct inode *inode, struct file *file) +{ + int target; + Scsi_Device * SDev; + + iscsi_trace(TRACE_OSDSO, "so_release()\n"); + + target = DEVICE_NR(inode->i_rdev); + SDev = rscsi_osds[target].device; + + SDev->access_count--; + + if (SDev->removable) { + if (!SDev->access_count) + if (scsi_block_when_processing_errors(SDev)) + scsi_ioctl(SDev, SCSI_IOCTL_DOORUNLOCK, NULL); + } + if (SDev->host->hostt->module) + __MOD_DEC_USE_COUNT(SDev->host->hostt->module); + if (so_template.module) + __MOD_DEC_USE_COUNT(so_template.module); + return 0; +} + +static struct block_device_operations so_fops = +{ + open: so_open, + release: so_release, + ioctl: so_ioctl, + check_media_change: check_scsiosd_media_change, + revalidate: fop_revalidate_scsiosd +}; + +/* + * If we need more than one SCSI osd major (i.e. more than + * 16 SCSI osds), we'll have to kmalloc() more gendisks later. + */ + +static struct gendisk so_gendisk = +{ + SCSI_OSD_MAJOR, /* Major number */ + "so", /* Major name */ + 0, /* Bits to shift to get real from partition */ + 1, /* Number of partitions per real */ + NULL, /* hd struct */ + NULL, /* block sizes */ + 0, /* number */ + NULL, /* internal */ + NULL, /* next */ + &so_fops, /* file operations */ +}; + +/* + * rw_intr is the interrupt routine for the device driver. + * It will be notified on the end of a SCSI read / write, and + * will take one of several actions based on success or failure. + */ + +static void rw_intr(Scsi_Cmnd * SCpnt) +{ + int result = SCpnt->result; + char nbuff[6]; + int this_count = SCpnt->bufflen >> 9; + int good_sectors = (result == 0 ? this_count : 0); + int block_sectors = 1; + + so_devname(DEVICE_NR(SCpnt->request.rq_dev), nbuff); + iscsi_trace(TRACE_OSDSO, "rw_intr(/dev/%s, host %d, result 0x%x)\n", nbuff, SCpnt->host->host_no, result); + + /* + Handle MEDIUM ERRORs that indicate partial success. Since this is a + relatively rare error condition, no care is taken to avoid + unnecessary additional work such as memcpy's that could be avoided. + */ + + /* An error occurred */ + if (driver_byte(result) != 0) { + /* Sense data is valid */ + if (SCpnt->sense_buffer[0] == 0xF0 && SCpnt->sense_buffer[2] == MEDIUM_ERROR) { + long error_sector = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | + SCpnt->sense_buffer[6]; + if (SCpnt->request.bh != NULL) + block_sectors = SCpnt->request.bh->b_size >> 9; + switch (SCpnt->device->sector_size) { + case 1024: + error_sector <<= 1; + if (block_sectors < 2) + block_sectors = 2; + break; + case 2048: + error_sector <<= 2; + if (block_sectors < 4) + block_sectors = 4; + break; + case 4096: + error_sector <<=3; + if (block_sectors < 8) + block_sectors = 8; + break; + case 256: + error_sector >>= 1; + break; + default: + break; + } + error_sector -= so[MINOR(SCpnt->request.rq_dev)].start_sect; + error_sector &= ~(block_sectors - 1); + good_sectors = error_sector - SCpnt->request.sector; + if (good_sectors < 0 || good_sectors >= this_count) + good_sectors = 0; + } + if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { + if (SCpnt->device->ten == 1) { + if (SCpnt->cmnd[0] == READ_10 || + SCpnt->cmnd[0] == WRITE_10) + SCpnt->device->ten = 0; + } + } + } + /* + * This calls the generic completion function, now that we know + * how many actual sectors finished, and how many sectors we need + * to say have failed. + */ + scsi_io_completion(SCpnt, good_sectors, block_sectors); +} +/* + * requeue_so_request() is the request handler function for the so driver. + * Its function in life is to take block device requests, and translate + * them to SCSI commands. + */ + + +static int check_scsiosd_media_change(kdev_t full_dev) +{ + int retval; + int target; + int flag = 0; + Scsi_Device * SDev; + + iscsi_trace(TRACE_OSDSO, "check_scsiosd_media_change()\n"); + + target = DEVICE_NR(full_dev); + SDev = rscsi_osds[target].device; + + if (target >= so_template.dev_max || !SDev) { + printk("SCSI osd request error: invalid device.\n"); + return 0; + } + if (!SDev->removable) + return 0; + + /* + * If the device is offline, don't send any commands - just pretend as + * if the command failed. If the device ever comes back online, we + * can deal with it then. It is only because of unrecoverable errors + * that we would ever take a device offline in the first place. + */ + if (SDev->online == FALSE) { + rscsi_osds[target].ready = 0; + SDev->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ + } + + /* Using Start/Stop enables differentiation between drive with + * no cartridge loaded - NOT READY, drive with changed cartridge - + * UNIT ATTENTION, or with same cartridge - GOOD STATUS. + * This also handles drives that auto spin down. eg iomega jaz 1GB + * as this will spin up the drive. + */ + retval = -ENODEV; + if (scsi_block_when_processing_errors(SDev)) + retval = scsi_ioctl(SDev, SCSI_IOCTL_START_UNIT, NULL); + + if (retval) { /* Unable to test, unit probably not ready. + * This usually means there is no disc in the + * drive. Mark as changed, and we will figure + * it out later once the drive is available + * again. */ + + rscsi_osds[target].ready = 0; + SDev->changed = 1; + return 1; /* This will force a flush, if called from + * check_disk_change */ + } + /* + * for removable scsi osd ( FLOPTICAL ) we have to recognise the + * presence of osd in the drive. This is kept in the Scsi_Osd + * struct and tested at open ! Daniel Roche ( dan@lectra.fr ) + */ + + rscsi_osds[target].ready = 1; /* FLOPTICAL */ + + retval = SDev->changed; + if (!flag) + SDev->changed = 0; + return retval; +} + +static int so_init_oneosd(int i) { + unsigned char cmd[10]; + char nbuff[6]; + Scsi_Request *SRpnt; + + iscsi_trace(TRACE_OSDSO, "so_init_oneosd(%i)\n", i); + + so_devname(i, nbuff); + if (rscsi_osds[i].device->online == FALSE) { + iscsi_trace_error("device is offline??\n"); + return i; + } + + /* + * TEST_UNIT_READY + */ + + SRpnt = scsi_allocate_request(rscsi_osds[i].device); + cmd[0] = TEST_UNIT_READY; + cmd[1] = (rscsi_osds[i].device->lun << 5) & 0xe0; + memset((void *) &cmd[2], 0, 8); + SRpnt->sr_cmd_len = 0; + SRpnt->sr_sense_buffer[0] = 0; + SRpnt->sr_sense_buffer[2] = 0; + SRpnt->sr_data_direction = SCSI_DATA_READ; + scsi_wait_req (SRpnt, (void *) cmd, NULL, 0, SO_TIMEOUT, MAX_RETRIES); + if (SRpnt->sr_result!=0) { + iscsi_trace_error("OSD not ready\n"); + return i; + } + + /* Initialize device */ + + rscsi_osds[i].capacity = 1048576*512; + rscsi_osds[i].device->changed = 0; + rscsi_osds[i].ready = 0; + rscsi_osds[i].write_prot = 0; + rscsi_osds[i].device->removable = 0; + SRpnt->sr_device->ten = 1; + SRpnt->sr_device->remap = 1; + SRpnt->sr_device->sector_size = 512; + + /* printk("%s : block size assumed to be 512 bytes, osd size 1GB. \n", nbuff); */ + + /* Wake up a process waiting for device */ + + scsi_release_request(SRpnt); + + /* Cleanup */ + + SRpnt = NULL; + return i; +} + +/* + * The so_init() function looks at all SCSI drives present, determines + * their size, and reads partition table entries for them. + */ + +static int so_registered; + +static int so_init() { + int i; + + iscsi_trace(TRACE_OSDSO, "so_init()\n"); + + if (so_template.dev_noticed == 0) { + iscsi_trace_error("no OSDs noticed\n"); + return 0; + } + if (!rscsi_osds) { + printf("%i osds detected \n", so_template.dev_noticed); + so_template.dev_max = so_template.dev_noticed; + } + if (so_template.dev_max > SCSI_OSDS_PER_MAJOR) { + iscsi_trace_error("so_template.dev_max (%i) > SCSI_OSDS_PER_MAJOR\n", so_template.dev_max); + so_template.dev_max = SCSI_OSDS_PER_MAJOR; + } + if (!so_registered) { + if (devfs_register_blkdev(SCSI_OSD_MAJOR, "so", &so_fops)) { + printk("Unable to get major %d for SCSI osd\n", SCSI_OSD_MAJOR); + return 1; + } + so_registered++; + } + + /* No loadable devices yet */ + + if (rscsi_osds) return 0; + + /* Real devices */ + + if ((rscsi_osds = kmalloc(so_template.dev_max * sizeof(Scsi_Osd), GFP_ATOMIC))==NULL) { + iscsi_trace_error("kmalloc() failed\n"); + goto cleanup_devfs; + } + memset(rscsi_osds, 0, so_template.dev_max * sizeof(Scsi_Osd)); + so_gendisk.real_devices = (void *) rscsi_osds; + + /* Partition sizes */ + + if ((so_sizes=kmalloc(so_template.dev_max*sizeof(int), GFP_ATOMIC))==NULL) { + iscsi_trace_error("kmalloc() failed\n"); + goto cleanup_rscsi_osds; + } + memset(so_sizes, 0, so_template.dev_max*sizeof(int)); + so_gendisk.sizes = so_sizes; + + /* Block sizes */ + + if ((so_blocksizes=kmalloc(so_template.dev_max*sizeof(int), GFP_ATOMIC))==NULL) { + iscsi_trace_error("kmalloc() failed\n"); + goto cleanup_so_sizes; + } + blksize_size[SCSI_OSD_MAJOR] = so_blocksizes; + + /* Sector sizes */ + + if ((so_hardsizes=kmalloc(so_template.dev_max*sizeof(int), GFP_ATOMIC))==NULL) { + iscsi_trace_error("kmalloc() failed\n"); + goto cleanup_so_blocksizes; + } + hardsect_size[SCSI_OSD_MAJOR] = so_hardsizes; + + /* Partitions */ + + if ((so=kmalloc(so_template.dev_max*sizeof(struct hd_struct), GFP_ATOMIC))==NULL) { + iscsi_trace_error("kmalloc() failed\n"); + goto cleanup_so_hardsizes; + } + memset(so, 0, so_template.dev_max*sizeof(struct hd_struct)); + so_gendisk.part = so; + + /* Initialize Things */ + + for (i=0; inext) + if (gendisk == &so_gendisk) + break; + if (gendisk == NULL) { + so_gendisk.next = gendisk_head; + gendisk_head = &so_gendisk; + } + + for (i = 0; i < so_template.dev_max; ++i) + if (!rscsi_osds[i].capacity && rscsi_osds[i].device) { + so_init_oneosd(i); + if (!rscsi_osds[i].has_part_table) { + so_sizes[i] = rscsi_osds[i].capacity; + register_disk(&so_gendisk, MKDEV(MAJOR(i),MINOR(i)), 1, &so_fops, rscsi_osds[i].capacity); + rscsi_osds[i].has_part_table = 1; + } + } + + /* No read-ahead right not */ + + read_ahead[SCSI_OSD_MAJOR] = 0; + + return; +} + +static int so_detect(Scsi_Device * SDp) +{ + char nbuff[6]; + iscsi_trace(TRACE_OSDSO, "so_detect()\n"); + + if (SDp->type != TYPE_OSD && SDp->type != TYPE_MOD) + return 0; + + so_devname(so_template.dev_noticed++, nbuff); + printk("Detected scsi %sosd %s at scsi%d, channel %d, id %d, lun %d\n", + SDp->removable ? "removable " : "", + nbuff, + SDp->host->host_no, SDp->channel, SDp->id, SDp->lun); + + return 1; +} + +static int so_attach(Scsi_Device * SDp) +{ + unsigned int devnum; + Scsi_Osd *dpnt; + int i; + + iscsi_trace(TRACE_OSDSO, "so_attach(SDpnt 0x%p)\n", SDp); + if (SDp->type != TYPE_OSD && SDp->type != TYPE_MOD) + return 0; + + if (so_template.nr_dev >= so_template.dev_max) { + SDp->attached--; + return 1; + } + for (dpnt = rscsi_osds, i = 0; i < so_template.dev_max; i++, dpnt++) + if (!dpnt->device) + break; + + if (i >= so_template.dev_max) + panic("scsi_devices corrupt (so)"); + + rscsi_osds[i].device = SDp; + rscsi_osds[i].has_part_table = 0; + so_template.nr_dev++; + so_gendisk.nr_real++; + devnum = i % SCSI_OSDS_PER_MAJOR; + so_gendisk.de_arr[devnum] = SDp->de; + if (SDp->removable) + so_gendisk.flags[devnum] |= GENHD_FL_REMOVABLE; + return 0; +} + +#define DEVICE_BUSY rscsi_osds[target].device->busy +#define USAGE rscsi_osds[target].device->access_count +#define CAPACITY rscsi_osds[target].capacity +#define MAYBE_REINIT so_init_oneosd(target) + +/* This routine is called to flush all partitions and partition tables + * for a changed scsi osd, and then re-read the new partition table. + * If we are revalidating a osd because of a media change, then we + * enter with usage == 0. If we are using an ioctl, we automatically have + * usage == 1 (we need an open channel to use an ioctl :-), so this + * is our limit. + */ + +int revalidate_scsiosd(kdev_t dev, int maxusage) +{ + int target; + int max_p; + int start; + int i; + + iscsi_trace(TRACE_OSDSO, "revalidate_scsiosd()\n"); + + target = DEVICE_NR(dev); + + if (DEVICE_BUSY || USAGE > maxusage) { + printk("Device busy for revalidation (usage=%d)\n", USAGE); + return -EBUSY; + } + DEVICE_BUSY = 1; + + max_p = so_gendisk.max_p; + start = target << so_gendisk.minor_shift; + + for (i = max_p - 1; i >= 0; i--) { + int index = start + i; + /* invalidate_device(MKDEV(MAJOR(index),MINOR(index)), 1); */ + so_gendisk.part[index].start_sect = 0; + so_gendisk.part[index].nr_sects = 0; + /* + * Reset the blocksize for everything so that we can read + * the partition table. Technically we will determine the + * correct block size when we revalidate, but we do this just + * to make sure that everything remains consistent. + */ + so_blocksizes[index] = 1024; + if (rscsi_osds[target].device->sector_size == 2048) + so_blocksizes[index] = 2048; + else + so_blocksizes[index] = 1024; + } + +#ifdef MAYBE_REINIT + MAYBE_REINIT; +#endif + + grok_partitions(&so_gendisk, target % SCSI_OSDS_PER_MAJOR, 1, CAPACITY); + + DEVICE_BUSY = 0; + return 0; +} + +static int fop_revalidate_scsiosd(kdev_t dev) +{ + iscsi_trace(TRACE_OSDSO, "fop_revalidate_scsiosd()\n"); + return revalidate_scsiosd(dev, 0); +} +static void so_detach(Scsi_Device * SDp) +{ + Scsi_Osd *dpnt; + int i, j; + int max_p; + int start; + + iscsi_trace(TRACE_OSDSO, "so_detach()\n"); + + for (dpnt = rscsi_osds, i = 0; i < so_template.dev_max; i++, dpnt++) + if (dpnt->device == SDp) { + + /* If we are disconnecting a osd driver, sync and invalidate + * everything */ + max_p = so_gendisk.max_p; + start = i << so_gendisk.minor_shift; + + for (j = max_p - 1; j >= 0; j--) { + int index = start + j; + /* invalidate_device(MKDEV(MAJOR(index),MINOR(index)), 1); */ + so_gendisk.part[index].start_sect = 0; + so_gendisk.part[index].nr_sects = 0; + so_sizes[index] = 0; + } + devfs_register_partitions (&so_gendisk, MINOR(start), 1); + /* unregister_disk() */ + dpnt->has_part_table = 0; + dpnt->device = NULL; + dpnt->capacity = 0; + SDp->attached--; + so_template.dev_noticed--; + so_template.nr_dev--; + so_gendisk.nr_real--; + return; + } + return; +} + +static int __init init_so(void) +{ + iscsi_trace(TRACE_OSDSO, "init_so()\n"); + so_template.module = THIS_MODULE; + return scsi_register_module(MODULE_SCSI_DEV, &so_template); +} + +static void __exit exit_so(void) +{ + struct gendisk **prev_sogd_link; + struct gendisk *sogd; + int removed = 0; + + iscsi_trace(TRACE_OSDSO, "exit_so()\n"); + + scsi_unregister_module(MODULE_SCSI_DEV, &so_template); + + devfs_unregister_blkdev(SCSI_OSD_MAJOR, "so"); + + so_registered--; + if (rscsi_osds != NULL) { + kfree(rscsi_osds); + kfree(so_sizes); + kfree(so_blocksizes); + kfree(so_hardsizes); + kfree((char *) so); + + /* + * Now remove &so_gendisk from the linked list + */ + prev_sogd_link = &gendisk_head; + while ((sogd = *prev_sogd_link) != NULL) { + if (sogd >= &so_gendisk && sogd <= &so_gendisk) { + removed++; + *prev_sogd_link = sogd->next; + continue; + } + prev_sogd_link = &sogd->next; + } + + if (removed != 1) + printk("%s %d &so_gendisk in osd chain", removed > 1 ? "total" : "just", removed); + + } + blk_size[SCSI_OSD_MAJOR] = NULL; + hardsect_size[SCSI_OSD_MAJOR] = NULL; + read_ahead[SCSI_OSD_MAJOR] = 0; + so_template.dev_max = 0; +} + +module_init(init_so); +module_exit(exit_so); diff --git a/external/bsd/iscsi/dist/src/start_osd b/external/bsd/iscsi/dist/src/start_osd new file mode 100644 index 000000000000..7d0a8e819b4c --- /dev/null +++ b/external/bsd/iscsi/dist/src/start_osd @@ -0,0 +1,5 @@ +#!/bin/sh +insmod ./so.o +insmod ./intel_iscsi.o +insmod ./osdfs.o +mount -t osdfs /dev/so0 /mnt -o gid=0x2d159c01 -o uid=0x2c8f1801 diff --git a/external/bsd/iscsi/dist/src/stop_osd b/external/bsd/iscsi/dist/src/stop_osd new file mode 100644 index 000000000000..d5f5c3a737ec --- /dev/null +++ b/external/bsd/iscsi/dist/src/stop_osd @@ -0,0 +1,5 @@ +#!/bin/sh +umount /mnt +rmmod osdfs +rmmod intel_iscsi +rmmod so diff --git a/external/bsd/iscsi/dist/src/storage.c b/external/bsd/iscsi/dist/src/storage.c new file mode 100644 index 000000000000..207beeb73b05 --- /dev/null +++ b/external/bsd/iscsi/dist/src/storage.c @@ -0,0 +1,424 @@ +/* $NetBSD: storage.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include "config.h" + +#include +#include + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include "iscsi.h" +#include "iscsiutil.h" +#include "target.h" +#include "device.h" + +#include "conffile.h" +#include "storage.h" + +/* let's use symbolic names for the fields in the config file */ +enum { + EXTENT_NAME_COL = 0, + EXTENT_DEVICE_COL = 1, + EXTENT_SACRED_COL = 2, + EXTENT_LENGTH_COL = 3, + + DEVICE_NAME_COL = 0, + DEVICE_RAIDLEVEL_COL = 1, + DEVICE_LENGTH_COL = 2, + + TARGET_NAME_COL = 0, + TARGET_V1_DEVICE_COL = 1, + TARGET_V1_NETMASK_COL = 2, + TARGET_V2_FLAGS_COL = 1, + TARGET_V2_DEVICE_COL = 2, + TARGET_V2_NETMASK_COL = 3 +}; + +#define DEFAULT_FLAGS "ro" + + +/* find an extent by name */ +static disc_extent_t * +find_extent(extv_t *evp, char *s) +{ + size_t i; + + for (i = 0 ; i < evp->c ; i++) { + if (strcmp(evp->v[i].extent, s) == 0) { + return &evp->v[i]; + } + } + return NULL; +} + +/* allocate space for a new extent */ +static int +do_extent(conffile_t *cf, extv_t *evp, ent_t *ep) +{ + struct stat st; + char *cp; + + if (find_extent(evp, ep->sv.v[EXTENT_NAME_COL]) != NULL) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: attempt to re-define extent `%s'\n", ep->sv.v[EXTENT_NAME_COL]); + return 0; + } + ALLOC(disc_extent_t, evp->v, evp->size, evp->c, 14, 14, "do_extent", exit(EXIT_FAILURE)); + evp->v[evp->c].extent = strdup(ep->sv.v[EXTENT_NAME_COL]); + evp->v[evp->c].dev = strdup(ep->sv.v[EXTENT_DEVICE_COL]); + evp->v[evp->c].sacred = strtoll(ep->sv.v[EXTENT_SACRED_COL], NULL, 10); + if (strcasecmp(ep->sv.v[EXTENT_LENGTH_COL], "size") == 0) { + if (stat(ep->sv.v[EXTENT_DEVICE_COL], &st) == 0) { + evp->v[evp->c].len = st.st_size; + } + } else { + evp->v[evp->c].len = strtoll(ep->sv.v[EXTENT_LENGTH_COL], &cp, 10); + if (cp != NULL) { + switch(tolower((unsigned)*cp)) { + case 't': + evp->v[evp->c].len *= (uint64_t)(1024ULL * 1024ULL * 1024ULL * 1024ULL); + break; + case 'g': + evp->v[evp->c].len *= (uint64_t)(1024ULL * 1024ULL * 1024ULL); + break; + case 'm': + evp->v[evp->c].len *= (uint64_t)(1024ULL * 1024ULL); + break; + case 'k': + evp->v[evp->c].len *= (uint64_t)1024ULL; + break; + } + } + } + evp->c += 1; + return 1; +} + +/* find a device by name */ +static disc_device_t * +find_device(devv_t *devvp, char *s) +{ + size_t i; + + for (i = 0 ; i < devvp->c ; i++) { + if (strcmp(devvp->v[i].dev, s) == 0) { + return &devvp->v[i]; + } + } + return NULL; +} + +/* return the size of the sub-device/extent */ +static uint64_t +getsize(conffile_t *cf, devv_t *devvp, extv_t *evp, char *s) +{ + disc_extent_t *xp; + disc_device_t *dp; + + if ((xp = find_extent(evp, s)) != NULL) { + return xp->len; + } + if ((dp = find_device(devvp, s)) != NULL) { + switch (dp->xv[0].type) { + case DE_EXTENT: + return dp->xv[0].u.xp->len; + case DE_DEVICE: + return dp->xv[0].u.dp->len; + } + } + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Warning: sub-device/extent `%s' not found\n", s); + return 0; +} + +/* allocate space for a device */ +static int +do_device(conffile_t *cf, devv_t *devvp, extv_t *evp, ent_t *ep) +{ + if (find_device(devvp, ep->sv.v[DEVICE_NAME_COL]) != NULL) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: attempt to re-define device `%s'\n", ep->sv.v[DEVICE_NAME_COL]); + return 0; + } + ALLOC(disc_device_t, devvp->v, devvp->size, devvp->c, 14, 14, "do_device", exit(EXIT_FAILURE)); + devvp->v[devvp->c].dev = strdup(ep->sv.v[DEVICE_NAME_COL]); + devvp->v[devvp->c].raid = (strncasecmp(ep->sv.v[DEVICE_RAIDLEVEL_COL], "raid", 4) == 0) ? atoi(&ep->sv.v[DEVICE_RAIDLEVEL_COL][4]) : 0; + devvp->v[devvp->c].size = ep->sv.c - 2; + devvp->v[devvp->c].len = getsize(cf, devvp, evp, ep->sv.v[DEVICE_LENGTH_COL]); + NEWARRAY(disc_de_t, devvp->v[devvp->c].xv, ep->sv.c - 2, "do_device", exit(EXIT_FAILURE)); + for (devvp->v[devvp->c].c = 0 ; devvp->v[devvp->c].c < devvp->v[devvp->c].size ; devvp->v[devvp->c].c++) { + if ((devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.xp = find_extent(evp, ep->sv.v[devvp->v[devvp->c].c + 2])) != NULL) { + if (devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.xp->used) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: extent `%s' has already been used\n", ep->sv.v[devvp->v[devvp->c].c + 2]); + return 0; + } + if (devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.xp->len != devvp->v[devvp->c].len && devvp->v[devvp->c].raid != 0) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: extent `%s' has size %" PRIu64 ", not %" PRIu64"\n", ep->sv.v[devvp->v[devvp->c].c + 2], devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.xp->len, devvp->v[devvp->c].len); + return 0; + } + devvp->v[devvp->c].xv[devvp->v[devvp->c].c].type = DE_EXTENT; + devvp->v[devvp->c].xv[devvp->v[devvp->c].c].size = devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.xp->len; + devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.xp->used = 1; + } else if ((devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.dp = find_device(devvp, ep->sv.v[devvp->v[devvp->c].c + 2])) != NULL) { + if (devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.dp->used) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: device `%s' has already been used\n", ep->sv.v[devvp->v[devvp->c].c + 2]); + return 0; + } + devvp->v[devvp->c].xv[devvp->v[devvp->c].c].type = DE_DEVICE; + devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.dp->used = 1; + devvp->v[devvp->c].xv[devvp->v[devvp->c].c].size = devvp->v[devvp->c].xv[devvp->v[devvp->c].c].u.dp->len; + } else { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: no extent or device found for `%s'\n", ep->sv.v[devvp->v[devvp->c].c + 2]); + return 0; + } + } + if (devvp->v[devvp->c].raid == 1) { + /* check we have more than 1 device/extent */ + if (devvp->v[devvp->c].c < 2) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: device `%s' is specified as RAID1, but has only %d sub-devices/extents\n", devvp->v[devvp->c].dev, devvp->v[devvp->c].c); + return 0; + } + } + devvp->c += 1; + return 1; +} + +/* find a target by name */ +static disc_target_t * +find_target(targv_t *tvp, char *s) +{ + size_t i; + + for (i = 0 ; i < tvp->c ; i++) { + if (strcmp(tvp->v[i].target, s) == 0) { + return &tvp->v[i]; + } + } + return NULL; +} + +/* allocate space for a new target */ +static int +do_target(conffile_t *cf, targv_t *tvp, devv_t *devvp, extv_t *evp, ent_t *ep) +{ + disc_extent_t *xp; + disc_device_t *dp; + const char *flags; + char tgt[256]; + char *iqn; + int netmaskcol; + int devcol; + + if ((iqn = strchr(ep->sv.v[TARGET_NAME_COL], '=')) == NULL) { + (void) strlcpy(tgt, ep->sv.v[TARGET_NAME_COL], sizeof(tgt)); + } else { + (void) snprintf(tgt, sizeof(tgt), "%.*s", (int)(iqn - ep->sv.v[TARGET_NAME_COL]), ep->sv.v[TARGET_NAME_COL]); + iqn += 1; + } + if (find_target(tvp, tgt) != NULL) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: attempt to re-define target `%s'\n", tgt); + return 0; + } + ALLOC(disc_target_t, tvp->v, tvp->size, tvp->c, 14, 14, "do_target", exit(EXIT_FAILURE)); + if (ep->sv.c == 3) { + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Warning: old 3 field \"targets\" entry, assuming read-only target\n"); + devcol = TARGET_V1_DEVICE_COL; + netmaskcol = TARGET_V1_NETMASK_COL; + flags = DEFAULT_FLAGS; + } else { + devcol = TARGET_V2_DEVICE_COL; + flags = ep->sv.v[TARGET_V2_FLAGS_COL]; + netmaskcol = TARGET_V2_NETMASK_COL; + } + if (iqn != NULL) { + tvp->v[tvp->c].iqn = strdup(iqn); + } + if ((dp = find_device(devvp, ep->sv.v[devcol])) != NULL) { + tvp->v[tvp->c].de.type = DE_DEVICE; + tvp->v[tvp->c].de.u.dp = dp; + tvp->v[tvp->c].target = strdup(tgt); + tvp->v[tvp->c].mask = strdup(ep->sv.v[netmaskcol]); + if (strcmp(flags, "readonly") == 0 || strcmp(flags, "ro") == 0 || strcmp(flags, "r") == 0) { + tvp->v[tvp->c].flags |= TARGET_READONLY; + } + tvp->c += 1; + return 1; + } + if ((xp = find_extent(evp, ep->sv.v[devcol])) != NULL) { + tvp->v[tvp->c].de.type = DE_EXTENT; + tvp->v[tvp->c].de.u.xp = xp; + tvp->v[tvp->c].target = strdup(tgt); + tvp->v[tvp->c].mask = strdup(ep->sv.v[netmaskcol]); + if (strcmp(flags, "readonly") == 0 || strcmp(flags, "ro") == 0 || strcmp(flags, "r") == 0) { + tvp->v[tvp->c].flags |= TARGET_READONLY; + } + tvp->c += 1; + return 1; + } + (void) fprintf(stderr, "%s:%d: ", conffile_get_name(cf), conffile_get_lineno(cf)); + (void) fprintf(stderr, "Error: no device or extent found for `%s'\n", ep->sv.v[devcol]); + return 0; +} + +/* print an extent */ +static void +pextent(disc_extent_t *ep, int indent) +{ + int i; + + for (i = 0 ; i < indent ; i++) { + (void) fputc('\t', stdout); + } + printf("%s:%s:%" PRIu64 ":%" PRIu64 "\n", ep->extent, ep->dev, ep->sacred, ep->len); +} + +static void pdevice(disc_device_t *, int); + +/* print information about an extent or a device */ +static void +pu(disc_de_t *dep, int indent) +{ + switch(dep->type) { + case DE_EXTENT: + pextent(dep->u.xp, indent); + break; + case DE_DEVICE: + pdevice(dep->u.dp, indent); + break; + } +} + +/* print information about a device */ +static void +pdevice(disc_device_t *dp, int indent) +{ + int i; + size_t j; + + for (i = 0 ; i < indent ; i++) { + (void) fputc('\t', stdout); + } + printf("%s:RAID%d\n", dp->dev, dp->raid); + for (j = 0 ; j < dp->c ; j++) { + pu(&dp->xv[j], indent + 1); + } +} + +/* print informnation about a target */ +static void +ptarget(disc_target_t *tp, int indent) +{ + int i; + + for (i = 0 ; i < indent ; i++) { + (void) fputc('\t', stdout); + } + printf("%s:%s:%s\n", tp->target, (tp->flags & TARGET_READONLY) ? "ro" : "rw", tp->mask); + pu(&tp->de, indent + 1); +} + +/* print all information */ +static void +ptargets(targv_t *tvp) +{ + size_t i; + + for (i = 0 ; i < tvp->c ; i++) { + ptarget(&tvp->v[i], 0); + } +} + +/* read a configuration file */ +int +read_conf_file(const char *cf, targv_t *tvp, devv_t *dvp, extv_t *evp) +{ + conffile_t conf; + ent_t e; + + (void) memset(&conf, 0x0, sizeof(conf)); + if (!conffile_open(&conf, cf, "r", " \t", "#")) { + (void) fprintf(stderr, "Error: can't open `%s'\n", cf); + return 0; + } + printf("Reading configuration from `%s'\n", cf); + (void) memset(&e, 0x0, sizeof(e)); + while (conffile_getent(&conf, &e)) { + if (strncmp(e.sv.v[0], "extent", 6) == 0) { + do_extent(&conf, evp, &e); + } else if (strncmp(e.sv.v[0], "device", 6) == 0) { + do_device(&conf, dvp, evp, &e); + } else if (strncmp(e.sv.v[0], "target", 6) == 0 || + strncmp(e.sv.v[0], "lun", 3) == 0) { + do_target(&conf, tvp, dvp, evp, &e); + } + e.sv.c = 0; + } + ptargets(tvp); + (void) conffile_close(&conf); + return 1; +} + +/* write the pid to the pid file */ +void +write_pid_file(const char *f) +{ + FILE *fp; + + if ((fp = fopen(f, "w")) == NULL) { + (void) fprintf(stderr, "Couldn't create pid file \"%s\": %s", f, strerror(errno)); + } else { + fprintf(fp, "%ld\n", (long) getpid()); + fclose(fp); + } +} diff --git a/external/bsd/iscsi/dist/src/strlcpy.c b/external/bsd/iscsi/dist/src/strlcpy.c new file mode 100644 index 000000000000..60f07f71f28a --- /dev/null +++ b/external/bsd/iscsi/dist/src/strlcpy.c @@ -0,0 +1,68 @@ +/* $NetBSD: strlcpy.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ +/* $OpenBSD: strlcpy.c,v 1.7 2003/04/12 21:56:39 millert Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND TODD C. MILLER DISCLAIMS ALL + * WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL TODD C. MILLER BE LIABLE + * FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include "compat.h" + +#include +#include +#include + + +#if !HAVE_STRLCPY +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +#ifdef _LIBC +_strlcpy(dst, src, siz) +#else +strlcpy(dst, src, siz) +#endif + char *dst; + const char *src; + size_t siz; +{ + char *d = dst; + const char *s = src; + size_t n = siz; + + _DIAGASSERT(dst != NULL); + _DIAGASSERT(src != NULL); + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} +#endif diff --git a/external/bsd/iscsi/dist/src/strtoll.c b/external/bsd/iscsi/dist/src/strtoll.c new file mode 100644 index 000000000000..9a3f2385ced1 --- /dev/null +++ b/external/bsd/iscsi/dist/src/strtoll.c @@ -0,0 +1,60 @@ +/* $NetBSD: strtoll.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include "config.h" + +#include + +#include +#include +#include + +#include "compat.h" + +#ifndef HAVE_STRTOLL + +static char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; + +int64_t +strtoll(const char *ptr, const char **endptr, int base) +{ + const char *cp; + int64_t ret; + char *dig; + int d; + + for (ret = 0, cp = ptr ; *cp && (dig = strchr(digits, *cp)) != NULL && (d = (int)(dig - digits)) < base ; cp++) { + ret = (ret * base) + d; + } + if (endptr != NULL) { + *endptr = cp; + } + return ret; +} +#endif /* HAVE_STRTOLL */ diff --git a/external/bsd/iscsi/dist/src/target.c b/external/bsd/iscsi/dist/src/target.c new file mode 100644 index 000000000000..579c55cbc987 --- /dev/null +++ b/external/bsd/iscsi/dist/src/target.c @@ -0,0 +1,1761 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include +#include + +#include + +#ifdef HAVE_NETINET_TCP_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef HAVE_SYSLOG_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_INTTYPES_H +#include +#endif + + +#include "iscsi.h" +#include "target.h" +#include "device.h" +#include "iscsi-md5.h" +#include "parameters.h" + +enum { + TARGET_SHUT_DOWN = 0, + TARGET_INITIALIZING = 1, + TARGET_INITIALIZED = 2, + TARGET_SHUTTING_DOWN = 3 +}; + +/*********** + * Private * + ***********/ + +static target_session_t *g_session; +static iscsi_queue_t g_session_q; +static iscsi_mutex_t g_session_q_mutex; + +/********************* + * Private Functions * + *********************/ + +static char * +get_iqn(target_session_t *sess, uint32_t t, char *buf, size_t size) +{ + if (sess->globals->tv->v[t].iqn != NULL) { + (void) strlcpy(buf, sess->globals->tv->v[t].iqn, size); + return buf; + } + (void) snprintf(buf, size, "%s:%s", sess->globals->targetname, + sess->globals->tv->v[t].target); + return buf; +} + +static int +reject_t(target_session_t * sess, uint8_t *header, uint8_t reason) +{ + iscsi_reject_t reject; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + + iscsi_trace_error(__FILE__, __LINE__, "reject %x\n", reason); + reject.reason = reason; + reject.length = ISCSI_HEADER_LEN; + reject.StatSN = ++(sess->StatSN); + reject.ExpCmdSN = sess->ExpCmdSN; + reject.MaxCmdSN = sess->MaxCmdSN; + reject.DataSN = 0; /* SNACK not yet implemented */ + + if (iscsi_reject_encap(rsp_header, &reject) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_reject_encap() failed\n"); + return -1; + } + if (iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN, + header, ISCSI_HEADER_LEN, 0) != 2 * ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + return -1; + } + return 0; +} + +static int +scsi_command_t(target_session_t *sess, uint8_t *header) +{ + target_cmd_t cmd; + iscsi_scsi_cmd_args_t scsi_cmd; + iscsi_scsi_rsp_t scsi_rsp; + iscsi_read_data_t data; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + uint32_t DataSN = 0; + + (void) memset(&scsi_cmd, 0x0, sizeof(scsi_cmd)); + if (iscsi_scsi_cmd_decap(header, &scsi_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_scsi_cmd_decap() failed\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: SCSI Command (CmdSN %u, op %#x)\n", sess->id, scsi_cmd.CmdSN, scsi_cmd.cdb[0]); + + /* For Non-immediate commands, the CmdSN should be between ExpCmdSN */ + /* and MaxCmdSN, inclusive of both. Otherwise, ignore the command */ + if ((!scsi_cmd.immediate) && + ((scsi_cmd.CmdSN < sess->ExpCmdSN) || (scsi_cmd.CmdSN > sess->MaxCmdSN))) { + iscsi_trace_error(__FILE__, __LINE__, "CmdSN(%d) of SCSI Command not valid, ExpCmdSN(%d) MaxCmdSN(%d). Ignoring the command\n", scsi_cmd.CmdSN, sess->ExpCmdSN, sess->MaxCmdSN); + return 0; + } + /* Arg check. */ + scsi_cmd.attr = 0; /* Temp fix FIXME */ + /* + * RETURN_NOT_EQUAL("ATTR (FIX ME)", scsi_cmd.attr, 0, NO_CLEANUP, + * -1); + */ + + /* Check Numbering */ + + if (scsi_cmd.CmdSN != sess->ExpCmdSN) { + iscsi_trace_warning(__FILE__, __LINE__, "Expected CmdSN %d, got %d. (ignoring and resetting expectations)\n", + sess->ExpCmdSN, scsi_cmd.CmdSN); + sess->ExpCmdSN = scsi_cmd.CmdSN; + } + /* Check Transfer Lengths */ + if (sess->sess_params.first_burst_length + && (scsi_cmd.length > sess->sess_params.first_burst_length)) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_cmd.length (%u) > FirstBurstLength (%u)\n", + scsi_cmd.length, sess->sess_params.first_burst_length); + scsi_cmd.status = 0x02; + scsi_cmd.length = 0; + goto response; + } + if (sess->sess_params.max_data_seg_length + && (scsi_cmd.length > sess->sess_params.max_data_seg_length)) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_cmd.length (%u) > MaxRecvDataSegmentLength (%u)\n", + scsi_cmd.length, sess->sess_params.max_data_seg_length); + return -1; + } + +#if 0 + /* commented out in original Intel reference code */ + if (scsi_cmd.final && scsi_cmd.output) { + RETURN_NOT_EQUAL("Length", scsi_cmd.length, scsi_cmd.trans_len, NO_CLEANUP, -1); + } +#endif + + /* Read AHS. Need to optimize/clean this. */ + /* We should not be calling malloc(). */ + /* We need to check for properly formated AHS segments. */ + + if (scsi_cmd.ahs_len) { + uint32_t ahs_len; + uint8_t *ahs_ptr; + uint8_t ahs_type; + + scsi_cmd.ahs = NULL; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %u bytes AHS\n", scsi_cmd.ahs_len); + if ((scsi_cmd.ahs = iscsi_malloc_atomic((unsigned)scsi_cmd.ahs_len)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } +#define AHS_CLEANUP do { \ + if (scsi_cmd.ahs != NULL) { \ + iscsi_free_atomic(scsi_cmd.ahs); \ + } \ +} while (/* CONSTCOND */ 0) + if (iscsi_sock_msg(sess->sock, 0, (unsigned)scsi_cmd.ahs_len, scsi_cmd.ahs, 0) != scsi_cmd.ahs_len) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + AHS_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "read %u bytes AHS\n", scsi_cmd.ahs_len); + for (ahs_ptr = scsi_cmd.ahs; ahs_ptr < (scsi_cmd.ahs + scsi_cmd.ahs_len - 1) ; ahs_ptr += ahs_len) { + ahs_len = ISCSI_NTOHS(*((uint16_t *) (void *)ahs_ptr)); + RETURN_EQUAL("AHS Length", ahs_len, 0, AHS_CLEANUP, -1); + switch (ahs_type = *(ahs_ptr + 2)) { + case ISCSI_AHS_EXTENDED_CDB: + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Got ExtendedCDB AHS (%u bytes extra CDB)\n", ahs_len - 1); + scsi_cmd.ext_cdb = ahs_ptr + 4; + break; + case ISCSI_AHS_BIDI_READ: + scsi_cmd.bidi_trans_len = ISCSI_NTOHL(*((uint32_t *) (void *) (ahs_ptr + 4))); + *((uint32_t *) (void *) (ahs_ptr + 4)) = scsi_cmd.bidi_trans_len; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Got Bidirectional Read AHS (expected read length %u)\n", scsi_cmd.bidi_trans_len); + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "unknown AHS type %x\n", ahs_type); + AHS_CLEANUP; + return -1; + } + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "done parsing %u bytes AHS\n", scsi_cmd.ahs_len); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "no AHS to read\n"); + scsi_cmd.ahs = NULL; + } + + sess->ExpCmdSN++; + sess->MaxCmdSN++; + + /* Execute cdb. device_command() will set scsi_cmd.input if */ + /* there is input data and set the length of the input */ + /* to either scsi_cmd.trans_len or scsi_cmd.bidi_trans_len, depending */ + /* on whether scsi_cmd.output was set. */ + + if (scsi_cmd.input) { + scsi_cmd.send_data = sess->buff; + } + scsi_cmd.input = 0; + cmd.scsi_cmd = &scsi_cmd; + cmd.callback = NULL; + if (device_command(sess, &cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "device_command() failed\n"); + AHS_CLEANUP; + return -1; + } + /* Send any input data */ + + scsi_cmd.bytes_sent = 0; + if (!scsi_cmd.status && scsi_cmd.input) { + struct iovec sg_singleton; + struct iovec *sg, *sg_orig, *sg_new = NULL; + int sg_len_orig, sg_len; + uint32_t offset, trans_len; + int fragment_flag = 0; + int offset_inc; +#define SG_CLEANUP do { \ + if (fragment_flag) { \ + iscsi_free_atomic(sg_new); \ + } \ +} while (/* CONSTCOND */ 0) + if (scsi_cmd.output) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending %u bytes bi-directional input data\n", scsi_cmd.bidi_trans_len); + trans_len = scsi_cmd.bidi_trans_len; + } else { + trans_len = scsi_cmd.trans_len; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending %u bytes input data as separate PDUs\n", trans_len); + + if (scsi_cmd.send_sg_len) { + sg_orig = (struct iovec *) (void *) scsi_cmd.send_data; + sg_len_orig = scsi_cmd.send_sg_len; + } else { + sg_len_orig = 1; + sg_singleton.iov_base = scsi_cmd.send_data; + sg_singleton.iov_len = trans_len; + sg_orig = &sg_singleton; + } + sg = sg_orig; + sg_len = sg_len_orig; + + offset_inc = (sess->sess_params.max_data_seg_length) ? sess->sess_params.max_data_seg_length : trans_len; + + for (offset = 0; offset < trans_len; offset += offset_inc) { + (void) memset(&data, 0x0, sizeof(data)); + + data.length = (sess->sess_params.max_data_seg_length) ? MIN(trans_len - offset, sess->sess_params.max_data_seg_length) : trans_len - offset; + if (data.length != trans_len) { + if (!fragment_flag) { + if ((sg_new = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len_orig)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + AHS_CLEANUP; + return -1; + } + fragment_flag++; + } + sg = sg_new; + sg_len = sg_len_orig; + (void) memcpy(sg, sg_orig, sizeof(struct iovec) * sg_len_orig); + if (modify_iov(&sg, &sg_len, offset, data.length) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + SG_CLEANUP; + AHS_CLEANUP; + return -1; + } + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending read data PDU (offset %u, len %u)\n", offset, data.length); + if (offset + data.length == trans_len) { + data.final = 1; + + if (sess->UsePhaseCollapsedRead) { + data.status = 1; + data.status = scsi_cmd.status; + data.StatSN = ++(sess->StatSN); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "status %#x collapsed into last data PDU\n", data.status); + } else { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "NOT collapsing status with last data PDU\n"); + } + } else if (offset + data.length > trans_len) { + iscsi_trace_error(__FILE__, __LINE__, "offset+data.length > trans_len??\n"); + SG_CLEANUP; + AHS_CLEANUP; + return -1; + } + data.task_tag = scsi_cmd.tag; + data.ExpCmdSN = sess->ExpCmdSN; + data.MaxCmdSN = sess->MaxCmdSN; + data.DataSN = DataSN++; + data.offset = offset; + if (iscsi_read_data_encap(rsp_header, &data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_read_data_encap() failed\n"); + SG_CLEANUP; + AHS_CLEANUP; + return -1; + } + if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN, sg, data.length, sg_len) + != ISCSI_HEADER_LEN + data.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + SG_CLEANUP; + AHS_CLEANUP; + return -1; + } + scsi_cmd.bytes_sent += data.length; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sent read data PDU ok (offset %u, len %u)\n", data.offset, data.length); + } + SG_CLEANUP; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully sent %u bytes read data\n", trans_len); + } + /* + * Send a response PDU if + * + * 1) we're not using phase collapsed input (and status was good) + * 2) we are using phase collapsed input, but there was no input data (e.g., TEST UNIT READY) + * 3) command had non-zero status and possible sense data + */ +response: + if (!sess->UsePhaseCollapsedRead || !scsi_cmd.length || scsi_cmd.status) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending SCSI response PDU\n"); + (void) memset(&scsi_rsp, 0x0, sizeof(scsi_rsp)); + scsi_rsp.length = scsi_cmd.status ? scsi_cmd.length : 0; + scsi_rsp.tag = scsi_cmd.tag; + /* If r2t send, then the StatSN is already incremented */ + if (sess->StatSN < scsi_cmd.ExpStatSN) { + ++sess->StatSN; + } + scsi_rsp.StatSN = sess->StatSN; + scsi_rsp.ExpCmdSN = sess->ExpCmdSN; + scsi_rsp.MaxCmdSN = sess->MaxCmdSN; + scsi_rsp.ExpDataSN = (!scsi_cmd.status && scsi_cmd.input) ? DataSN : 0; + scsi_rsp.response = 0x00; /* iSCSI response */ + scsi_rsp.status = scsi_cmd.status; /* SCSI status */ + if (iscsi_scsi_rsp_encap(rsp_header, &scsi_rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_scsi_rsp_encap() failed\n"); + AHS_CLEANUP; + return -1; + } + if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN, + scsi_cmd.send_data, scsi_rsp.length, scsi_cmd.send_sg_len) + != ISCSI_HEADER_LEN + scsi_rsp.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + AHS_CLEANUP; + return -1; + } + /* Make sure all data was transferred */ + + if (scsi_cmd.output) { + RETURN_NOT_EQUAL("scsi_cmd.bytes_recv", scsi_cmd.bytes_recv, scsi_cmd.trans_len, AHS_CLEANUP, -1); + if (scsi_cmd.input) { + RETURN_NOT_EQUAL("scsi_cmd.bytes_sent", scsi_cmd.bytes_sent, scsi_cmd.bidi_trans_len, AHS_CLEANUP, -1); + } + } else { + if (scsi_cmd.input) { + RETURN_NOT_EQUAL("scsi_cmd.bytes_sent", scsi_cmd.bytes_sent, scsi_cmd.trans_len, AHS_CLEANUP, -1); + } + } + } + /* Device callback after command has completed */ + + if (cmd.callback) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "issuing device callback\n"); + if ((*cmd.callback)(cmd.callback_arg) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "device callback failed\n"); + AHS_CLEANUP; + return -1; + } + } + AHS_CLEANUP; + return 0; +} + +static int +task_command_t(target_session_t * sess, uint8_t *header) +{ + iscsi_task_cmd_t cmd; + iscsi_task_rsp_t rsp; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + + /* Get & check args */ + + if (iscsi_task_cmd_decap(header, &cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_task_cmd_decap() failed\n"); + return -1; + } + if (cmd.CmdSN != sess->ExpCmdSN) { + iscsi_trace_warning(__FILE__, __LINE__, "Expected CmdSN %d, got %d. (ignoring and resetting expectations)\n", + cmd.CmdSN, sess->ExpCmdSN); + sess->ExpCmdSN = cmd.CmdSN; + } + sess->MaxCmdSN++; + + (void) memset(&rsp, 0x0, sizeof(rsp)); + rsp.response = ISCSI_TASK_RSP_FUNCTION_COMPLETE; + + switch (cmd.function) { + case ISCSI_TASK_CMD_ABORT_TASK: + printf("ISCSI_TASK_CMD_ABORT_TASK\n"); + break; + case ISCSI_TASK_CMD_ABORT_TASK_SET: + printf("ISCSI_TASK_CMD_ABORT_TASK_SET\n"); + break; + case ISCSI_TASK_CMD_CLEAR_ACA: + printf("ISCSI_TASK_CMD_CLEAR_ACA\n"); + break; + case ISCSI_TASK_CMD_CLEAR_TASK_SET: + printf("ISCSI_TASK_CMD_CLEAR_TASK_SET\n"); + break; + case ISCSI_TASK_CMD_LOGICAL_UNIT_RESET: + printf("ISCSI_TASK_CMD_LOGICAL_UNIT_RESET\n"); + break; + case ISCSI_TASK_CMD_TARGET_WARM_RESET: + printf("ISCSI_TASK_CMD_TARGET_WARM_RESET\n"); + break; + case ISCSI_TASK_CMD_TARGET_COLD_RESET: + printf("ISCSI_TASK_CMD_TARGET_COLD_RESET\n"); + break; + case ISCSI_TASK_CMD_TARGET_REASSIGN: + printf("ISCSI_TASK_CMD_TARGET_REASSIGN\n"); + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "Unknown task function %d\n", cmd.function); + rsp.response = ISCSI_TASK_RSP_REJECTED; + } + + rsp.tag = cmd.tag; + rsp.StatSN = ++(sess->StatSN); + rsp.ExpCmdSN = sess->ExpCmdSN; + rsp.MaxCmdSN = sess->MaxCmdSN; + + if (iscsi_task_rsp_encap(rsp_header, &rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_task_cmd_decap() failed\n"); + return -1; + } + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + + } + return 0; +} + +static int +nop_out_t(target_session_t * sess, uint8_t *header) +{ + iscsi_nop_out_args_t nop_out; + char *ping_data = NULL; + + if (iscsi_nop_out_decap(header, &nop_out) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_nop_out_decap() failed\n"); + return -1; + } + if (nop_out.CmdSN != sess->ExpCmdSN) { + iscsi_trace_warning(__FILE__, __LINE__, "Expected CmdSN %d, got %d. (ignoring and resetting expectations)\n", + nop_out.CmdSN, sess->ExpCmdSN); + sess->ExpCmdSN = nop_out.CmdSN; + } + /* TODO Clarify whether we need to update the CmdSN */ + /* sess->ExpCmdSN++; */ + /* sess->MaxCmdSN++; */ + + if (nop_out.length) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %u bytes ping data\n", nop_out.length); + if ((ping_data = iscsi_malloc(nop_out.length)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + if ((uint32_t)iscsi_sock_msg(sess->sock, 0, nop_out.length, ping_data, 0) != nop_out.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + if (ping_data) { + iscsi_free(ping_data); + } + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully read %u bytes ping data:\n", nop_out.length); + iscsi_print_buffer(ping_data, nop_out.length); + } + if (nop_out.tag != 0xffffffff) { + iscsi_nop_in_args_t nop_in; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending %u bytes ping response\n", nop_out.length); + (void) memset(&nop_in, 0x0, sizeof(nop_in)); + nop_in.length = nop_out.length; + nop_in.lun = nop_out.lun; + nop_in.tag = nop_out.tag; + nop_in.transfer_tag = 0xffffffff; + nop_in.StatSN = ++(sess->StatSN); + nop_in.ExpCmdSN = sess->ExpCmdSN; + nop_in.MaxCmdSN = sess->MaxCmdSN; + + if (iscsi_nop_in_encap(rsp_header, &nop_in) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_nop_in_encap() failed\n"); + if (ping_data) { + iscsi_free(ping_data); + } + return -1; + } + if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN, + ping_data, nop_in.length, 0) != ISCSI_HEADER_LEN + nop_in.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + if (ping_data) { + iscsi_free(ping_data); + } + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully sent %u bytes ping response\n", nop_out.length); + } + if (ping_data) { + iscsi_free(ping_data); + } + return 0; +} + +/* + * text_command_t + */ + +static int +text_command_t(target_session_t * sess, uint8_t *header) +{ + iscsi_text_cmd_args_t text_cmd; + iscsi_text_rsp_args_t text_rsp; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + char *text_in = NULL; + char *text_out = NULL; + unsigned len_in; + char buf[BUFSIZ]; + int len_out = 0; + uint32_t i; + +#define TC_CLEANUP do { \ + if (text_in != NULL) { \ + iscsi_free_atomic(text_in); \ + } \ + if (text_out != NULL) { \ + iscsi_free_atomic(text_out); \ + } \ +} while (/* CONSTCOND */ 0) +#define TC_ERROR { \ + TC_CLEANUP; \ + return -1; \ +} + /* Get text args */ + + if (iscsi_text_cmd_decap(header, &text_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_text_cmd_decap() failed\n"); + return -1; + } + /* Check args & update numbering */ + RETURN_NOT_EQUAL("Continue", text_cmd.cont, 0, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("CmdSN", text_cmd.CmdSN, sess->ExpCmdSN, NO_CLEANUP, -1); + + sess->ExpCmdSN++; + sess->MaxCmdSN++; + + if ((text_out = iscsi_malloc_atomic(2048)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + /* Read text parameters */ + + if ((len_in = text_cmd.length) != 0) { + iscsi_parameter_t *ptr; + + if ((text_in = iscsi_malloc_atomic(len_in + 1)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + TC_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %u bytes text parameters\n", len_in); + if ((unsigned)iscsi_sock_msg(sess->sock, 0, len_in, text_in, 0) != len_in) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TC_CLEANUP; + return -1; + } + text_in[len_in] = 0x0; + PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred, text_in, (int) len_in, text_out, (int *)(void *)&len_out, 2048, 0, TC_ERROR); + + /* + * Handle exceptional cases not covered by parameters.c + * (e.g., SendTargets) + */ + + if ((ptr = param_get(sess->params, "SendTargets")) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "param_get() failed\n"); + TC_CLEANUP; + return -1; + } + if (ptr->rx_offer) { + if (ptr->offer_rx && strcmp(ptr->offer_rx, "All") == 0 && !param_equiv(sess->params, "SessionType", "Discovery")) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Rejecting SendTargets=All in a non Discovery session\n"); + PARAM_TEXT_ADD(sess->params, "SendTargets", "Reject", text_out, &len_out, 2048, 0, TC_ERROR); + } else { + for (i = 0 ; i < sess->globals->tv->c ; i++) { + if (sess->address_family == ISCSI_IPv6 || + (sess->address_family == ISCSI_IPv4 && allow_netmask(sess->globals->tv->v[i].mask, sess->initiator))) { + (void) get_iqn(sess, i, buf, sizeof(buf)); + PARAM_TEXT_ADD(sess->params, "TargetName", buf, text_out, &len_out, 2048, 0, TC_ERROR); + PARAM_TEXT_ADD(sess->params, "TargetAddress", sess->globals->targetaddress, text_out, &len_out, 2048, 0, TC_ERROR); + } else { +#ifdef HAVE_SYSLOG_H + syslog(LOG_INFO, "WARNING: attempt to discover targets from %s (not allowed by %s) has been rejected", sess->initiator, sess->globals->tv->v[0].mask); +#endif + } + } + } + ptr->rx_offer = 0; + } + /* Parse outgoing offer */ + + if (len_out) { + PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred, text_out, len_out, NULL, NULL, 2048, 1, TC_ERROR); + } + } + if (sess->IsFullFeature) { + set_session_parameters(sess->params, &sess->sess_params); + } + /* Send response */ + + text_rsp.final = text_cmd.final; + text_rsp.cont = 0; + text_rsp.length = len_out; + text_rsp.lun = text_cmd.lun; + text_rsp.tag = text_cmd.tag; + text_rsp.transfer_tag = (text_rsp.final) ? 0xffffffff : 0x1234; + text_rsp.StatSN = ++(sess->StatSN); + text_rsp.ExpCmdSN = sess->ExpCmdSN; + text_rsp.MaxCmdSN = sess->MaxCmdSN; + if (iscsi_text_rsp_encap(rsp_header, &text_rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_text_rsp_encap() failed\n"); + TC_CLEANUP; + return -1; + } + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TC_CLEANUP; + return -1; + } + if (len_out) { + if (iscsi_sock_msg(sess->sock, 1, (unsigned) len_out, text_out, 0) != len_out) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TC_CLEANUP; + return -1; + } + } + TC_CLEANUP; + return 0; +} + +/* given a target's iqn, find the relevant target that we're exporting */ +int +find_target_iqn(target_session_t *sess) +{ + char buf[BUFSIZ]; + uint32_t i; + + for (i = 0 ; i < sess->globals->tv->c ; i++) { + if (param_equiv(sess->params, "TargetName", + get_iqn(sess, i, buf, sizeof(buf)))) { + return sess->d = i; + } + } + return -1; +} + +/* given a tsih, find the relevant target that we're exporting */ +int +find_target_tsih(globals_t *globals, int tsih) +{ + uint32_t i; + + for (i = 0 ; i < globals->tv->c ; i++) { + if (globals->tv->v[i].tsih == tsih) { + return i; + } + } + return -1; +} + +/* + * login_command_t() handles login requests and replies. + */ + +static int +login_command_t(target_session_t * sess, uint8_t *header) +{ + iscsi_login_cmd_args_t cmd; + iscsi_login_rsp_args_t rsp; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + char *text_in = NULL; + char *text_out = NULL; + char logbuf[BUFSIZ]; + int len_in = 0; + int len_out = 0; + int status = 0; + int i; + + /* Initialize response */ + +#define LC_CLEANUP do { \ + if (text_in != NULL) { \ + iscsi_free_atomic(text_in); \ + } \ + if (text_out != NULL) { \ + iscsi_free_atomic(text_out); \ + } \ +} while (/* CONSTCOND */ 0) +#define LC_ERROR { \ + TC_CLEANUP; \ + return -1; \ +} + + (void) memset(&rsp, 0x0, sizeof(rsp)); + rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR; + + /* Get login args & check preconditions */ + + if (iscsi_login_cmd_decap(header, &cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_login_cmd_decap() failed\n"); + goto response; + } + if (sess->IsLoggedIn) { + iscsi_trace_error(__FILE__, __LINE__, "duplicate login attempt on sess %d\n", sess->id); + goto response; + } + if ((cmd.cont != 0) && (cmd.transit != 0)) { + iscsi_trace_error(__FILE__, __LINE__, "Bad cmd.continue. Expected 0.\n"); + goto response; + } else if ((cmd.version_max < ISCSI_VERSION) || (cmd.version_min > ISCSI_VERSION)) { + iscsi_trace_error(__FILE__, __LINE__, "Target iscsi version (%u) not supported by initiator [Max Ver (%u) and Min Ver (%u)]\n", ISCSI_VERSION, cmd.version_max, cmd.version_min); + rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR; + rsp.status_detail = ISCSI_LOGIN_DETAIL_VERSION_NOT_SUPPORTED; + rsp.version_max = ISCSI_VERSION; + rsp.version_active = ISCSI_VERSION; + goto response; + } else if (cmd.tsih != 0) { + iscsi_trace_error(__FILE__, __LINE__, "Bad cmd.tsih (%u). Expected 0.\n", cmd.tsih); + goto response; + } + /* Parse text parameters and build response */ + + if ((text_out = iscsi_malloc_atomic(2048)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + if ((len_in = cmd.length) != 0) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading %d bytes text data\n", len_in); + if ((text_in = iscsi_malloc_atomic((unsigned)(len_in + 1))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + LC_CLEANUP; + return -1; + } + if (iscsi_sock_msg(sess->sock, 0, (unsigned) len_in, text_in, 0) != len_in) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + LC_CLEANUP; + return -1; + } + text_in[len_in] = 0x0; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully read %d bytes text data\n", len_in); + + /* + * Parse incoming parameters (text_out will contain the + * response we need + */ + + /* to send back to the initiator */ + + + if ((status = param_text_parse(sess->params, &sess->sess_params.cred, text_in, len_in, text_out, &len_out, 2048, 0)) != 0) { + switch (status) { + case ISCSI_PARAM_STATUS_FAILED: + rsp.status_detail = ISCSI_LOGIN_DETAIL_SUCCESS; + break; + case ISCSI_PARAM_STATUS_AUTH_FAILED: + rsp.status_detail = ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE; + break; + default: + /* + * We will need to set the detail field based on more detailed error + * cases. Will need to fix this if compliciance test break + * (status_detail field). + */ + break; + } + goto response; + } + /* Parse the outgoing offer */ + if (!sess->LoginStarted) { + PARAM_TEXT_ADD(sess->params, "TargetPortalGroupTag", "1", text_out, &len_out, 2048, 0, LC_ERROR); + } + if (len_out) { + PARAM_TEXT_PARSE(sess->params, &sess->sess_params.cred, text_out, len_out, NULL, NULL, 2048, 1, LC_ERROR; + ); + } + } + if (!sess->LoginStarted) { + sess->LoginStarted = 1; + } + /* + * For now, we accept what ever the initiators' current and next + * states are. And le are always + */ + /* ready to transitition to that state. */ + + rsp.csg = cmd.csg; + rsp.nsg = cmd.nsg; + rsp.transit = cmd.transit; + + if (cmd.csg == ISCSI_LOGIN_STAGE_SECURITY) { + if (param_equiv(sess->params, "AuthResult", "No")) { + rsp.transit = 0; + } else if (param_equiv(sess->params, "AuthResult", "Fail")) { + rsp.status_class = rsp.status_detail = ISCSI_LOGIN_DETAIL_INIT_AUTH_FAILURE; + goto response; + } + } + if (cmd.transit && cmd.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE) { + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "transitioning to ISCSI_LOGIN_STAGE_FULL_FEATURE\n"); + + /* Check post conditions */ + + if (param_equiv(sess->params, "InitiatorName", "")) { + iscsi_trace_error(__FILE__, __LINE__, "InitiatorName not specified\n"); + goto response; + } + if (param_equiv(sess->params, "SessionType", "Normal")) { + if (param_equiv(sess->params, "TargetName", "")) { + iscsi_trace_error(__FILE__, __LINE__, "TargetName not specified\n"); + goto response; + } + if ((i = find_target_iqn(sess)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "Bad TargetName \"%s\"\n", param_val(sess->params, "TargetName")); + goto response; + } + if (cmd.tsih != 0 && find_target_tsih(sess->globals, cmd.tsih) != i) { + iscsi_trace_error(__FILE__, __LINE__, "target tsih expected %d, cmd.tsih %d, i %d\n", sess->globals->tv->v[i].tsih, cmd.tsih, i); + } + sess->d = i; + } else if ((i = find_target_tsih(sess->globals, cmd.tsih)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "Abnormal SessionType cmd.tsih %d not found\n", cmd.tsih); + i = sess->d; + } + if (param_equiv(sess->params, "SessionType", "")) { + iscsi_trace_error(__FILE__, __LINE__, "SessionType not specified\n"); + goto response; + } + sess->ExpCmdSN = sess->MaxCmdSN = cmd.CmdSN; + sess->cid = cmd.cid; + sess->isid = cmd.isid; + + sess->globals->tv->v[i].tsih = sess->tsih = ++sess->globals->last_tsih; + sess->IsFullFeature = 1; + + sess->IsLoggedIn = 1; + if (!param_equiv(sess->params, "SessionType", "Discovery")) { + (void) strlcpy(param_val(sess->params, "MaxConnections"), "1", 2); + } + set_session_parameters(sess->params, &sess->sess_params); + } else { + if ((i = find_target_tsih(sess->globals, cmd.tsih)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "cmd.tsih %d not found\n", cmd.tsih); + } + } + + /* No errors */ + + rsp.status_class = rsp.status_detail = ISCSI_LOGIN_DETAIL_SUCCESS; + rsp.length = len_out; + + /* Send login response */ + +response: + sess->ExpCmdSN = sess->MaxCmdSN = cmd.CmdSN; + rsp.isid = cmd.isid; + rsp.StatSN = cmd.ExpStatSN; /* debug */ + rsp.tag = cmd.tag; + rsp.cont = cmd.cont; + rsp.ExpCmdSN = sess->ExpCmdSN; + rsp.MaxCmdSN = sess->MaxCmdSN; + if (!rsp.status_class) { + if (rsp.transit && (rsp.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE)) { + rsp.version_max = ISCSI_VERSION; + rsp.version_active = ISCSI_VERSION; + rsp.StatSN = ++(sess->StatSN); + rsp.tsih = sess->tsih; + } + } + if (iscsi_login_rsp_encap(rsp_header, &rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_login_rsp_encap() failed\n"); + LC_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending login response\n"); + if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, ISCSI_HEADER_LEN, + text_out, rsp.length, 0) != ISCSI_HEADER_LEN + rsp.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + LC_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sent login response ok\n"); + if (rsp.status_class != 0) { + LC_CLEANUP; + return -1; + } + if (cmd.transit && cmd.nsg == ISCSI_LOGIN_STAGE_FULL_FEATURE) { + + /* log information to stdout */ + (void) snprintf(logbuf, sizeof(logbuf), + "> iSCSI %s login successful from %s on %s disk %d, ISID %" PRIu64 ", TSIH %u", + param_val(sess->params, "SessionType"), + param_val(sess->params, "InitiatorName"), + sess->initiator, + sess->d, + sess->isid, + sess->tsih); + printf("%s\n", logbuf); +#ifdef HAVE_SYSLOG_H + /* log information to syslog */ + syslog(LOG_INFO, "%s", logbuf); +#endif + + /* Buffer for data xfers to/from the scsi device */ + if (!param_equiv(sess->params, "MaxRecvDataSegmentLength", "0")) { + if ((sess->buff = iscsi_malloc((unsigned)(param_atoi(sess->params, "MaxRecvDataSegmentLength")))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + LC_CLEANUP; + return -1; + } + } else { + iscsi_trace_error(__FILE__, __LINE__, "MaxRecvDataSegmentLength of 0 not supported\n"); + LC_CLEANUP; + return -1; + } + } + LC_CLEANUP; + return 0; +} + +static int +logout_command_t(target_session_t * sess, uint8_t *header) +{ + iscsi_logout_cmd_args_t cmd; + iscsi_logout_rsp_args_t rsp; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + char logbuf[BUFSIZ]; + int i; + + (void) memset(&rsp, 0x0, sizeof(rsp)); + if (iscsi_logout_cmd_decap(header, &cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_logout_cmd_decap() failed\n"); + return -1; + } + sess->StatSN = cmd.ExpStatSN; + if ((cmd.reason == ISCSI_LOGOUT_CLOSE_RECOVERY) && (param_equiv(sess->params, "ErrorRecoveryLevel", "0"))) { + rsp.response = ISCSI_LOGOUT_STATUS_NO_RECOVERY; + } + RETURN_NOT_EQUAL("CmdSN", cmd.CmdSN, sess->ExpCmdSN, NO_CLEANUP, -1); + RETURN_NOT_EQUAL("ExpStatSN", cmd.ExpStatSN, sess->StatSN, NO_CLEANUP, -1); + + rsp.tag = cmd.tag; + rsp.StatSN = sess->StatSN; + rsp.ExpCmdSN = ++sess->ExpCmdSN; + rsp.MaxCmdSN = sess->MaxCmdSN; + if (iscsi_logout_rsp_encap(rsp_header, &rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_logout_rsp_encap() failed\n"); + return -1; + } + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, rsp_header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sent logout response OK\n"); + + /* log information to stdout */ + (void) snprintf(logbuf, sizeof(logbuf), + "< iSCSI %s logout successful from %s on %s disk %d, ISID %" PRIu64 ", TSIH %u", + param_val(sess->params, "SessionType"), + param_val(sess->params, "InitiatorName"), + sess->initiator, + sess->d, + sess->isid, + sess->tsih); + printf("%s\n", logbuf); +#ifdef HAVE_SYSLOG + /* log information to syslog */ + syslog(LOG_INFO, "%s", logbuf); +#endif + + sess->IsLoggedIn = 0; + + if (sess->sess_params.cred.user) { + free(sess->sess_params.cred.user); + sess->sess_params.cred.user = NULL; + } + + if ((i = find_target_tsih(sess->globals, sess->tsih)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "logout sess->tsih %d not found\n", sess->tsih); + } else { + sess->globals->tv->v[i].tsih = 0; + } + sess->tsih = 0; + + return 0; +} + +static int +verify_cmd_t(target_session_t * sess, uint8_t *header) +{ + int op = ISCSI_OPCODE(header); + + if ((!sess->LoginStarted) && (op != ISCSI_LOGIN_CMD)) { + /* Terminate the connection */ + iscsi_trace_error(__FILE__, __LINE__, "session %d: iSCSI op %#x attempted before LOGIN PHASE\n", + sess->id, op); + return -1; + } + if (!sess->IsFullFeature && ((op != ISCSI_LOGIN_CMD) && (op != ISCSI_LOGOUT_CMD))) { + iscsi_login_rsp_args_t rsp; + uint8_t rsp_header[ISCSI_HEADER_LEN]; + iscsi_trace_error(__FILE__, __LINE__, "session %d: iSCSI op %#x attempted before FULL FEATURE\n", + sess->id, op); + /* Create Login Reject response */ + (void) memset(&rsp, 0x0, sizeof(rsp)); + rsp.status_class = ISCSI_LOGIN_STATUS_INITIATOR_ERROR; + rsp.status_detail = ISCSI_LOGIN_DETAIL_NOT_LOGGED_IN; + rsp.version_max = ISCSI_VERSION; + rsp.version_active = ISCSI_VERSION; + + if (iscsi_login_rsp_encap(rsp_header, &rsp) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_login_rsp_encap() failed\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending login response\n"); + if ((uint32_t)iscsi_sock_send_header_and_data(sess->sock, rsp_header, + ISCSI_HEADER_LEN, NULL, 0, 0) != ISCSI_HEADER_LEN + + rsp.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_send_header_and_data() failed\n"); + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sent login response ok\n"); + return -1; + } + return 0; +} + +/* + * this function looks at the opcode in the received header for the session, + * and does a switch on the opcode to call the required function. + */ +static int +execute_t(target_session_t *sess, uint8_t *header) +{ + int op = ISCSI_OPCODE(header); + + if (verify_cmd_t(sess, header) != 0) { + return -1; + } + switch (op) { + case ISCSI_TASK_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "session %d: Task Command\n", sess->id); + if (task_command_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "task_command_t() failed\n"); + return -1; + } + break; + + case ISCSI_NOP_OUT: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "session %d: NOP-Out\n", sess->id); + if (nop_out_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_out_t() failed\n"); + return -1; + } + break; + + case ISCSI_LOGIN_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "session %d: Login Command\n", sess->id); + if (login_command_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "login_command_t() failed\n"); + return -1; + } + break; + + case ISCSI_TEXT_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "session %d: Text Command\n", sess->id); + if (text_command_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "text_command_t() failed\n"); + return -1; + } + break; + + case ISCSI_LOGOUT_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "session %d: Logout Command\n", sess->id); + if (logout_command_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "logout_command_t() failed\n"); + return -1; + } + break; + + case ISCSI_SCSI_CMD: + iscsi_trace(TRACE_ISCSI_CMD, __FILE__, __LINE__, "session %d: SCSI Command\n", sess->id); + if (scsi_command_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_command_t() failed\n"); + return -1; + } + break; + + default: + iscsi_trace_error(__FILE__, __LINE__, "Unknown Opcode %#x\n", ISCSI_OPCODE(header)); + if (reject_t(sess, header, 0x04) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "reject_t() failed\n"); + return -1; + } + break; + } + return 0; +} + +/* + * Currently one thread per session, used for both Rx and Tx. + */ + +static int +worker_proc_t(void *arg) +{ + target_session_t *sess = (target_session_t *) arg; + uint8_t header[ISCSI_HEADER_LEN]; + iscsi_parameter_t **l = &sess->params; + + ISCSI_THREAD_START("worker_thread"); + sess->worker.pid = ISCSI_GETPID; + sess->worker.state |= ISCSI_WORKER_STATE_STARTED; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: started\n", sess->id); + + /* + * ISCSI_PARAM_TYPE_LIST format: + * ISCSI_PARAM_TYPE_BINARY format: + * ISCSI_PARAM_TYPE_NUMERICAL format: + * ISCSI_PARAM_TYPE_DECLARATIVE format: "" + */ + + sess->params = NULL; + l = &sess->params; + + /* CHAP Parameters */ + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthMethod", "CHAP", "CHAP,None", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "CHAP_A", "None", "5", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_N", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_R", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_I", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "CHAP_C", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetPortalGroupTag", "1", "1", return -1); + /* CHAP Parameters */ + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "HeaderDigest", "None", "None", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "DataDigest", "None", "None", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxConnections", "1", "1", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SendTargets", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetName", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorName", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAlias", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "InitiatorAlias", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "TargetAddress", "", "", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "InitialR2T", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "OFMarker", "No", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "IFMarker", "No", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "OFMarkInt", "1", "65536", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "IFMarkInt", "1", "65536", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_AND, "ImmediateData", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxRecvDataSegmentLength", "8192", "16777215", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "MaxBurstLength", "262144", "16777215", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL_Z, "FirstBurstLength", "65536", "16777215", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Wait", "2", "2", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "DefaultTime2Retain", "20", "20", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "MaxOutstandingR2T", "1", "1", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataPDUInOrder", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_BINARY_OR, "DataSequenceInOrder", "Yes", "Yes,No", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_NUMERICAL, "ErrorRecoveryLevel", "0", "0", return -1); + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_DECLARATIVE, "SessionType", "Normal", "Normal,Discovery", return -1); + /* + * Auth Result is not in specs, we use this key to pass + * authentication result + */ + PARAM_LIST_ADD(l, ISCSI_PARAM_TYPE_LIST, "AuthResult", "No", "Yes,No,Fail", return -1); + + /* Set remaining session parameters */ + + sess->UsePhaseCollapsedRead = ISCSI_USE_PHASE_COLLAPSED_READ_DFLT; + + /* Loop for commands */ + + while (sess->globals->state != TARGET_SHUT_DOWN) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: reading header\n", sess->id); + if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: iscsi_sock_msg() failed\n", sess->id); + break; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: iscsi op %#x\n", sess->id, ISCSI_OPCODE(header)); + if (execute_t(sess, header) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "execute_t() failed\n"); + break; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: iscsi op %#x complete\n", sess->id, ISCSI_OPCODE(header)); + if (ISCSI_OPCODE(header) == ISCSI_LOGOUT_CMD) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: logout received, ending session\n", sess->id); + break; + } + } + + /* Clean up */ + + iscsi_free(sess->buff); + if (param_list_destroy(sess->params) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "param_list_destroy() failed\n"); + return -1; + } + /* Terminate connection */ + + if (iscsi_sock_close(sess->sock) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_close() failed\n"); + } + /* Make session available */ + + ISCSI_LOCK(&g_session_q_mutex, return -1); + (void) memset(sess, 0x0, sizeof(*sess)); + if (iscsi_queue_insert(&g_session_q, sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + return -1; + } + ISCSI_UNLOCK(&g_session_q_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "session %d: ended\n", sess->id); + + return 0; +} + +static int +read_data_pdu(target_session_t * sess, + iscsi_write_data_t * data, + iscsi_scsi_cmd_args_t * args) +{ + uint8_t header[ISCSI_HEADER_LEN]; + int ret_val = -1; + + if (iscsi_sock_msg(sess->sock, 0, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + if ((ret_val = iscsi_write_data_decap(header, data)) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_write_data_decap() failed\n"); + return ret_val; + } + /* Check args */ + if (sess->sess_params.max_data_seg_length) { + if (data->length > sess->sess_params.max_data_seg_length) { + args->status = 0x02; + return -1; + } + } + if ((args->bytes_recv + data->length) > args->trans_len) { + args->status = 0x02; + return -1; + } + if (data->tag != args->tag) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Data ITT (%d) does not match with command ITT (%d)\n", data->tag, args->tag); + if (data->final) { + args->status = 0x02; + return -1; + } else { + /* Send a reject PDU */ + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Sending Reject PDU\n"); + if (reject_t(sess, header, 0x09) != 0) { /* Invalid PDU Field */ + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Sending Reject PDU failed\n"); + return 1; + } + } + } + return 0; +} + +int +target_transfer_data(target_session_t * sess, iscsi_scsi_cmd_args_t * args, struct iovec * sg, int sg_len) +{ + iscsi_write_data_t data; + struct iovec *iov, *iov_ptr = NULL; + int iov_len; + +#define TTD_CLEANUP do { \ + if (iov_ptr != NULL) { \ + iscsi_free_atomic(iov_ptr); \ + } \ +} while (/* CONSTCOND */ 0) + + args->bytes_recv = 0; + if ((!sess->sess_params.immediate_data) && args->length) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Cannot accept any Immediate data\n"); + args->status = 0x02; + return -1; + } + /* Make a copy of the iovec */ + + if ((iov_ptr = iscsi_malloc_atomic(sizeof(struct iovec) * sg_len)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + iov = iov_ptr; + (void) memcpy(iov, sg, sizeof(struct iovec) * sg_len); + iov_len = sg_len; + + /* + * Read any immediate data. + */ + + if (sess->sess_params.immediate_data && args->length) { + if (sess->sess_params.max_data_seg_length) { + RETURN_GREATER("args->length", args->length, sess->sess_params.max_data_seg_length, TTD_CLEANUP, -1); + } + /* Modify iov to include just immediate data */ + + if (modify_iov(&iov, &iov_len, 0, args->length) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + TTD_CLEANUP; + return -1; + } + iscsi_trace(TRACE_SCSI_DATA, __FILE__, __LINE__, "reading %u bytes immediate write data\n", args->length); + if ((uint32_t)iscsi_sock_msg(sess->sock, 0, args->length, iov, iov_len) != args->length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TTD_CLEANUP; + return -1; + } + iscsi_trace(TRACE_SCSI_DATA, __FILE__, __LINE__, "successfully read %u bytes immediate write data\n", args->length); + args->bytes_recv += args->length; + } + /* + * Read iSCSI data PDUs + */ + + if (args->bytes_recv < args->trans_len) { + int r2t_flag = 0; + int read_status = 0; + iscsi_r2t_t r2t; + int desired_xfer_len = MIN(sess->sess_params.first_burst_length, + args->trans_len) - args->bytes_recv; + + (void) memset(&r2t, 0x0, sizeof(r2t)); + do { + + /* + * Send R2T if we're either operating in solicted + * mode or we're operating in unsolicted + */ + /* mode and have reached the first burst */ + if (!r2t_flag && (sess->sess_params.initial_r2t || + (sess->sess_params.first_burst_length && + (args->bytes_recv >= sess->sess_params.first_burst_length)))) { + uint8_t header[ISCSI_HEADER_LEN]; + + desired_xfer_len = MIN((args->trans_len - args->bytes_recv), + sess->sess_params.max_burst_length); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending R2T for %u bytes data\n", desired_xfer_len); + r2t.tag = args->tag; + + r2t.transfer_tag = 0x1234; + + r2t.ExpCmdSN = sess->ExpCmdSN; + r2t.MaxCmdSN = sess->MaxCmdSN; + r2t.StatSN = ++(sess->StatSN); + r2t.length = desired_xfer_len; + r2t.offset = args->bytes_recv; + if (iscsi_r2t_encap(header, &r2t) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "r2t_encap() failed\n"); + TTD_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "sending R2T tag %u transfer tag %u len %u offset %u\n", + r2t.tag, r2t.transfer_tag, r2t.length, r2t.offset); + if (iscsi_sock_msg(sess->sock, 1, ISCSI_HEADER_LEN, header, 0) != ISCSI_HEADER_LEN) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TTD_CLEANUP; + return -1; + } + r2t_flag = 1; + r2t.R2TSN += 1; + } + /* Read iSCSI data PDU */ + + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "reading data pdu\n"); + if ((read_status = read_data_pdu(sess, &data, args)) != 0) { + if (read_status == 1) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "Unknown PDU received and ignored. Expecting Data PDU\n"); + continue; + } else { + iscsi_trace_error(__FILE__, __LINE__, "read_data_pdu() failed\n"); + args->status = 0x02; + TTD_CLEANUP; + return -1; + } + } + WARN_NOT_EQUAL("ExpStatSN", data.ExpStatSN, sess->StatSN); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "read data pdu OK (offset %u, length %u)\n", data.offset, data.length); + + /* Modify iov with offset and length. */ + + iov = iov_ptr; + (void) memcpy(iov, sg, sizeof(struct iovec) * sg_len); + iov_len = sg_len; + if (modify_iov(&iov, &iov_len, data.offset, data.length) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + TTD_CLEANUP; + return -1; + } + /* Scatter into destination buffers */ + + if ((uint32_t)iscsi_sock_msg(sess->sock, 0, data.length, iov, iov_len) != data.length) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + TTD_CLEANUP; + return -1; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully scattered %u bytes\n", data.length); + args->bytes_recv += data.length; + desired_xfer_len -= data.length; + if ((!r2t_flag) && (args->bytes_recv > sess->sess_params.first_burst_length)) { + iscsi_trace_error(__FILE__, __LINE__, "Received unsolicited data (%u) more than first_burst_length (%u)\n", args->bytes_recv, sess->sess_params.first_burst_length); + args->status = 0x02; + TTD_CLEANUP; + return -1; + } + if ((desired_xfer_len != 0) && data.final) { + iscsi_trace_error(__FILE__, __LINE__, "Expecting more data (%d) from initiator for this sequence\n", desired_xfer_len); + args->status = 0x02; + TTD_CLEANUP; + return -1; + } + if ((desired_xfer_len == 0) && !data.final) { + iscsi_trace_error(__FILE__, __LINE__, "Final bit not set on the last data PDU of this sequence\n"); + args->status = 0x02; + TTD_CLEANUP; + return -1; + } + if ((desired_xfer_len == 0) && (args->bytes_recv < args->trans_len)) { + r2t_flag = 0; + } + } while (args->bytes_recv < args->trans_len); + RETURN_NOT_EQUAL("Final bit", data.final, 1, TTD_CLEANUP, -1); + } else { + RETURN_NOT_EQUAL("Final bit", args->final, 1, TTD_CLEANUP, -1); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "successfully transferred %u bytes write data\n", args->trans_len); + TTD_CLEANUP; + return 0; +} + + + + +/******************** + * Public Functions * + ********************/ + +int +target_init(globals_t *gp, targv_t *tv, char *TargetName) +{ + int i; + uint32_t j; + + NEWARRAY(target_session_t, g_session, gp->max_sessions, "target_init", return -1); + (void) strlcpy(gp->targetname, TargetName, sizeof(gp->targetname)); + if (gp->state == TARGET_INITIALIZING || gp->state == TARGET_INITIALIZED) { + iscsi_trace_error(__FILE__, __LINE__, "duplicate target initialization attempted\n"); + return -1; + } + gp->state = TARGET_INITIALIZING; + if (iscsi_queue_init(&g_session_q, gp->max_sessions) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_init() failed\n"); + return -1; + } + gp->tv = tv; + for (i = 0; i < gp->max_sessions; i++) { + g_session[i].id = i; + if (iscsi_queue_insert(&g_session_q, &g_session[i]) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_queue_insert() failed\n"); + return -1; + } + } + for (j = 0 ; j < tv->c ; j++) { + if ((g_session[j].d = device_init(gp, tv, &tv->v[j])) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "device_init() failed\n"); + return -1; + } + } + ISCSI_MUTEX_INIT(&g_session_q_mutex, return -1); + gp->listener_listening = 0; + gp->listener_pid = -1; + gp->state = TARGET_INITIALIZED; + + printf("TARGET: TargetName is %s\n", gp->targetname); + for (i = 0 ; i < gp->sockc ; i++) { + printf("\tsocket %d listening on port %hd\n", gp->sockv[i], gp->port); + } + + return 0; +} + +int +target_shutdown(globals_t *gp) +{ + target_session_t *sess; + int i; + + if ((gp->state == TARGET_SHUTTING_DOWN) || (gp->state == TARGET_SHUT_DOWN)) { + iscsi_trace_error(__FILE__, __LINE__, "duplicate target shutdown attempted\n"); + return -1; + } + gp->state = TARGET_SHUTTING_DOWN; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "shutting down target\n"); + for (i = 0; i < gp->max_sessions; i++) { + sess = &g_session[i]; + + /* Need to replace with a call to session_destroy() */ + + if (sess->IsLoggedIn) { + printf("shutting down socket on sess %d\n", i); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "shutting down socket on sess %d\n", i); + if (iscsi_sock_shutdown(sess->sock, 2) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_shutdown() failed\n"); + return -1; + } + printf("waiting for worker %d (pid %d, state %d)\n", i, sess->worker.pid, sess->worker.state); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "waiting for worker %d (pid %d, state %d)\n", + i, sess->worker.pid, sess->worker.state); + while (sess->worker.state & ISCSI_WORKER_STATE_STARTED) { + ISCSI_SPIN; + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "worker %d has exited\n", i); + } + if (device_shutdown(sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "device_shutdown() failed\n"); + return -1; + } + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "shutting down accept socket\n"); + if (iscsi_sock_shutdown(gp->sock, 2) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_shutdown() failed\n"); + return -1; + } + if (gp->listener_pid != ISCSI_GETPID) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "waiting for listener thread\n"); + while (gp->listener_listening) + ISCSI_SPIN; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "listener thread has exited\n"); + } + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "closing accept socket\n"); + if (iscsi_sock_close(gp->sock) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_close() failed\n"); + return -1; + } + ISCSI_MUTEX_DESTROY(&g_session_q_mutex, return -1); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "target shutdown complete\n"); + gp->state = TARGET_SHUT_DOWN; + + return 0; +} + +int +target_listen(globals_t *gp) +{ + struct sockaddr_in6 remoteAddrStorage6; + struct sockaddr_in6 localAddrStorage6; + struct sockaddr_in remoteAddrStorage; + struct sockaddr_in localAddrStorage; + target_session_t *sess; + iscsi_socket_t newconn; + socklen_t remoteAddrLen; + socklen_t localAddrLen; + char remote[1024]; + char local[1024]; + int i; + + ISCSI_THREAD_START("listen_thread"); + gp->listener_pid = ISCSI_GETPID; + gp->listener_listening++; + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "listener thread started\n"); + + if (!iscsi_socks_establish(gp->sockv, gp->famv, &gp->sockc, gp->address_family, gp->port)) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_establish() failed\n"); + goto done; + } + gp->sock = gp->sockv[0]; + + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "create, bind, listen OK\n"); + + /* Loop for connections: FIX ME with queue */ + + while (gp->state != TARGET_SHUT_DOWN) { + ISCSI_LOCK(&g_session_q_mutex, return -1); + if ((sess = iscsi_queue_remove(&g_session_q)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "no free sessions: iscsi_queue_remove() failed\n"); + goto done; + } + ISCSI_UNLOCK(&g_session_q_mutex, return -1); +#if 0 + (void) memset(sess, 0x0, sizeof(*sess)); +#endif + + sess->globals = gp; + + /* Accept connection, spawn session thread, and */ + /* clean up old threads */ + + i = iscsi_waitfor_connection(gp->sockv, gp->sockc, gp->config_file, &newconn); + + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "waiting for %s connection on port %hd\n", + iscsi_address_family(gp->famv[i]), + gp->port); + + if (!iscsi_sock_accept(newconn, &sess->sock)) { + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "iscsi_sock_accept() failed\n"); + goto done; + } + + switch (gp->famv[i]) { + case AF_INET: + sess->address_family = ISCSI_IPv4; + (void) memset(&localAddrStorage, 0x0, localAddrLen = sizeof(localAddrStorage)); + if (getsockname(sess->sock, (struct sockaddr *) (void *) &localAddrStorage, &localAddrLen) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_getsockname() failed\n"); + goto done; + } + + (void) memset(&remoteAddrStorage, 0x0, remoteAddrLen = sizeof(remoteAddrStorage)); + if (getpeername(sess->sock, (struct sockaddr *) (void *) &remoteAddrStorage, &remoteAddrLen) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_getpeername() failed\n"); + goto done; + } + +#ifdef HAVE_GETNAMEINFO + if (getnameinfo((struct sockaddr *)(void *)&localAddrStorage, + sizeof(localAddrStorage), local, sizeof(local), NULL, 0, NI_NUMERICHOST) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "getnameinfo local failed\n"); + } + if (getnameinfo((struct sockaddr *)(void *)&remoteAddrStorage, + sizeof(remoteAddrStorage), remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "getnameinfo remote failed\n"); + } + (void) strlcpy(sess->initiator, remote, sizeof(sess->initiator)); +#else + (void) strlcpy(local, inet_ntoa(localAddrStorage.sin_addr), sizeof(local)); + (void) strlcpy(sess->initiator, inet_ntoa(remoteAddrStorage.sin_addr), sizeof(sess->initiator)); +#endif + + (void) snprintf(gp->targetaddress, sizeof(gp->targetaddress), "%s:%u,1", local, gp->port); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "IPv4 connection accepted on port %d (local IP %s, remote IP %s)\n", + gp->port, local, sess->initiator); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "TargetAddress = \"%s\"\n", gp->targetaddress); + break; + + case AF_INET6: + sess->address_family = ISCSI_IPv6; + (void) memset(&localAddrStorage6, 0x0, localAddrLen = sizeof(localAddrStorage6)); + if (getsockname(sess->sock, (struct sockaddr *) (void *) &localAddrStorage6, &localAddrLen) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "getsockname() failed\n"); + goto done; + } + + (void) memset(&remoteAddrStorage6, 0x0, remoteAddrLen = sizeof(remoteAddrStorage6)); + if (getpeername(sess->sock, (struct sockaddr *) (void *) &remoteAddrStorage6, &remoteAddrLen) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_getpeername() failed\n"); + goto done; + } + + if (getnameinfo((struct sockaddr *)(void *)&localAddrStorage6, sizeof(localAddrStorage6), local, sizeof(local), NULL, 0, NI_NUMERICHOST) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "getnameinfo local failed\n"); + } + if (getnameinfo((struct sockaddr *)(void *)&remoteAddrStorage6, sizeof(remoteAddrStorage6), remote, sizeof(remote), NULL, 0, NI_NUMERICHOST) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "getnameinfo remote failed\n"); + } + (void) strlcpy(sess->initiator, remote, sizeof(sess->initiator)); + (void) snprintf(gp->targetaddress, sizeof(gp->targetaddress), "%s:%u,1", local, gp->port); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "IPv6 connection accepted on port %d (local IP %s, remote IP %s)\n", + gp->port, local, sess->initiator); + iscsi_trace(TRACE_ISCSI_DEBUG, __FILE__, __LINE__, "TargetAddress = \"%s\"\n", gp->targetaddress); + break; + } + + if (iscsi_thread_create(&sess->worker.thread, (void *) worker_proc_t, sess) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_thread_create() failed\n"); + goto done; + } + } +done: + gp->listener_listening--; + return 0; +} diff --git a/external/bsd/iscsi/dist/src/targets.5 b/external/bsd/iscsi/dist/src/targets.5 new file mode 100644 index 000000000000..7f51a4410b7e --- /dev/null +++ b/external/bsd/iscsi/dist/src/targets.5 @@ -0,0 +1,179 @@ +.\" $NetBSD: targets.5,v 1.1 2009/06/21 21:20:31 agc Exp $ +.\" +.\" Copyright © 2006 Alistair Crooks. All rights reserved. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" 3. 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. +.\" +.Dd December 18, 2007 +.Dt TARGETS 5 +.Os +.Sh NAME +.Nm targets +.Nd configuration file for iSCSI targets +.Sh SYNOPSIS +.Nm targets +.Sh DESCRIPTION +The +.Nm +file describes the iSCSI storage which is presented to iSCSI +initiators by the +.Xr iscsi-target 8 +service. +A description of the iSCSI protocol can be found in +.%T "Internet Small Computer Systems Interface \\*(tNRFC\\*(sP 3720" . +.Pp +Each line in the file +(other than comment lines that begin with a +.Sq # ) +specifies an extent, a device (made up of extents or other devices), +or a target to present to the initiator. +.Pp +Each definition, an extent, a device, and a target, is specified +on a single whitespace delimited line. +.Pp +The +.Ar extent +definition specifies a piece of storage that will be used +as storage, and presented to initiators. +It is the basic definition for an iSCSI target. +Each target must contain at least one extent definition. +The first field in the definition is the extent name, which must +begin with the word +.Dq extent +and be followed by a number. +The next field is the file or +.Nx +device which will be used as persistent storage. +The next field is the offset (in bytes) of the start of the extent. +This field is usually 0. +The fourth field in the definition is the size of the extent. +The basic unit is bytes, and the shorthand +.Ar KB , +.Ar MB , +.Ar GB , +and +.Ar TB +can be used for kilobytes (1024 bytes), +megabytes (1024 kilobytes), gigabytes +(1024 megabytes), and +terabytes (1024 gigabytes) respectively. +It is possible to use the word +.Dq size +to use the full size of the pre-existing regular file +given in the extent name. +.Pp +The +.Ar device +definition specifies a LUN or device, and is made up of extents +and other devices. +It is possible to create hierarchies of devices using the device definition. +The first field in the definition is the device name, which must +begin with the word +.Dq device +and be followed by a number. +The next field is the type of resilience that is to be provided +by the device. +For simple devices, +.Ar RAID0 +suffices. +Greater resilience can be gained by using the +.Ar RAID1 +resilience field. +Following the resilience field is a list of extents or other devices. +Large devices can be created by using multiple RAID0 extents, +in which case each extent will be concatenated. +Resilient devices can be created by using multiple RAID1 devices +or extents, in which case data will be written to each of the +devices or extents in turn. +If RAID1 resilience is used, all the extents or sub-devices must +be the same size. +Please note that RAID1 recovery is not yet supported by the +.Xr iscsi-target 8 +utility. +An extent or sub-device may only be used once. +.Pp +The +.Ar target +definition specifies an iSCSI target, which is presented to the iSCSI +initiator. +Multiple targets can be specified. +The first field in the definition is the target name, which must +begin with either of the words +.Dq target +or +.Dq lun +and be followed by a number. +Optionally, if a target is followed by an +.Dq = +sign and some text, +the text is taken to be that of the iSCSI Qualified Name +of the target. +This IQN is used by the initiator to connect to the appropriate target. +The next field is a selector for whether the storage should be presented +as writable, or merely as read-only storage. +The field of +.Dq rw +denotes read-write storage, +whilst +.Dq ro +denotes read-only storage. +The next field is the device or extent name that will be used as persistent storage +for this target. +The fourth field is a slash-notation netmask which will be used, during the +discovery phase, to control the network addresses to which targets will +be presented. +The magic values +.Dq any +and +.Dq all +will expand to be the same as +.Dq 0/0 . +If an attempt is made to discover a target which is not allowed +by the netmask, a warning will be issued using +.Xr syslog 3 +to make administrators aware of this attempt. +The administrator can still use +tcp wrapper functionality, as found in +.Xr hosts_access 5 +and +.Xr hosts.deny 5 +to allow or deny discovery attempts from initiators as +well as using the inbuilt netmask functionality. +.Sh FILES +.Bl -tag -width /etc/iscsi/targets -compact +.It Pa /etc/iscsi/targets +the list of exported storage +.Nm +.El +.Sh SEE ALSO +.Xr syslog 3 , +.Xr hosts.deny 5 , +.Xr hosts_access 5 , +.Xr iscsi-target 8 +.Sh HISTORY +The +.Nm +file first appeared in +.Nx 4.0 . diff --git a/external/bsd/iscsi/dist/src/tests.c b/external/bsd/iscsi/dist/src/tests.c new file mode 100644 index 000000000000..7a21a48b54ca --- /dev/null +++ b/external/bsd/iscsi/dist/src/tests.c @@ -0,0 +1,1229 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" +#include "compat.h" + +#include + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_UTIME_H +#include +#endif + +#include + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#include "scsi_cmd_codes.h" + +#include "iscsi.h" +#include "initiator.h" +#include "tests.h" +#include "osd.h" +#include "osd_ops.h" + + +#define toSeconds(t) (t.tv_sec + (t.tv_usec/1000000.0)) + +typedef struct osd_device_t { + int target; + int lun; +} OSD_DEVICE_T; + +int osd_command(void *dev, osd_args_t * args, OSD_OPS_MEM * mem); + +/* + * SCSI Command Tests + */ +int +nop_out(uint64_t target, int lun, int length, int ping, const char *data) +{ + initiator_cmd_t cmd; + iscsi_nop_out_args_t nop_cmd; + + cmd.type = ISCSI_NOP_OUT; + cmd.ptr = &nop_cmd; + cmd.isid = target; + cmd.targetname[0] = 0x0; + (void) memset(&nop_cmd, 0x0, sizeof(iscsi_nop_out_args_t)); + RETURN_GREATER("length", length, 4096, NO_CLEANUP, -1); + nop_cmd.length = length; + nop_cmd.data = (const uint8_t *) data; + nop_cmd.lun = lun; + if (!ping) { + nop_cmd.tag = 0xffffffff; + } + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + return 0; +} + +static int +inquiry(uint64_t target, uint32_t lun, uint32_t *device_type) +{ + uint8_t data[36], cdb[16]; + initiator_cmd_t cmd; + iscsi_scsi_cmd_args_t args; + + memset(cdb, 0, 16); + cdb[0] = INQUIRY; + cdb[1] = lun << 5; + cdb[4] = 35; + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.input = 1; + args.trans_len = 36; + args.cdb = cdb; + args.lun = lun; + args.recv_data = data; + memset(&cmd, 0, sizeof(initiator_cmd_t)); + cmd.isid = target; + cmd.type = ISCSI_SCSI_CMD; + cmd.ptr = &args; + + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "INQUIRY failed (status %#x)\n", args.status); + return -1; + } + *device_type = data[0] & 0x1f; + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "Device Type %#x\n", *device_type); + + return 0; +} + + +int +read_capacity(uint64_t target, uint32_t lun, uint32_t *max_lba, uint32_t *block_len) +{ + uint8_t data[8], cdb[16]; + initiator_cmd_t cmd; + iscsi_scsi_cmd_args_t args; + + memset(cdb, 0, 16); + cdb[0] = READ_CAPACITY; + cdb[1] = lun << 5; + + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.recv_data = data; + args.input = 1; + args.lun = lun; + args.trans_len = 8; + args.cdb = cdb; + + cmd.isid = target; + cmd.type = ISCSI_SCSI_CMD; + cmd.ptr = &args; + + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "READ_CAPACITY failed (status %#x)\n", args.status); + return -1; + } + *max_lba = ISCSI_NTOHL(*((uint32_t *) (data))); + *block_len = ISCSI_NTOHL(*((uint32_t *) (data + 4))); + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "Max LBA (lun %u): %u\n", lun, *max_lba); + iscsi_trace(TRACE_SCSI_DEBUG, __FILE__, __LINE__, "Block Len (lun %u): %u\n", lun, *block_len); + if (*max_lba == 0) { + iscsi_trace_error(__FILE__, __LINE__, "Device returned Maximum LBA of zero\n"); + return -1; + } + if (*block_len % 2) { + iscsi_trace_error(__FILE__, __LINE__, "Device returned strange block len: %u\n", *block_len); + return -1; + } + return 0; +} + +/* + * write_read_test() writes a pattern to the first and last block of the + * target:lun + */ +/* + * specified and then reads back this pattern. is either 6 or 10 ans + * specifies + */ +/* WRITE_6/READ_6 and WRITE_10/READ_10, respectively. */ + +int +write_read_test(uint64_t target, uint32_t lun, int type) +{ + iscsi_scsi_cmd_args_t args; + initiator_cmd_t cmd; + uint32_t max_lba; + uint32_t block_len; + uint32_t i; + uint16_t len = 1; + uint8_t data[4096]; + uint8_t cdb[16]; + int j; + + if ((type != 6) && (type != 10)) { + iscsi_trace_error(__FILE__, __LINE__, "bad type, select 6 or 10\n"); + return -1; + } + /* determine last block on device */ + + if (read_capacity(target, lun, &max_lba, &block_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_capacity() failed\n"); + return -1; + } + /* write pattern into first and last block on device */ + + for (i = 0; i <= max_lba; i += max_lba) { + for (j = 0; j < block_len; j++) + data[j] = (uint8_t) (i + j); + memset(cdb, 0, 16); + if (type == 10) { + cdb[0] = WRITE_10; + cdb[1] = lun << 5; + lba2cdb(cdb, &i, &len); + } else { + *((uint32_t *) (cdb + 0)) = ISCSI_HTONL(i); + cdb[0] = WRITE_6; + cdb[1] = (cdb[1] & 0x1f) | lun << 5; + cdb[4] = len; + } + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.send_data = data; + args.output = 1; + args.length = block_len; + args.lun = lun; + args.trans_len = block_len; + args.cdb = cdb; + + cmd.isid = target; + cmd.ptr = &args; + cmd.type = ISCSI_SCSI_CMD; + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + } + + /* read pattern back from first and last block */ + + for (i = 0; i <= max_lba; i += max_lba) { + memset(cdb, 0, 16); + if (type == 10) { + cdb[0] = READ_10; + cdb[1] = lun << 5; + lba2cdb(cdb, &i, &len); + } else { + *((uint32_t *) (cdb + 0)) = ISCSI_HTONL(i); + cdb[0] = READ_6; + cdb[1] = (cdb[1] & 0x1f) | lun << 5; + cdb[4] = len; + } + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.recv_data = data; + args.input = 1; + args.lun = lun; + args.trans_len = block_len; + args.cdb = cdb; + cmd.isid = target; + cmd.type = ISCSI_SCSI_CMD; + cmd.ptr = &args; + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + for (j = 0; j < block_len; j++) { + if (data[j] != (uint8_t) (i + j)) { + iscsi_trace_error(__FILE__, __LINE__, "Bad byte. data[%d] = %u, expected %u.\n", + j, data[j], (uint8_t) (i + j)); + return -1; + } + } + } + return 0; +} + +/* + * WRITE_10|READ_10 + */ + +int +read_or_write(uint64_t target, uint32_t lun, uint32_t lba, uint32_t len, + uint32_t block_len, uint8_t *data, int sg_len, int writing) +{ + initiator_cmd_t cmd; + iscsi_scsi_cmd_args_t args; + uint8_t cdb[16]; + + /* Build CDB */ + + cdb[0] = writing ? WRITE_10 : READ_10; + cdb[1] = lun << 5; + cdb[2] = ((uint8_t *) &lba)[3]; + cdb[3] = ((uint8_t *) &lba)[2]; + cdb[4] = ((uint8_t *) &lba)[1]; + cdb[5] = ((uint8_t *) &lba)[0]; + cdb[7] = ((uint8_t *) &len)[1]; + cdb[8] = ((uint8_t *) &len)[0]; + + /* Build iSCSI command */ + + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.lun = lun; + args.output = writing ? 1 : 0; + args.input = writing ? 0 : 1; + args.trans_len = len * block_len; + args.send_data = writing ? data : NULL; + args.send_sg_len = writing ? sg_len : 0; + args.recv_data = writing ? NULL : data; + args.recv_sg_len = writing ? 0 : sg_len; + args.cdb = cdb; + cmd.isid = target; + cmd.ptr = &args; + cmd.type = ISCSI_SCSI_CMD; + + /* Execute iSCSI command */ + + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_command() failed (status %#x)\n", args.status); + return -1; + } + return 0; +} + +int +throughput_test(uint32_t target, uint32_t lun, uint32_t length, uint32_t request, uint32_t verbose, int writing, int sg_factor) +{ + uint32_t max_lba, block_len; + uint8_t **data; + uint32_t iters; + uint32_t num_blocks; + uint32_t block_offset; + struct iovec *sg; + int i, j; + struct timeval t_start, t_stop; + double seconds; + + /* Get device block len & capacity */ + + if (read_capacity(target, lun, &max_lba, &block_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_capacity() failed\n"); + return -1; + } + if (request % block_len) { + iscsi_trace_error(__FILE__, __LINE__, "request must be a multiple of %u\n", block_len); + return -1; + } + if (!sg_factor) { + iscsi_trace_error(__FILE__, __LINE__, "sg_factor must be at least 1\n"); + return -1; + } + if (request % sg_factor) { + iscsi_trace_error(__FILE__, __LINE__, "request must be a multiple of sg_factor\n"); + return -1; + } + if (length % request) { + iscsi_trace_error(__FILE__, __LINE__, "length must be a multiple of request\n"); + return -1; + } + if (length > ((max_lba + 1) * block_len)) { + iscsi_trace_error(__FILE__, __LINE__, "attempt to read past device (max length %u)\n", max_lba * block_len); + return -1; + } + if ((sg = iscsi_malloc(sg_factor * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + if ((data = iscsi_malloc(sg_factor * sizeof(uint8_t *))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + for (i = 0; i < sg_factor; i++) { + if ((data[i] = iscsi_malloc(request / sg_factor)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + } + + gettimeofday(&t_start, 0); + + iters = length / request; + num_blocks = request / block_len; + for (i = 0; i < iters; i++) { + block_offset = i * num_blocks; + + /* The iSCSI initiator may modify our sg list */ + + for (j = 0; j < sg_factor; j++) { + sg[j].iov_base = data[j]; + sg[j].iov_len = request / sg_factor; + } + if (read_or_write(target, lun, block_offset, num_blocks, block_len, (uint8_t *) sg, sg_factor, writing) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_10() failed\n"); + goto done; + } + if (verbose && !((i + 1) % verbose)) { + printf("%u total bytes %s: this request (lba %u, len %u)\n", + (i + 1) * request, writing ? "written" : "read", block_offset, num_blocks); + } + } + + gettimeofday(&t_stop, 0); + seconds = toSeconds(t_stop) - toSeconds(t_start); + + /* Output results */ + + printf("%u MB %s in %.2f seconds --> %.2f MB/sec\n", length / 1048576, writing ? "written" : "read", (double) seconds, + (double) (length / seconds) / 1048576); + +done: for (i = 0; i < sg_factor; i++) { + if (data[i]) + iscsi_free(data[i]); + } + iscsi_free(data); + iscsi_free(sg); + + return 0; +} + +int +integrity_test(uint32_t target, uint32_t lun, uint32_t length, int sg_factor) +{ + uint32_t max_lba, block_len; + uint8_t **data; + struct iovec *sg; + int i, j; + + /* Get device block len & capacity; and check args */ + + if (read_capacity(target, lun, &max_lba, &block_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_capacity() failed\n"); + return -1; + } + if (length % block_len) { + iscsi_trace_error(__FILE__, __LINE__, "length must be a multiple of block len %u\n", block_len); + return -1; + } + if (!sg_factor) { + iscsi_trace_error(__FILE__, __LINE__, "sg_factor must be at least 1\n"); + return -1; + } + if (length % sg_factor) { + iscsi_trace_error(__FILE__, __LINE__, "length must be a multiple of sg_factor\n"); + return -1; + } + if (length > ((max_lba + 1) * block_len)) { + iscsi_trace_error(__FILE__, __LINE__, "attempt to read past device (max length %u)\n", max_lba * block_len); + return -1; + } + /* Allocate sg and data buffers; fill data buffers with pattern */ + + if ((sg = iscsi_malloc(sg_factor * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + if ((data = iscsi_malloc(sg_factor * sizeof(uint8_t *))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + for (i = 0; i < sg_factor; i++) { + if ((data[i] = iscsi_malloc(length / sg_factor)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + for (j = 0; j < (length / sg_factor); j++) { + /* data[i][j] = i+j; */ + data[i][j] = i + 1; + } + } + + /* Write blocks */ + + for (j = 0; j < sg_factor; j++) { + sg[j].iov_base = data[j]; + sg[j].iov_len = length / sg_factor; + } + if (read_or_write(target, lun, 0, length / block_len, block_len, (uint8_t *) sg, sg_factor, 1) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_or_write() failed\n"); + goto done; + } + for (i = 0; i < sg_factor; i++) { + for (j = 0; j < (length / sg_factor); j++) { + /* if (data[i][j] != (uint8_t)(i+j)) { */ + if (data[i][j] != (uint8_t) (i + 1)) { + iscsi_trace_error(__FILE__, __LINE__, "Bad byte data[%d][%d]: got %u, expected %u\n", i, j, data[i][j], (uint8_t) (i + j)); + goto done; + } + } + } + + /* Read blocks */ + + for (j = 0; j < sg_factor; j++) { + memset(data[j], 0, length / sg_factor); + sg[j].iov_base = data[j]; + sg[j].iov_len = length / sg_factor; + } + if (read_or_write(target, lun, 0, length / block_len, block_len, (uint8_t *) sg, sg_factor, 0) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_or_write() failed\n"); + goto done; + } + for (i = 0; i < sg_factor; i++) { + for (j = 0; j < (length / sg_factor); j++) { + /* if (data[i][j] != (uint8_t)(i+j)) { */ + if (data[i][j] != (uint8_t) (i + 1)) { + iscsi_trace_error(__FILE__, __LINE__, "Bad byte data[%d][%d]: got %u, expected %u\n", i, j, data[i][j], (uint8_t) (i + j)); + goto done; + } + } + } + +done: + for (i = 0; i < sg_factor; i++) { + if (data[i]) + iscsi_free(data[i]); + } + iscsi_free(data); + iscsi_free(sg); + + return 0; +} + +int +nop_test(uint32_t target, uint32_t lun, uint32_t iters) +{ + struct timeval t_start, t_stop; + char *data; + int i, j, k; + + if ((data = iscsi_malloc(4096)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc() failed\n"); + return -1; + } + /* Fill with some pattern */ + + for (i = 0; i < 4096; i++) + data[i] = (uint8_t) i; + + for (k = 0; k <= 1; k++) { /* 0 = no ping, 1= ping */ + for (j = 0; j <= 4096; j *= 4) { /* payload between 0 and + * 4K */ + gettimeofday(&t_start, 0); + for (i = 0; i < iters; i++) { + if (nop_out(target, lun, j, k, data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_out() failed\n"); + return -1; + } + } + gettimeofday(&t_stop, 0); + + /* Output results */ + + printf("NOP_OUT (%4i bytes, ping = %d): %u iters in %.2f sec --> %.2f usec\n", j, k, + iters, toSeconds(t_stop) - toSeconds(t_start), + ((toSeconds(t_stop) - toSeconds(t_start)) * 1e6) / iters); + if (!j) + j = 1; + } + } + iscsi_free(data); + + return 0; +} + +static const char * +humanise(uint8_t op) +{ + switch(op) { + case TEST_UNIT_READY: + return "TEST_UNIT_READY"; + case INQUIRY: + return "INQUIRY"; + case READ_10: + return "READ_10"; + case WRITE_10: + return "WRITE_10"; + case READ_CAPACITY: + return "READ CAPACITY"; + default: + return "unknown"; + } +} + +/* latency_test() performs for a number of iterations and outputs */ +/* the average latency. can be any of WRITE_10, READ_10, */ +/* TEST_UNIT_READY, READ_CAPACITY or INQUIRY. */ + +int +latency_test(uint64_t target, uint32_t lun, uint8_t op, uint32_t iters) +{ + uint32_t length, trans_len; + uint32_t max_lba, block_len; + int input, output; + uint8_t *data, cdb[16]; + initiator_cmd_t cmd; + iscsi_scsi_cmd_args_t args; + struct timeval t_start, t_stop; + int i, rc = -1; + uint32_t lba = 0; + uint16_t len = 1; + + /* Get device block len */ + + if ((op == WRITE_10) || (op == READ_10)) { + if (read_capacity(target, lun, &max_lba, &block_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_capacity() failed\n"); + return -1; + } + if ((data = iscsi_malloc(block_len)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + } else { + if ((data = iscsi_malloc(1024)) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + } + + + /* Build CDB: */ + + memset(cdb, 0, 16); + input = output = length = trans_len = 0; + cdb[1] = lun << 5; + switch (op) { + case TEST_UNIT_READY: + cdb[0] = TEST_UNIT_READY; + break; + case INQUIRY: + cdb[0] = INQUIRY; + cdb[4] = 35; + input = 1; + trans_len = 36; + break; + case READ_CAPACITY: + cdb[0] = READ_CAPACITY; + input = 1; + trans_len = 8; + break; + case READ_10: + input = 1; + trans_len = block_len; + cdb[0] = READ_10; + cdb[1] = lun << 5; + lba2cdb(cdb, &lba, &len); + break; + case WRITE_10: + output = 1; + trans_len = block_len; + cdb[0] = WRITE_10; + cdb[1] = lun << 5; + lba2cdb(cdb, &lba, &len); + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "op %#x not implemented\n", op); + return -1; + } + + /* Build iSCSI command */ + + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.lun = lun; + args.cdb = cdb; + args.input = input; + args.output = output; + args.trans_len = trans_len; + args.send_data = output ? data : NULL; + args.recv_data = input ? data : NULL; + + cmd.isid = target; + cmd.type = ISCSI_SCSI_CMD; + cmd.ptr = &args; + + /* Run test */ + + gettimeofday(&t_start, 0); + for (i = 0; i < iters; i++) { + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + goto done; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_command() failed (status %#x)\n", args.status); + goto done; + } + } + gettimeofday(&t_stop, 0); + + /* Output results */ + + printf("SCSI op 0x%2x (%s): %u iters in %.2f sec --> %.2f usec\n", + op, humanise(op), iters, toSeconds(t_stop) - toSeconds(t_start), + ((toSeconds(t_stop) - toSeconds(t_start)) * 1e6) / iters); + + rc = 0; +done: + iscsi_free(data); + return rc; +} + +/* + * scatter_gather() tests scatter/gather performance for WRITE_10 and + * READ_10. Instead of specifying a data buffer in args.send_data and + * arg.recv_data, we specify a scatter/gather list. */ + +int +scatter_gather_test(uint64_t target, uint32_t lun, uint8_t op) +{ + uint32_t length, trans_len; + uint8_t cdb[16]; + uint32_t lba = 0; + struct iovec *sg; + uint8_t **buff; + uint32_t block_len, max_lba; + uint16_t len; + int i, n; + int input, output; + initiator_cmd_t cmd; + iscsi_scsi_cmd_args_t args; + int xfer_size = 100 * 1048576; + int xfer_chunk = 1048576; + int rc = -1; + struct timeval t_start, t_stop; + + /* Number of iterations (xfer_chunk bytes read/written per iteration) */ + + if (xfer_size % xfer_chunk) { + iscsi_trace_error(__FILE__, __LINE__, "xfer_size (%d) is not a multiple of xfer_chunk (%d)\n", xfer_size, xfer_chunk); + return -1; + } + n = xfer_size / xfer_chunk; + + /* Number of blocks per iteration */ + + if (read_capacity(target, lun, &max_lba, &block_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_capacity() failed\n"); + return -1; + } + if (xfer_chunk % block_len) { + iscsi_trace_error(__FILE__, __LINE__, "xfer_chunk (%d) is not a multiple of block_len (%d)\n", xfer_chunk, block_len); + return -1; + } + len = xfer_chunk / block_len; + + /* Build CDB */ + + memset(cdb, 0, 16); + cdb[1] = lun << 5; + trans_len = block_len * len; + length = input = output = 0; + switch (op) { + case WRITE_10: + cdb[0] = WRITE_10; + output = 1; + length = trans_len; + break; + case READ_10: + cdb[0] = READ_10; + input = 1; + break; + default: + iscsi_trace_error(__FILE__, __LINE__, "scatter/gather test not implemented for SCSI op %#x\n", op); + return -1; + } + + /* Allocate buffers for scatter/gather */ + + if ((buff = iscsi_malloc(len * sizeof(uint8_t *))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + for (i = 0; i < len; i++) { + buff[i] = iscsi_malloc(block_len); + if (buff[i] == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + } + } + if ((sg = iscsi_malloc(len * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "out of memory\n"); + return -1; + } + for (i = 0; i < len; i++) { + sg[i].iov_base = buff[i]; + sg[i].iov_len = block_len; + } + lba2cdb(cdb, &lba, &len); + + gettimeofday(&t_start, 0); + + /* Begin I/O */ + + for (i = 0; i < n; i++) { + +#if 0 + for (j = 0; j < len; j++) { + sg[j].iov_base = buff[j]; + sg[j].iov_len = block_len; + } +#endif + + memset(&args, 0, sizeof(iscsi_scsi_cmd_args_t)); + args.send_data = output ? ((uint8_t *) sg) : NULL; + args.send_sg_len = output ? len : 0; + args.recv_data = input ? ((uint8_t *) sg) : NULL; + args.recv_sg_len = input ? len : 0; + args.input = input; + args.output = output; + args.length = length; + args.lun = lun; + args.trans_len = trans_len; + args.cdb = cdb; + + cmd.isid = target; + cmd.type = ISCSI_SCSI_CMD; + cmd.ptr = &args; + + if (initiator_command(&cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + goto done; + } + if (args.status) { + iscsi_trace_error(__FILE__, __LINE__, "scsi_command() failed (status %#x)\n", args.status); + goto done; + } + } + + gettimeofday(&t_stop, 0); + printf("SCSI op %#x (%s): %u bytes (%s) in %.2f secs --> %.2f MB/sec\n", + op, humanise(op), xfer_size, (op == WRITE_10) ? "gathered" : "scattered", + toSeconds(t_stop) - toSeconds(t_start), + (xfer_size / 1048576) / (toSeconds(t_stop) - toSeconds(t_start))); + rc = 0; + +done: + for (i = 0; i < len; i++) { + iscsi_free(buff[i]); + } + iscsi_free(buff); + iscsi_free(sg); + return rc; +} + +/* + * OSD Tests + */ + +static int +osd_tests(int target, int lun) +{ + uint32_t GroupID; + uint64_t UserID; + char buffer[1024]; + OSD_DEVICE_T dev = {0, 0}; + uint16_t len; + + if (osd_create_group((void *) &dev, &osd_command, &GroupID) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_create_group() failed\n"); + return -1; + } + printf("OSD_CREATE_GROUP: PASSED\n"); + + if (osd_create((void *) &dev, GroupID, &osd_command, &UserID) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_create() failed\n"); + return -1; + } + printf("OSD_CREATE: PASSED\n"); + + if (osd_write((void *) &dev, GroupID, UserID, 0, 13, "Hello, World!", 0, &osd_command) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_write() failed\n"); + return -1; + } + printf("OSD_WRITE: PASSED\n"); + + if (osd_read((void *) &dev, GroupID, UserID, 0, 13, buffer, 0, &osd_command) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_write() failed\n"); + } + if (strncmp(buffer, "Hello, World!", 13)) { + iscsi_trace_error(__FILE__, __LINE__, "osd_read() failed\n"); + return -1; + } + printf("OSD_READ: PASSED\n"); + + if (osd_set_one_attr((void *) &dev, GroupID, UserID, 0x30000000, 0x1, 480, buffer, &osd_command) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_write() failed\n"); + } + printf("OSD_SET_ATTR: PASSED\n"); + + if (osd_get_one_attr((void *) &dev, GroupID, UserID, 0x30000000, 0, 480, &osd_command, &len, buffer) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_get_one_attr() failed\n"); + } + if (strncmp(buffer, "Hello, World!", 13)) { + iscsi_trace_error(__FILE__, __LINE__, "osd_read() failed\n"); + return -1; + } + printf("OSD_GET_ATTR: PASSED\n"); + + if (osd_remove((void *) &dev, GroupID, UserID, &osd_command) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_remove() failed\n"); + return -1; + } + printf("OSD_REMOVE: PASSED\n"); + + if (osd_remove_group((void *) &dev, GroupID, &osd_command) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_remove_group() failed\n"); + return -1; + } + printf("OSD_REMOVE: PASSED\n"); + + return 0; +} + +static int +disk_tests(int target, int lun) +{ + uint32_t request_size; + uint32_t max_lba, block_len; + uint32_t min_request_size = 8192; + uint32_t max_request_size = 262144; + uint32_t xfer_size = 32 * 262144; + + /* Initial Tests */ + + if (read_capacity(target, lun, &max_lba, &block_len) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "read_capacity() failed\n"); + return -1; + } + printf("read_capacity PASSED\n"); + if (write_read_test(target, lun, 10) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "write_read_test() failed\n"); + return -1; + } + printf("write_read_test PASSED\n"); + if (integrity_test(target, lun, max_request_size, 1024) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "integrity_test() failed\n"); + return -1; + } + printf("integrity_test PASSED\n"); + + /* Latency Tests */ + + if (latency_test(target, lun, READ_10, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(READ_10) failed\n"); + return -1; + } + if (latency_test(target, lun, WRITE_10, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(WRITE_10) failed\n"); + return -1; + } + if (latency_test(target, lun, READ_CAPACITY, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(READ_CAPACITY) failed\n"); + return -1; + } + /* Throughput Tests */ + + for (request_size = min_request_size; request_size <= max_request_size; request_size *= 2) { + printf("%u bytes/request: ", request_size); + if (throughput_test(target, lun, xfer_size, request_size, (xfer_size / request_size) + 1, 1, 1) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "througput_test() failed\n"); + return -1; + } + } + for (request_size = min_request_size; request_size <= max_request_size; request_size *= 2) { + printf("%u bytes/request: ", request_size); + if (throughput_test(target, lun, xfer_size, request_size, (xfer_size / request_size) + 1, 0, 1) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "througput_test() failed\n"); + return -1; + } + } + + return 0; +} + +int +test_all(int target, int lun) +{ + uint32_t device_type = 0; + const char *data = "Hello, world!"; + + /* Initial Tests */ + + printf("##BEGIN INITIAL TESTS[%d:%d]##\n", target, lun); + if (nop_out(target, lun, 13, 0, data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_out() failed\n"); + return -1; + } + printf("nop_out() PASSED\n"); + if (nop_out(target, lun, 13, 1, data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_out() w/ ping failed\n"); + return -1; + } + printf("nop_out() w/ ping PASSED\n"); + if (inquiry(target, lun, &device_type) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "inquiry() failed\n"); + return -1; + } + printf("inquiry() PASSED: device type %#x\n", device_type); + printf("##END INITIAL TESTS[%d:%d]##\n\n", target, lun); + + /* iSCSI Latency Tests */ + + printf("##BEGIN iSCSI LATENCY TESTS[%d:%d]##\n", target, lun); + if (nop_test(target, lun, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_test() failed\n"); + return -1; + } + printf("##END iSCSI LATENCY TESTS[%d:%d]##\n\n", target, lun); + + /* SCSI Latency Tests */ + + printf("##BEGIN SCSI LATENCY TESTS[%d:%d]##\n", target, lun); + if (latency_test(target, lun, TEST_UNIT_READY, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(TEST_UNIT_READY) failed\n"); + return -1; + } + if (latency_test(target, lun, INQUIRY, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(INQUIRY) failed\n"); + return -1; + } + printf("##END SCSI LATENCY TESTS[%d:%d]##\n\n", target, lun); + + /* Device-specific tests */ + + printf("##BEGIN DEVICE-SPECIFIC TESTS[%d:%d]##\n", target, lun); + switch (device_type) { + case 0x00: + if (disk_tests(target, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_tests() failed\n"); + return -1; + } + break; + case 0x0e: + if (osd_tests(target, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_tests() failed\n"); + return -1; + } + break; + default: + break; + } + printf("##END DEVICE-SPECIFIC TESTS[%d:%d]##\n\n", target, lun); + + return 0; +} + +int +ii_test_all(void) +{ + uint32_t device_type = 0; + const char *data = "Hello, world!"; + int target = 0; + int lun = 0; + + /* Initial Tests */ + + printf("##BEGIN INITIAL TESTS[%d:%d]##\n", target, lun); + if (nop_out(target, lun, 13, 0, data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_out() failed\n"); + return -1; + } + printf("nop_out() PASSED\n"); + if (nop_out(target, lun, 13, 1, data) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_out() w/ ping failed\n"); + return -1; + } + printf("nop_out() w/ ping PASSED\n"); + if (inquiry(target, lun, &device_type) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "inquiry() failed\n"); + return -1; + } + printf("inquiry() PASSED: device type %#x\n", device_type); + printf("##END INITIAL TESTS[%d:%d]##\n\n", target, lun); + + /* iSCSI Latency Tests */ + + printf("##BEGIN iSCSI LATENCY TESTS[%d:%d]##\n", target, lun); + if (nop_test(target, lun, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "nop_test() failed\n"); + return -1; + } + printf("##END iSCSI LATENCY TESTS[%d:%d]##\n\n", target, lun); + + /* SCSI Latency Tests */ + + printf("##BEGIN SCSI LATENCY TESTS[%d:%d]##\n", target, lun); + if (latency_test(target, lun, TEST_UNIT_READY, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(TEST_UNIT_READY) failed\n"); + return -1; + } + if (latency_test(target, lun, INQUIRY, 1000) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "latency_test(INQUIRY) failed\n"); + return -1; + } + printf("##END SCSI LATENCY TESTS[%d:%d]##\n\n", target, lun); + + /* Device-specific tests */ + + printf("##BEGIN DEVICE-SPECIFIC TESTS[%d:%d]##\n", target, lun); + switch (device_type) { + case 0x00: + if (disk_tests(target, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "disk_tests() failed\n"); + return -1; + } + break; + case 0x0e: + if (osd_tests(target, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "osd_tests() failed\n"); + return -1; + } + break; + default: + break; + } + printf("##END DEVICE-SPECIFIC TESTS[%d:%d]##\n\n", target, lun); + + return 0; +} + +int +osd_command(void *dev, osd_args_t * args, OSD_OPS_MEM * m) +{ + initiator_cmd_t initiator_cmd; + iscsi_scsi_cmd_args_t scsi_cmd; + uint8_t ahs[1024], *ahs_ptr = ahs; + int ahs_len = 0; + uint8_t cdb[CONFIG_OSD_CDB_LEN]; + uint64_t target = ((OSD_DEVICE_T *) dev)->target; + uint16_t len; + + /* Build AHS for expected bidi read length */ + + if (m->send_len && m->recv_len) { + memset(ahs_ptr, 0, 8); + len = 8; + *((uint32_t *) ahs_ptr) = ISCSI_HTONS(len); /* AHS length */ + ahs_ptr[2] = 0x02; /* Type */ + *((uint32_t *) (ahs_ptr + 4)) = ISCSI_HTONL(m->recv_len); /* Expected Read length */ + ahs_ptr += 8; + ahs_len += 8; + } + /* Build AHS for extended CDB */ + + OSD_ENCAP_CDB(args, cdb); + /* OSD_PRINT_CDB(cdb, cdb+16); */ + memset(ahs_ptr, 0, 4); + len = (CONFIG_OSD_CDB_LEN - 15); /* AHS length */ + *((uint16_t *) ahs_ptr) = ISCSI_HTONS(len); /* AHS length */ + ahs_ptr[2] = 0x01; /* Type */ + memcpy(ahs_ptr + 4, cdb + 16, CONFIG_OSD_CDB_LEN - 16); /* Copy remaining CDB */ + ahs_ptr += CONFIG_OSD_CDB_LEN - 15; + ahs_len += CONFIG_OSD_CDB_LEN - 15; + + /* Build iscsi_scsi_cmd_args_t */ + + memset(&scsi_cmd, 0, sizeof(iscsi_scsi_cmd_args_t)); + scsi_cmd.cdb = cdb; + scsi_cmd.ahs_len = ahs_len; + scsi_cmd.ahs = ahs; + if (m->send_len && m->recv_len) { + scsi_cmd.input = 1; + scsi_cmd.output = 1; + scsi_cmd.length = m->send_len; + scsi_cmd.trans_len = m->send_len; + scsi_cmd.bidi_trans_len = m->recv_len; + scsi_cmd.send_data = __UNCONST(m->send_data); /* XXX - agc */ + scsi_cmd.send_sg_len = m->send_sg; + scsi_cmd.recv_data = m->recv_data; + scsi_cmd.recv_sg_len = m->recv_sg; + } else if (m->send_len) { + scsi_cmd.output = 1; + scsi_cmd.length = m->send_len; + scsi_cmd.trans_len = m->send_len; + scsi_cmd.send_data = __UNCONST(m->send_data); /* XXX - agc */ + scsi_cmd.send_sg_len = m->send_sg; + } else if (m->recv_len) { + scsi_cmd.input = 1; + scsi_cmd.trans_len = m->recv_len; + scsi_cmd.recv_data = m->recv_data; + scsi_cmd.recv_sg_len = m->recv_sg; + } + /* Build initiator_cmd_t */ + + memset(&initiator_cmd, 0, sizeof(initiator_cmd_t)); + initiator_cmd.isid = target; + initiator_cmd.type = ISCSI_SCSI_CMD; + initiator_cmd.ptr = &scsi_cmd; + + /* Execute initiator_cmd_t */ + + if (initiator_command(&initiator_cmd) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_command() failed\n"); + return -1; + } + if (scsi_cmd.status != 0) { + iscsi_trace_error(__FILE__, __LINE__, "SCSI command failed\n"); + return -1; + } + return 0; +} diff --git a/external/bsd/iscsi/dist/src/usocktest.c b/external/bsd/iscsi/dist/src/usocktest.c new file mode 100644 index 000000000000..e3de8577acc3 --- /dev/null +++ b/external/bsd/iscsi/dist/src/usocktest.c @@ -0,0 +1,378 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#define EXTERN + +#include +#include +#include +#include +#include "iscsiutil.h" + +/* + * NOTE: THIS IS A WORK IN PROGRESS. + * + * For now, you must manually enter the host and target send and recv patterns + * (shown in the code below) beginning at line 104. By default, this code will + * simulate the TCP traffic generated by an 8K iSCSI read between host and target. + */ + +#define NUM_ITERS_DEFAULT 200 +#define VERBOSE_FREQ_DEFAULT 20 +#define PORT_DEFAULT 5001 +#define HOST_SEND_PATTERN_DEFAULT "48" /* send iSCSI command PDU (SCSI READ) */ +#define TARG_RECV_PATTERN_DEFAULT "48" +#define TARG_SEND_PATTERN_DEFAULT "48+8192" /* phase collapsed 8K data + status */ +#define HOST_RECV_PATTERN_DEFAULT "48+8192" + +/* + * Constants + */ + +#define toSeconds(t) (t.tv_sec + (t.tv_usec/1000000.)) +#define MAX_PATTERN_LEN 1024 +#define MAX_BUFFS MAX_PATTERN_LEN/2 + + +char usage[] = "usage: -t I/O target\n" + " -hsp e.g., 48\n" + " -tsp e.g., 48\n" + " -hsp e.g.. 8240\n" + " -hsp e.g., 48+8192\n" + " -n number of iterations\n" + " -v verbose mode\n" + " -p port number\n" + "\nNOTE: The pattern args are not yet implemented.\n" + " You must manually edit usocktest.c to change\n" + " the request pattern which, by default, generates\n" + " TCP traffic identical to an 32 MB iSCSI read\n" + " that uses 8KB data PDUs.\n"; + +int main(int argc, char *argv[]) { + int i, j, n; + char HostSendPattern[MAX_PATTERN_LEN]; + char HostRecvPattern[MAX_PATTERN_LEN]; + char TargSendPattern[MAX_PATTERN_LEN]; + char TargRecvPattern[MAX_PATTERN_LEN]; + int HostSendSize[MAX_BUFFS]; + int HostRecvSize[MAX_BUFFS]; + int TargSendSize[MAX_BUFFS]; + int TargRecvSize[MAX_BUFFS]; + unsigned char* HostSendBuff[MAX_BUFFS]; + unsigned char* HostRecvBuff[MAX_BUFFS]; + unsigned char* TargSendBuff[MAX_BUFFS]; + unsigned char* TargRecvBuff[MAX_BUFFS]; + int NumHostSendBuffs; + int NumHostRecvBuffs; + int NumTargSendBuffs; + int NumTargRecvBuffs; + char ctrlBufferSend[MAX_PATTERN_LEN]; + char ctrlBufferRecv[MAX_PATTERN_LEN]; + unsigned ctrlBuffSize = MAX_PATTERN_LEN; + struct timeval t_start, t_stop; + double time; + iscsi_socket_t iscsi_sock, iscsi_sock_new; + int HostSendTotal, HostRecvTotal; + int TargRecvTotal, TargSendTotal; + int IsTarget; + int Port = PORT_DEFAULT; + int NumIters = NUM_ITERS_DEFAULT; + int VerboseFreq = VERBOSE_FREQ_DEFAULT; + char TargetIP[64] = ""; + + /* + * Parse command line + */ + + strcpy(HostSendPattern, HOST_SEND_PATTERN_DEFAULT); + strcpy(HostRecvPattern, HOST_RECV_PATTERN_DEFAULT); + strcpy(TargSendPattern, TARG_SEND_PATTERN_DEFAULT); + strcpy(TargRecvPattern, TARG_RECV_PATTERN_DEFAULT); + for (i=1; i0)?0:1; + + /* + * Convert command line string patterns here. For now, you must + * manually enter these below. + */ + + NumHostSendBuffs = 1; + HostSendSize[0] = 48; + NumTargRecvBuffs = 1; + TargRecvSize[0] = 48; + NumHostRecvBuffs = 2; + HostRecvSize[0] = 48; + HostRecvSize[1] = 524288; + NumTargSendBuffs = 2; + TargSendSize[0] = 48; + TargSendSize[1] = 524288; + + /* + * Create/bind/listen + */ + + if (iscsi_sock_create(&iscsi_sock)!=0) { + iscsi_trace_error("iscsi_sock_create() failed\n"); + return -1; + } + if (IsTarget) { + if (iscsi_sock_bind(iscsi_sock, Port)!=0) { + iscsi_trace_error("iscsi_sock_bind() failed\n"); + return -1; + } + if (iscsi_sock_listen(iscsi_sock)!=0) { + iscsi_trace_error("iscsi_sock_listen() failed\n"); + return -1; + } + } + + /* + * Accept connection + */ + +accept: + if (IsTarget) { + printf("Waiting for TCP connection on port %u\n", Port); + if(iscsi_sock_accept(iscsi_sock, &iscsi_sock_new)!=0) { + iscsi_trace_error("iscsi_sock_accept() failed\n"); + return -1; + } + printf("Connection accepted\n"); + } else { + printf("Connecting to %s\n", TargetIP); + if(iscsi_sock_connect(iscsi_sock, TargetIP, Port)!=0) { + iscsi_trace_error("iscsi_sock_connect() failed\n"); + return -1; + } + printf("Connected\n"); + iscsi_sock_new = iscsi_sock; + } + + /* + * Host/Target handshake for test parameters + */ + + if (!IsTarget) { + iscsi_trace(TRACE_DEBUG, "Sending test parameters\n"); + sprintf(ctrlBufferSend, "%s:%s:%s:%s:%i:%i:%i", + HostSendPattern, HostRecvPattern, TargSendPattern, TargRecvPattern, + NumIters, VerboseFreq, Port); + if ((n=iscsi_sock_msg(iscsi_sock_new, 1, ctrlBuffSize, ctrlBufferSend, 0))!=ctrlBuffSize) { + iscsi_trace_error("iscsi_sock_msg() failed\n"); + return -1; + } + if ((n=iscsi_sock_msg(iscsi_sock_new, 0, ctrlBuffSize, ctrlBufferRecv, 0))!=ctrlBuffSize) { + iscsi_trace_error("iscsi_sock_msg() failed\n"); + return -1; + } + iscsi_trace(TRACE_DEBUG, "Test parameters sent\n"); + } else { + char *ptr, *delim; + + iscsi_trace(TRACE_DEBUG, "Receiving test parameters\n"); + if ((n=iscsi_sock_msg(iscsi_sock_new, 0, ctrlBuffSize, ctrlBufferRecv, 0))!=ctrlBuffSize) { + iscsi_trace_error("iscsi_sock_msg() failed\n"); + return -1; + } + ptr = ctrlBufferRecv; + delim = strchr(ptr, ':'); + strncpy(HostSendPattern, ptr, delim-ptr+1); HostSendPattern[delim-ptr] = 0x0; ptr = delim+1; + delim = strchr(ptr, ':'); + strncpy(HostRecvPattern, ptr, delim-ptr+1); HostRecvPattern[delim-ptr] = 0x0; ptr = delim+1; + delim = strchr(ptr, ':'); + strncpy(TargSendPattern, ptr, delim-ptr+1); TargSendPattern[delim-ptr] = 0x0; ptr = delim+1; + delim = strchr(ptr, ':'); + strncpy(TargRecvPattern, ptr, delim-ptr+1); TargRecvPattern[delim-ptr] = 0x0; ptr = delim+1; + sscanf(ptr, "%i:%i", &NumIters, &VerboseFreq); + if ((n=iscsi_sock_msg(iscsi_sock_new, 1, ctrlBuffSize, ctrlBufferSend, 0))!=ctrlBuffSize) { + iscsi_trace_error("iscsi_sock_msg() failed\n"); + return -1; + } + iscsi_trace(TRACE_DEBUG, "Test parameters received\n"); + } + + /* + * Check Arguments + */ + + HostSendTotal = 0; for (i=0; i Target receiving size (%i)\n", + HostSendTotal, TargRecvTotal); + return -1; + } + HostRecvTotal = 0; for (i=0; i Target sending size (%i)\n", + HostRecvTotal, TargSendTotal); + return -1; + } + iscsi_trace(TRACE_DEBUG, "HostSendPattern: \"%s\"\n", HostSendPattern); + iscsi_trace(TRACE_DEBUG, "HostRecvPattern: \"%s\"\n", HostRecvPattern); + iscsi_trace(TRACE_DEBUG, "TargRecvPattern: \"%s\"\n", TargRecvPattern); + iscsi_trace(TRACE_DEBUG, "TargSendPattern: \"%s\"\n", TargSendPattern); + iscsi_trace(TRACE_DEBUG, "NumIters: %i\n", NumIters); + iscsi_trace(TRACE_DEBUG, "VerboseFreq: %i\n", VerboseFreq); + iscsi_trace(TRACE_DEBUG, "HostSendTotal: %i bytes\n", HostSendTotal); + iscsi_trace(TRACE_DEBUG, "HostRecvTotal: %i bytes\n", HostRecvTotal); + + /* + * Allocate buffers + */ + + for (i=0; i +#include + +#ifdef HAVE_PWD_H +#include +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#ifdef HAVE_SIGNAL_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#include "scsi_cmd_codes.h" + +#include "iscsi.h" +#include "initiator.h" +#include "tests.h" + +int +mycallback(void *arg) +{ + (*((int *) arg))++; + return 0; +} + +int +main(int argc, char *argv[]) +{ + struct sigaction act; + char hostname[1024]; + char *host; + int tgtlo = 0; + int tgthi = CONFIG_INITIATOR_NUM_TARGETS; + int target = -1; + int lun = 0; + int i, j; + int iterations; + + /* Check args */ + + iterations = 1; + (void) gethostname(host = hostname, sizeof(hostname)); + while ((i = getopt(argc, argv, "h:l:n:t:")) != -1) { + switch(i) { + case 'h': + host = optarg; + break; + case 'l': + lun = atoi(optarg); + break; + case 'n': + iterations = atoi(optarg); + break; + case 't': + target = atoi(optarg); + break; + default: + (void) fprintf(stderr, "%s: unknown option `%c'", *argv, i); + } + } + if (target != -1) { + if (target >= CONFIG_INITIATOR_NUM_TARGETS) { + iscsi_trace_error(__FILE__, __LINE__, "initiator only configured with %d targets\n", CONFIG_INITIATOR_NUM_TARGETS); + exit(EXIT_FAILURE); + } + tgtlo = target; + tgthi = target + 1; + } + if (argc == 1) { + (void) fprintf(stderr, "usage: %s [-h hostname] [-l lun] [-n iterations] [-t target]\n", *argv); + exit(EXIT_FAILURE); + } + for (j = 0; j < iterations; j++) { + + printf("\n", j); + + /* Ignore sigpipe */ + + act.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &act, NULL); + + /* Initialize Initiator */ + if (initiator_init(host) == -1) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_init() failed\n"); + return -1; + } + /* Run tests for each target */ + + for (i = tgtlo; i < tgthi; i++) { + if (test_all(i, lun) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "test_all() failed\n"); + return -1; + } + } + + /* Shutdown Initiator */ + + if (initiator_shutdown() == -1) { + iscsi_trace_error(__FILE__, __LINE__, "initiator_shutdown() failed\n"); + return -1; + } + } + + printf("\n"); + printf("************************************\n"); + printf("* ALL TESTS COMPLETED SUCCESSFULLY *\n"); + printf("************************************\n"); + printf("\n"); + + exit(EXIT_SUCCESS); +} diff --git a/external/bsd/iscsi/dist/src/util.c b/external/bsd/iscsi/dist/src/util.c new file mode 100644 index 000000000000..e8dafd329585 --- /dev/null +++ b/external/bsd/iscsi/dist/src/util.c @@ -0,0 +1,1296 @@ +/* + * IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. By downloading, copying, installing or + * using the software you agree to this license. If you do not agree to this license, do not download, install, + * copy or use the software. + * + * Intel License Agreement + * + * Copyright (c) 2000, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * -Redistributions of source code must retain the above copyright notice, this list of conditions and the + * following disclaimer. + * + * -Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other materials provided with the distribution. + * + * -The name of Intel Corporation may not be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * 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 MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include +#include + +#ifdef HAVE_SYS_SOCKET_H +#include +#endif + +#ifdef HAVE_SYS_UIO_H +#include +#endif + +#ifdef HAVE_ARPA_INET_H +#include +#endif + +#ifdef HAVE_NETINET_IN_H +#include +#endif + +#ifdef HAVE_NETINET_TCP_H +#include +#endif + +#ifdef HAVE_NETDB_H +#include +#endif + +#ifdef HAVE_CTYPE_H +#include +#endif + +#ifdef HAVE_ERRNO_H +#include +#endif + +#ifdef HAVE_PTHREAD_H +#include +#endif + +#ifdef HAVE_STDARG_H +#include +#endif + +#ifdef HAVE_SYS_SELECT_H +#include +#endif + +#ifdef HAVE_POLL_H +#include +#endif + +#include +#include + +#ifdef HAVE_STRING_H +#include +#endif + +#include + +#include "compat.h" +#include "iscsiutil.h" + + + +/* + * Memory Allocation + */ + +void * +iscsi_malloc_atomic(unsigned n) +{ + void *ptr; + + ptr = malloc(n); + iscsi_trace(TRACE_MEM, __FILE__, __LINE__, "iscsi_malloc_atomic(%u) = %p\n", n, ptr); + return ptr; +} + +void * +iscsi_malloc(unsigned n) +{ + void *ptr; + + ptr = malloc(n); + iscsi_trace(TRACE_MEM, __FILE__, __LINE__, "iscsi_malloc(%u) = %p\n", n, ptr); + return ptr; +} + +void +iscsi_free_atomic(void *ptr) +{ + (void) free(ptr); + iscsi_trace(TRACE_MEM, __FILE__, __LINE__, "iscsi_free_atomic(%p)\n", ptr); +} + +void +iscsi_free(void *ptr) +{ + (void) free(ptr); + iscsi_trace(TRACE_MEM, __FILE__, __LINE__, "iscsi_free(%p)\n", ptr); +} + +/* debugging levels */ +void +set_debug(const char *level) +{ + if (strcmp(level, "net") == 0) { + iscsi_debug_level |= TRACE_NET_ALL; + } else if (strcmp(level, "iscsi") == 0) { + iscsi_debug_level |= TRACE_ISCSI_ALL; + } else if (strcmp(level, "scsi") == 0) { + iscsi_debug_level |= TRACE_SCSI_ALL; + } else if (strcmp(level, "osd") == 0) { + iscsi_debug_level |= TRACE_OSD; + } else if (strcmp(level, "all") == 0) { + iscsi_debug_level |= TRACE_ALL; + } +} + +/* + * Threading Routines + */ +int +iscsi_thread_create(iscsi_thread_t * thread, void *(*proc) (void *), void *arg) +{ + if (pthread_create(&thread->pthread, NULL, proc, arg) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "pthread_create() failed\n"); + return -1; + } + if (pthread_detach(thread->pthread) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "pthread_detach() failed\n"); + return -1; + } + return 0; +} + +/* + * Queuing Functions + */ +int +iscsi_queue_init(iscsi_queue_t * q, int depth) +{ + q->head = q->tail = q->count = 0; + q->depth = depth; + if ((q->elem = iscsi_malloc_atomic((unsigned)(depth * sizeof(void *)))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + iscsi_spin_init(&q->lock); + return 0; +} + +void +iscsi_queue_destroy(iscsi_queue_t * q) +{ + iscsi_free_atomic(q->elem); +} + +int +iscsi_queue_full(iscsi_queue_t * q) +{ + return (q->count == q->depth); +} + +int +iscsi_queue_depth(iscsi_queue_t * q) +{ + return q->count; +} + +int +iscsi_queue_insert(iscsi_queue_t * q, void *ptr) +{ + uint32_t flags; + + iscsi_spin_lock_irqsave(&q->lock, &flags); + if (iscsi_queue_full(q)) { + iscsi_trace_error(__FILE__, __LINE__, "QUEUE FULL\n"); + iscsi_spin_unlock_irqrestore(&q->lock, &flags); + return -1; + } + q->elem[q->tail] = ptr; + q->tail++; + if (q->tail == q->depth) { + q->tail = 0; + } + q->count++; + iscsi_spin_unlock_irqrestore(&q->lock, &flags); + return 0; +} + +void * +iscsi_queue_remove(iscsi_queue_t * q) +{ + uint32_t flags = 0; + void *ptr; + + iscsi_spin_lock_irqsave(&q->lock, &flags); + if (!iscsi_queue_depth(q)) { + iscsi_trace(TRACE_QUEUE, __FILE__, __LINE__, "QUEUE EMPTY\n"); + iscsi_spin_unlock_irqrestore(&q->lock, &flags); + return NULL; + } + q->count--; + ptr = q->elem[q->head]; + q->head++; + if (q->head == q->depth) { + q->head = 0; + } + iscsi_spin_unlock_irqrestore(&q->lock, &flags); + return ptr; +} + +void +iscsi_trace(const int trace, const char *f, const int line, const char *fmt, ...) +{ +#ifdef CONFIG_ISCSI_DEBUG + va_list vp; + char buf[8192]; + + if (iscsi_debug_level & trace) { + va_start(vp, fmt); + (void) vsnprintf(buf, sizeof(buf), fmt, vp); + printf("pid %d:%s:%d: %s", + (int) ISCSI_GETPID, f, line, + buf); + va_end(vp); + } +#endif +} + +void +iscsi_trace_warning(const char *f, const int line, const char *fmt, ...) +{ +#ifdef CONFIG_ISCSI_DEBUG + va_list vp; + char buf[8192]; + + if (iscsi_debug_level & TRACE_WARN) { + va_start(vp, fmt); + (void) vsnprintf(buf, sizeof(buf), fmt, vp); + printf("pid %d:%s:%d: ***WARNING*** %s", + (int) ISCSI_GETPID, f, line, + buf); + va_end(vp); + } +#endif +} + +void +iscsi_trace_error(const char *f, const int line, const char *fmt, ...) +{ +#ifdef CONFIG_ISCSI_DEBUG + va_list vp; + char buf[8192]; + + va_start(vp, fmt); + (void) vsnprintf(buf, sizeof(buf), fmt, vp); + va_end(vp); + printf("pid %d:%s:%d: ***ERROR*** %s", (int) ISCSI_GETPID, f, line, buf); +# ifdef HAVE_SYSLOG + syslog(LOG_ERR, "pid %d:%s:%d: ***ERROR*** %s", ISCSI_GETPID, f, line, buf); +# endif /* HAVE_SYSLOG */ +#endif +} + +void +iscsi_print_buffer(const char *buf, const size_t len) +{ +#ifdef CONFIG_ISCSI_DEBUG + size_t i; + + if (iscsi_debug_level & TRACE_NET_BUFF) { + for (i=0 ; i < len; i++) { + if (i % 4 == 0) { + if (i) { + printf("\n"); + } + printf("%4zu:", i); + } + printf("%2x ", (uint8_t) (buf)[i]); + } + if ((len + 1) % 32) { + printf("\n"); + } + } +#endif +} + +/* + * Hashing Functions + */ +#include "initiator.h" + +int +hash_init(hash_t * h, int n) +{ + int i; + + iscsi_spin_init(&h->lock); + h->n = n; + h->insertions = 0; + h->collisions = 0; + if ((h->bucket = iscsi_malloc_atomic(n * sizeof(initiator_cmd_t *))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + for (i = 0; i < n; i++) + h->bucket[i] = NULL; + return 0; +} + +int +hash_insert(hash_t * h, initiator_cmd_t * cmd, unsigned key) +{ + int i; + + iscsi_spin_lock(&h->lock); + cmd->hash_next = NULL; + cmd->key = key; + + i = key % (h->n); + if (h->bucket[i] == NULL) { + iscsi_trace(TRACE_HASH, __FILE__, __LINE__, "inserting key %u (val 0x%p) into bucket[%d]\n", key, cmd, i); + h->bucket[i] = cmd; + } else { + cmd->hash_next = h->bucket[i]; + h->bucket[i] = cmd; + h->collisions++; + iscsi_trace(TRACE_HASH, __FILE__, __LINE__, "inserting key %u (val 0x%p) into bucket[%d] (collision)\n", key, cmd, i); + } + h->insertions++; + iscsi_spin_unlock(&h->lock); + return 0; +} + +struct initiator_cmd_t * +hash_remove(hash_t * h, unsigned key) +{ + initiator_cmd_t *prev; + initiator_cmd_t *curr; + int i; + + iscsi_spin_lock(&h->lock); + i = key % (h->n); + if (h->bucket[i] == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "bucket emtpy\n"); + curr = NULL; + } else { + prev = NULL; + curr = h->bucket[i]; + while ((curr->key != key) && (curr->hash_next != NULL)) { + prev = curr; + curr = curr->hash_next; + } + if (curr->key != key) { + iscsi_trace_error(__FILE__, __LINE__, "key %u (%#x) not found in bucket[%d]\n", key, key, i); + curr = NULL; + } else { + if (prev == NULL) { + h->bucket[i] = h->bucket[i]->hash_next; + iscsi_trace(TRACE_HASH, __FILE__, __LINE__, "removed key %u (val 0x%p) from head of bucket\n", key, curr); + } else { + prev->hash_next = curr->hash_next; + if (prev->hash_next == NULL) { + iscsi_trace(TRACE_HASH, __FILE__, __LINE__, "removed key %u (val 0x%p) from end of bucket\n", key, curr); + } else { + iscsi_trace(TRACE_HASH, __FILE__, __LINE__, "removed key %u (val 0x%p) from middle of bucket\n", key, curr); + } + } + } + } + iscsi_spin_unlock(&h->lock); + return curr; +} + +int +hash_destroy(hash_t * h) +{ + iscsi_free_atomic(h->bucket); + return 0; +} + +/* + * Socket Functions + */ + +int +modify_iov(struct iovec ** iov_ptr, int *iovc, uint32_t offset, uint32_t length) +{ + size_t len; + int disp = offset; + int i; + struct iovec *iov = *iov_ptr; + char *basep; + + /* Given , find beginning iovec and modify its base and length */ + len = 0; + for (i = 0; i < *iovc; i++) { + len += iov[i].iov_len; + if (len > offset) { + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "found offset %u in iov[%d]\n", offset, i); + break; + } + disp -= iov[i].iov_len; + } + if (i == *iovc) { + iscsi_trace_error(__FILE__, __LINE__, "sum of iov lens (%u) < offset (%u)\n", len, offset); + return -1; + } + iov[i].iov_len -= disp; + basep = iov[i].iov_base; + basep += disp; + iov[i].iov_base = basep; + *iovc -= i; + *iov_ptr = &(iov[i]); + iov = *iov_ptr; + + /* + * Given , find ending iovec and modify its length (base does + * not change) + */ + + len = 0; /* we should re-use len and i here... */ + for (i = 0; i < *iovc; i++) { + len += iov[i].iov_len; + if (len >= length) { + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "length %u ends in iovec[%d]\n", length, i); + break; + } + } + if (i == *iovc) { + iscsi_trace_error(__FILE__, __LINE__, "sum of iovec lens (%u) < length (%u)\n", len, length); + for (i = 0; i < *iovc; i++) { + iscsi_trace_error(__FILE__, __LINE__, "iov[%d].iov_base = %p (len %u)\n", i, iov[i].iov_base, (unsigned)iov[i].iov_len); + } + return -1; + } + iov[i].iov_len -= (len - length); + *iovc = i + 1; + +#ifdef CONFIG_ISCSI_DEBUG + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "new iov:\n"); + len = 0; + for (i = 0; i < *iovc; i++) { + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "iov[%d].iov_base = %p (len %u)\n", i, iov[i].iov_base, (unsigned)iov[i].iov_len); + len += iov[i].iov_len; + } + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "new iov length: %u bytes\n", len); +#endif + + return 0; +} + +int +iscsi_sock_setsockopt(iscsi_socket_t * sock, int level, int optname, void *optval, unsigned optlen) +{ + int rc; + + if ((rc = setsockopt(*sock, level, optname, optval, optlen)) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "sock->ops->setsockopt() failed: rc %d errno %d\n", rc, errno); + return 0; + } + return 1; +} + +int +iscsi_sock_getsockopt(iscsi_socket_t * sock, int level, int optname, void *optval, unsigned *optlen) +{ + int rc; + + if ((rc = getsockopt(*sock, level, optname, optval, optlen)) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "sock->ops->getsockopt() failed: rc %d errno %d\n", rc, errno); + return 0; + } + return 1; +} + +int +iscsi_sock_create(iscsi_socket_t * sock) +{ + int rc; + + if ((*sock = rc = socket(AF_INET, SOCK_STREAM, 0)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "socket() failed: rc %d errno %d\n", rc, errno); + return 0; + } + return 1; +} + +int +iscsi_sock_bind(iscsi_socket_t sock, int port) +{ + struct sockaddr_in laddr; + int rc; + + (void) memset(&laddr, 0x0, sizeof(laddr)); + laddr.sin_family = AF_INET; + laddr.sin_addr.s_addr = INADDR_ANY; + laddr.sin_port = ISCSI_HTONS(port); + if ((rc = bind(sock, (struct sockaddr *) (void *) &laddr, sizeof(laddr))) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "bind() failed: rc %d errno %d\n", rc, errno); + return 0; + } + return 1; +} + +int +iscsi_sock_listen(iscsi_socket_t sock) +{ + int rc; + + if ((rc = listen(sock, 32)) < 0) { + iscsi_trace_error(__FILE__, __LINE__, "listen() failed: rc %d errno %d\n", rc, errno); + return 0; + } + return 1; +} + +#ifndef MAXSOCK +#define MAXSOCK 16 +#endif + +int +iscsi_socks_establish(iscsi_socket_t *sockv, int *famv, int *sockc, int family, int port) +{ + struct addrinfo hints; + struct addrinfo *res; + struct addrinfo *res0; + const char *cause = NULL; + char portnum[31]; + int one = 1; + int error; + + (void) memset(&hints, 0x0, sizeof(hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + hints.ai_flags = AI_PASSIVE; +#ifdef AI_NUMERICSERV + hints.ai_flags |= AI_NUMERICSERV; +#endif + (void) snprintf(portnum, sizeof(portnum), "%d", port); + if ((error = getaddrinfo(NULL, portnum, &hints, &res0)) != 0) { + hints.ai_flags = AI_PASSIVE; + if ((error = getaddrinfo(NULL, "iscsi-target", &hints, &res0)) != 0 || + (error = getaddrinfo(NULL, "iscsi", &hints, &res0)) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "getaddrinfo: %s", gai_strerror(error)); + return 0; + } + } + *sockc = 0; + for (res = res0; res && *sockc < MAXSOCK; res = res->ai_next) { + if ((sockv[*sockc] = socket(res->ai_family, res->ai_socktype, res->ai_protocol)) < 0) { + cause = "socket"; + continue; + } + famv[*sockc] = res->ai_family; + if (!iscsi_sock_setsockopt(&sockv[*sockc], SOL_SOCKET, SO_REUSEADDR, &one, sizeof(one))) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_setsockopt() failed\n"); + continue; + } + if (!iscsi_sock_setsockopt(&sockv[*sockc], SOL_TCP, TCP_NODELAY, &one, sizeof(one))) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_setsockopt() failed\n"); + continue; + } + + if (bind(sockv[*sockc], res->ai_addr, res->ai_addrlen) < 0) { + cause = "bind"; + close(sockv[*sockc]); + continue; + } + (void) listen(sockv[*sockc], 32); + + *sockc += 1; + } + if (*sockc == 0) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_establish: no sockets found: %s", cause); + freeaddrinfo(res0); + return 0; + } + freeaddrinfo(res0); + return 1; +} + +/* return the address family for the socket */ +const char * +iscsi_address_family(int fam) +{ + return (fam == AF_INET) ? "IPv4" : (fam == AF_INET6) ? "IPv6" : "[unknown type]"; +} + +/* wait for a connection to come in on a socket */ +/* ARGSUSED2 */ +int +iscsi_waitfor_connection(iscsi_socket_t *sockv, int sockc, const char *cf, iscsi_socket_t *sock) +{ +#ifdef HAVE_POLL + struct pollfd socks[MAXSOCK]; + int i; + + for (;;) { + for (i = 0 ; i < sockc ; i++) { + socks[i].fd = sockv[i]; + socks[i].events = POLLIN; + socks[i].revents = 0; + } + switch(poll(socks, (unsigned)sockc, INFTIM)) { + case -1: + /* interrupted system call */ + continue; + case 0: + /* timeout */ + continue; + default: + for (i = 0 ; i < sockc ; i++) { + if (socks[i].revents & POLLIN) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "connection %d selected\n", sockv[i]); + *sock = sockv[i]; + return i; + } + } + } + } +#else + fd_set infds; + int i; + + for (;;) { + FD_ZERO(&infds); + for (i = 0 ; i < sockc ; i++) { + FD_SET(sockv[i], &infds); + } + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "waiting for connection\n"); + switch (select(32, &infds, NULL, NULL, NULL)) { + case -1: + /* interrupted system call */ + continue; + case 0: + /* timeout */ + continue; + default: + for (i = 0 ; i < sockc ; i++) { + if (FD_ISSET(sockv[i], &infds)) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "connection %d selected\n", sockv[i]); + *sock = sockv[i]; + return i; + } + } + } + } +#endif +} + +int +iscsi_sock_accept(iscsi_socket_t sock, iscsi_socket_t * newsock) +{ + struct sockaddr_in remoteAddr; + socklen_t remoteAddrLen; + + remoteAddrLen = sizeof(remoteAddr); + (void) memset(&remoteAddr, 0, sizeof(remoteAddr)); + if ((*newsock = accept(sock, (struct sockaddr *) (void *)& remoteAddr, &remoteAddrLen)) < 0) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "accept() failed: rc %d errno %d\n", *newsock, errno); + return 0; + } + + return 1; +} + +int +iscsi_sock_getsockname(iscsi_socket_t sock, struct sockaddr * name, unsigned *namelen) +{ + if (getsockname(sock, name, namelen) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "getsockame() failed (errno %d)\n", errno); + return 0; + } + return 1; +} + +int +iscsi_sock_getpeername(iscsi_socket_t sock, struct sockaddr * name, unsigned *namelen) +{ + if (getpeername(sock, name, namelen) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "getpeername() failed (errno %d)\n", errno); + return 0; + } + return 1; +} + +int +iscsi_sock_shutdown(iscsi_socket_t sock, int how) +{ + int rc; + + if ((rc = shutdown(sock, how)) != 0) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "shutdown() failed: rc %d, errno %d\n", rc, errno); + } + return 0; +} + +int +iscsi_sock_close(iscsi_socket_t sock) +{ + int rc; + + if ((rc = close(sock)) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "close() failed: rc %d errno %d\n", rc, errno); + return -1; + } + return 0; +} + +int +iscsi_sock_connect(iscsi_socket_t sock, char *hostname, int port) +{ + struct addrinfo hints; + struct addrinfo *res; + char portstr[32]; + int rc = 0; + int i; + + (void) memset(&hints, 0, sizeof(hints)); + hints.ai_family = PF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + (void) snprintf(portstr, sizeof(portstr), "%d", port); + + for (i = 0; i < ISCSI_SOCK_CONNECT_TIMEOUT; i++) { + + /* Attempt connection */ +#ifdef AI_NUMERICSERV + hints.ai_flags = AI_NUMERICSERV; +#endif + if ((rc = getaddrinfo(hostname, portstr, &hints, &res)) != 0) { + hints.ai_flags = 0; + if ((rc = getaddrinfo(hostname, "iscsi-target", &hints, &res)) != 0 || + (rc = getaddrinfo(hostname, "iscsi", &hints, &res)) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "getaddrinfo: %s", gai_strerror(rc)); + return 0; + } + } + +#if ISCSI_SOCK_CONNECT_NONBLOCK == 1 + if (fcntl(sock, F_SETFL, O_NONBLOCK) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "fcntl O_NONBLOCK failed"); + freeaddrinfo(res); + return -1; + } +#endif + rc = connect(sock, res->ai_addr, res->ai_addrlen); +#if ISCSI_SOCK_CONNECT_NONBLOCK == 1 + if (fcntl(sock, F_SETFL, O_SYNC) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "fcntl O_SYNC failed\n"); + freeaddrinfo(res); + return -1; + } +#endif + + /* Check errno */ + + if (errno == EISCONN) { + rc = 0; + break; + } + if (errno == EAGAIN || errno == EINPROGRESS || errno == EALREADY) { + if (i != ISCSI_SOCK_CONNECT_TIMEOUT - 1) { + printf("***SLEEPING***\n"); + ISCSI_SLEEP(1); + } + } else { + break; + } + } + freeaddrinfo(res); + if (rc < 0) { + iscsi_trace_error(__FILE__, __LINE__, "connect() to %s:%d failed (errno %d)\n", hostname, port, errno); + } + return rc; +} + +/* + * NOTE: iscsi_sock_msg() alters *sg when socket sends and recvs return having only + * transfered a portion of the iovec. When this happens, the iovec is modified + * and resent with the appropriate offsets. + */ + +int +iscsi_sock_msg(iscsi_socket_t sock, int xmit, unsigned len, void *data, int iovc) +{ + int i; + unsigned n = 0; + int rc; + struct iovec *iov; + struct iovec singleton; + uint8_t padding[ISCSI_SOCK_MSG_BYTE_ALIGN]; + struct iovec *iov_padding = NULL; + uint32_t remainder; + uint32_t padding_len = 0; + size_t total_len = 0; + + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "%s %d bytes on sock\n", xmit ? "sending" : "receiving", len); + if (iovc == 0) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "building singleton iovec (data %p, len %u)\n", data, len); + singleton.iov_base = data; + singleton.iov_len = len; + iov = &singleton; + iovc = 1; + } else { + iov = (struct iovec *) data; + } + + /* Add padding */ + + if ((remainder = len % ISCSI_SOCK_MSG_BYTE_ALIGN) != 0) { + if ((iov_padding = iscsi_malloc_atomic((iovc + 1) * sizeof(struct iovec))) == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_malloc_atomic() failed\n"); + return -1; + } + memcpy(iov_padding, iov, iovc * sizeof(struct iovec)); + iov_padding[iovc].iov_base = padding; + padding_len = ISCSI_SOCK_MSG_BYTE_ALIGN - remainder; + iov_padding[iovc].iov_len = padding_len; + iov = iov_padding; + iovc++; + memset(padding, 0, padding_len); + len += padding_len; + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "Added iovec for padding (len %u)\n", padding_len); + } + /* + * We make copy of iovec if we're in debugging mode, as we'll print + * out + */ + /* + * the iovec and the buffer contents at the end of this subroutine + * and + */ + + do { + /* Check iovec */ + + total_len = 0; + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "%s %d buffers\n", xmit ? "gathering from" : "scattering into", iovc); + for (i = 0; i < iovc; i++) { + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "iov[%d].iov_base = %p, len %u\n", i, iov[i].iov_base, (unsigned)iov[i].iov_len); + total_len += iov[i].iov_len; + } + if (total_len != len - n) { + iscsi_trace_error(__FILE__, __LINE__, "iovcs sum to %u != total len of %u\n", total_len, len - n); + iscsi_trace_error(__FILE__, __LINE__, "iov = %p\n", iov); + for (i = 0; i < iovc; i++) { + iscsi_trace_error(__FILE__, __LINE__, "iov[%d].iov_base = %p, len %u\n", + i, iov[i].iov_base, (unsigned)iov[i].iov_len); + } + return -1; + } + if ((rc = (xmit) ? writev(sock, iov, iovc) : readv(sock, iov, iovc)) == 0) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "%s() failed: rc %d errno %d\n", (xmit) ? "writev" : "readv", rc, errno); + break; + } else if (rc < 0) { + /* Temp FIXME */ + iscsi_trace_error(__FILE__, __LINE__, "%s() failed: rc %d errno %d\n", (xmit)?"writev":"readv", rc, errno); + break; + } + n += rc; + if (n < len) { + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "Got partial %s: %d bytes of %u\n", (xmit) ? "send" : "recv", rc, len - n + rc); + + total_len = 0; + for (i = 0; i < iovc; i++) { + total_len += iov[i].iov_len; + } + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "before modify_iov: %s %d buffers, total_len = %u, n = %u, rc = %u\n", + xmit ? "gathering from" : "scattering into", iovc, total_len, n, rc); + if (modify_iov(&iov, &iovc, (unsigned) rc, len - n) != 0) { + iscsi_trace_error(__FILE__, __LINE__, "modify_iov() failed\n"); + break; + } + total_len = 0; + for (i = 0; i < iovc; i++) { + total_len += iov[i].iov_len; + } + iscsi_trace(TRACE_NET_IOV, __FILE__, __LINE__, "after modify_iov: %s %d buffers, total_len = %u, n = %u, rc = %u\n\n", + xmit ? "gathering from" : "scattering into", iovc, total_len, n, rc); + } + } while (n < len); + + if (remainder) { + iscsi_free_atomic(iov_padding); + } + iscsi_trace(TRACE_NET_DEBUG, __FILE__, __LINE__, "successfully %s %u bytes on sock (%u bytes padding)\n", xmit ? "sent" : "received", n, padding_len); + return n - padding_len; +} + +/* + * Temporary Hack: + * + * TCP's Nagle algorithm and delayed-ack lead to poor performance when we send + * two small messages back to back (i.e., header+data). The TCP_NODELAY option + * is supposed to turn off Nagle, but it doesn't seem to work on Linux 2.4. + * Because of this, if our data payload is small, we'll combine the header and + * data, else send as two separate messages. + */ + +int +iscsi_sock_send_header_and_data(iscsi_socket_t sock, + void *header, unsigned header_len, + const void *data, unsigned data_len, int iovc) +{ + struct iovec iov[ISCSI_MAX_IOVECS]; + + if (data_len && data_len <= ISCSI_SOCK_HACK_CROSSOVER) { + /* combine header and data into one iovec */ + if (iovc >= ISCSI_MAX_IOVECS) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + if (iovc == 0) { + iov[0].iov_base = header; + iov[0].iov_len = header_len; + iov[1].iov_base = __UNCONST((const char *)data); + iov[1].iov_len = data_len; + iovc = 2; + } else { + iov[0].iov_base = header; + iov[0].iov_len = header_len; + (void) memcpy(&iov[1], data, sizeof(struct iovec) * iovc); + iovc += 1; + } + if ((unsigned)iscsi_sock_msg(sock, Transmit, header_len + data_len, iov, iovc) != header_len + data_len) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + } else { + if ((unsigned)iscsi_sock_msg(sock, Transmit, header_len, header, 0) != header_len) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + if (data_len != 0 && (unsigned)iscsi_sock_msg(sock, Transmit, data_len, __UNCONST((const char *) data), iovc) != data_len) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_sock_msg() failed\n"); + return -1; + } + } + return header_len + data_len; +} + + +/* spin lock functions */ +int +iscsi_spin_init(iscsi_spin_t * lock) +{ + pthread_mutexattr_t mattr; + + pthread_mutexattr_init(&mattr); +#ifdef PTHREAD_MUTEX_ADAPTIVE_NP + pthread_mutexattr_settype(&mattr, PTHREAD_MUTEX_ADAPTIVE_NP); +#endif + if (pthread_mutex_init(lock, &mattr) != 0) + return -1; + return 0; +} + +int +iscsi_spin_lock(iscsi_spin_t * lock) +{ + return pthread_mutex_lock(lock); +} + +int +iscsi_spin_unlock(iscsi_spin_t * lock) +{ + return pthread_mutex_unlock(lock); +} + +/* ARGSUSED1 */ +int +iscsi_spin_lock_irqsave(iscsi_spin_t * lock, uint32_t *flags) +{ + return pthread_mutex_lock(lock); +} + +/* ARGSUSED1 */ +int +iscsi_spin_unlock_irqrestore(iscsi_spin_t * lock, uint32_t *flags) +{ + return pthread_mutex_unlock(lock); +} + +int +iscsi_spin_destroy(iscsi_spin_t * lock) +{ + return pthread_mutex_destroy(lock); +} + + +/* + * Mutex Functions, kernel module doesn't require mutex for locking. + * For thread sync, 'down' & 'up' have been wrapped into condition + * varibles, which is kernel semaphores in kernel module. + */ + +int +iscsi_mutex_init(iscsi_mutex_t * m) +{ + return (pthread_mutex_init(m, NULL) != 0) ? -1 : 0; +} + +int +iscsi_mutex_lock(iscsi_mutex_t * m) +{ + return pthread_mutex_lock(m); +} + +int +iscsi_mutex_unlock(iscsi_mutex_t * m) +{ + return pthread_mutex_unlock(m); +} + +int +iscsi_mutex_destroy(iscsi_mutex_t * m) +{ + return pthread_mutex_destroy(m); +} + +/* + * Condition Functions + */ + +int +iscsi_cond_init(iscsi_cond_t * c) +{ + return pthread_cond_init(c, NULL); +} + +int +iscsi_cond_wait(iscsi_cond_t * c, iscsi_mutex_t * m) +{ + return pthread_cond_wait(c, m); +} + +int +iscsi_cond_signal(iscsi_cond_t * c) +{ + return pthread_cond_signal(c); +} + +int +iscsi_cond_destroy(iscsi_cond_t * c) +{ + return pthread_cond_destroy(c); +} + +/* + * Misc. Functions + */ + +uint32_t +iscsi_atoi(char *value) +{ + if (value == NULL) { + iscsi_trace_error(__FILE__, __LINE__, "iscsi_atoi() called with NULL value\n"); + return 0; + } + return atoi(value); +} + +static const char HexString[] = "0123456789abcdef"; + +/* get the hex value (subscript) of the character */ +static int +HexStringIndex(const char *s, int c) +{ + const char *cp; + + return (c == '0') ? 0 : ((cp = strchr(s, tolower(c))) == NULL) ? -1 : (int)(cp - s); +} + +int +HexDataToText( + uint8_t *data, uint32_t dataLength, + char *text, uint32_t textLength) +{ + uint32_t n; + + if (!text || textLength == 0) { + return -1; + } + if (!data || dataLength == 0) { + *text = 0x0; + return -1; + } + if (textLength < 3) { + *text = 0x0; + return -1; + } + *text++ = '0'; + *text++ = 'x'; + + textLength -= 2; + + while (dataLength > 0) { + + if (textLength < 3) { + *text = 0x0; + return -1; + } + n = *data++; + dataLength--; + + *text++ = HexString[(n >> 4) & 0xf]; + *text++ = HexString[n & 0xf]; + + textLength -= 2; + } + + *text = 0x0; + + return 0; +} + + +int +HexTextToData( + const char *text, uint32_t textLength, + uint8_t *data, uint32_t dataLength) +{ + int i; + uint32_t n1; + uint32_t n2; + uint32_t len = 0; + + if ((text[0] == '0') && (text[1] != 'x' || text[1] != 'X')) { + /* skip prefix */ + text += 2; + textLength -= 2; + } + if ((textLength % 2) == 1) { + + i = HexStringIndex(HexString, *text++); + if (i < 0) + return -1; /* error, bad character */ + + n2 = i; + + if (dataLength < 1) { + return -1; /* error, too much data */ + } + *data++ = n2; + len++; + } + while (*text != 0x0) { + + if ((i = HexStringIndex(HexString, *text++)) < 0) { + /* error, bad character */ + return -1; + } + + n1 = i; + + if (*text == 0x0) { + /* error, odd string length */ + return -1; + } + + if ((i = HexStringIndex(HexString, *text++)) < 0) { + /* error, bad character */ + return -1; + } + + n2 = i; + + if (len >= dataLength) { + /* error, too much data */ + return len; + } + *data++ = (n1 << 4) | n2; + len++; + } + + return (len == 0) ? -1 : 0; +} + +void +GenRandomData(uint8_t *data, uint32_t length) +{ + unsigned n; + uint32_t r; + + for ( ; length > 0 ; length--) { + + r = rand(); + r = r ^ (r >> 8); + r = r ^ (r >> 4); + n = r & 0x7; + + r = rand(); + r = r ^ (r >> 8); + r = r ^ (r >> 5); + n = (n << 3) | (r & 0x7); + + r = rand(); + r = r ^ (r >> 8); + r = r ^ (r >> 5); + n = (n << 2) | (r & 0x3); + + *data++ = n; + } +} + + +void +cdb2lba(uint32_t *lba, uint16_t *len, uint8_t *cdb) +{ + /* Some platforms (like strongarm) aligns on */ + /* word boundaries. So HTONL and NTOHL won't */ + /* work here. */ + int indian = 1; + + if (*(char *) (void *) &indian) { + /* little endian */ + ((uint8_t *) (void *) lba)[0] = cdb[5]; + ((uint8_t *) (void *) lba)[1] = cdb[4]; + ((uint8_t *) (void *) lba)[2] = cdb[3]; + ((uint8_t *) (void *) lba)[3] = cdb[2]; + ((uint8_t *) (void *) len)[0] = cdb[8]; + ((uint8_t *) (void *) len)[1] = cdb[7]; + } else { + ((uint8_t *) (void *) lba)[0] = cdb[2]; + ((uint8_t *) (void *) lba)[1] = cdb[3]; + ((uint8_t *) (void *) lba)[2] = cdb[4]; + ((uint8_t *) (void *) lba)[3] = cdb[5]; + ((uint8_t *) (void *) len)[0] = cdb[7]; + ((uint8_t *) (void *) len)[1] = cdb[8]; + } +} + +void +lba2cdb(uint8_t *cdb, uint32_t *lba, uint16_t *len) +{ + /* Some platforms (like strongarm) aligns on */ + /* word boundaries. So HTONL and NTOHL won't */ + /* work here. */ + int indian = 1; + + if (*(char *) (void *) &indian) { + /* little endian */ + cdb[2] = ((uint8_t *) (void *)lba)[3]; + cdb[3] = ((uint8_t *) (void *)lba)[2]; + cdb[4] = ((uint8_t *) (void *)lba)[1]; + cdb[5] = ((uint8_t *) (void *)lba)[0]; + cdb[7] = ((uint8_t *) (void *)len)[1]; + cdb[8] = ((uint8_t *) (void *)len)[0]; + } else { + /* big endian */ + cdb[2] = ((uint8_t *) (void *)lba)[2]; + cdb[3] = ((uint8_t *) (void *)lba)[3]; + cdb[4] = ((uint8_t *) (void *)lba)[0]; + cdb[5] = ((uint8_t *) (void *)lba)[1]; + cdb[7] = ((uint8_t *) (void *)len)[0]; + cdb[8] = ((uint8_t *) (void *)len)[1]; + } +} diff --git a/external/bsd/iscsi/dist/src/uuid.c b/external/bsd/iscsi/dist/src/uuid.c new file mode 100644 index 000000000000..f36aaa5e7734 --- /dev/null +++ b/external/bsd/iscsi/dist/src/uuid.c @@ -0,0 +1,100 @@ +/* $NetBSD: uuid.c,v 1.1 2009/06/21 21:20:31 agc Exp $ */ + +/* + * Copyright © 2006 Alistair Crooks. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. 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. + */ +#include "config.h" + +#ifdef HAVE_INTTYPES_H +#include +#endif + +#include + +#ifdef HAVE_SYS_PARAM_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_UUID_H +#include +#endif + +#include "compat.h" +#include "defs.h" + +#ifndef HAVE_UUID_CREATE +/* just fill the struct with random values for now */ +void +uuid_create(uuid_t *uuid, uint32_t *status) +{ + uint64_t ether; + time_t t; + + (void) time(&t); + ether = (random() << 32) | random(); + uuid->time_low = t; + uuid->time_mid = (uint16_t)(random() & 0xffff); + uuid->time_hi_and_version = (uint16_t)(random() & 0xffff); + uuid->clock_seq_low = random() & 0xff; + uuid->clock_seq_hi_and_reserved = random() & 0xff; + (void) memcpy(&uuid->node, ðer, sizeof(uuid->node)); + *status = 0; +} +#endif + +#ifndef HAVE_UUID_TO_STRING +/* convert the struct to a printable string */ +void +uuid_to_string(uuid_t *uuid, char **str, uint32_t *status) +{ + char s[64]; + + (void) snprintf(s, sizeof(s), "%8.8x-%4.4x-%4.4x-%2.2x%2.2x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x", + uuid->time_low, + uuid->time_mid, + uuid->time_hi_and_version, + uuid->clock_seq_hi_and_reserved, + uuid->clock_seq_low, + uuid->node[0], + uuid->node[1], + uuid->node[2], + uuid->node[3], + uuid->node[4], + uuid->node[5]); + *str = strdup(s); + *status = 0; +} +#endif