diff options
-rw-r--r-- | Documentation/scsi/osst.txt | 218 | ||||
-rw-r--r-- | MAINTAINERS | 10 | ||||
-rw-r--r-- | drivers/scsi/Kconfig | 22 | ||||
-rw-r--r-- | drivers/scsi/Makefile | 1 | ||||
-rw-r--r-- | drivers/scsi/osst.c | 6107 | ||||
-rw-r--r-- | drivers/scsi/osst.h | 651 | ||||
-rw-r--r-- | drivers/scsi/osst_detect.h | 7 | ||||
-rw-r--r-- | drivers/scsi/osst_options.h | 107 | ||||
-rw-r--r-- | drivers/scsi/st.c | 6 |
9 files changed, 3 insertions, 7126 deletions
diff --git a/Documentation/scsi/osst.txt b/Documentation/scsi/osst.txt deleted file mode 100644 index 00c8ebb2fd18..000000000000 --- a/Documentation/scsi/osst.txt +++ /dev/null | |||
@@ -1,218 +0,0 @@ | |||
1 | README file for the osst driver | ||
2 | =============================== | ||
3 | (w) Kurt Garloff <garloff@suse.de> 12/2000 | ||
4 | |||
5 | This file describes the osst driver as of version 0.8.x/0.9.x, the released | ||
6 | version of the osst driver. | ||
7 | It is intended to help advanced users to understand the role of osst and to | ||
8 | get them started using (and maybe debugging) it. | ||
9 | It won't address issues like "How do I compile a kernel?" or "How do I load | ||
10 | a module?", as these are too basic. | ||
11 | Once the OnStream got merged into the official kernel, the distro makers | ||
12 | will provide the OnStream support for those who are not familiar with | ||
13 | hacking their kernels. | ||
14 | |||
15 | |||
16 | Purpose | ||
17 | ------- | ||
18 | The osst driver was developed, because the standard SCSI tape driver in | ||
19 | Linux, st, does not support the OnStream SC-x0 SCSI tape. The st is not to | ||
20 | blame for that, as the OnStream tape drives do not support the standard SCSI | ||
21 | command set for Serial Access Storage Devices (SASDs), which basically | ||
22 | corresponds to the QIC-157 spec. | ||
23 | Nevertheless, the OnStream tapes are nice pieces of hardware and therefore | ||
24 | the osst driver has been written to make these tape devs supported by Linux. | ||
25 | The driver is free software. It's released under the GNU GPL and planned to | ||
26 | be integrated into the mainstream kernel. | ||
27 | |||
28 | |||
29 | Implementation | ||
30 | -------------- | ||
31 | The osst is a new high-level SCSI driver, just like st, sr, sd and sg. It | ||
32 | can be compiled into the kernel or loaded as a module. | ||
33 | As it represents a new device, it got assigned a new device node: /dev/osstX | ||
34 | are character devices with major no 206 and minor numbers like the /dev/stX | ||
35 | devices. If those are not present, you may create them by calling | ||
36 | Makedevs.sh as root (see below). | ||
37 | The driver started being a copy of st and as such, the osst devices' | ||
38 | behavior looks very much the same as st to the userspace applications. | ||
39 | |||
40 | |||
41 | History | ||
42 | ------- | ||
43 | In the first place, osst shared its identity very much with st. That meant | ||
44 | that it used the same kernel structures and the same device node as st. | ||
45 | So you could only have either of them being present in the kernel. This has | ||
46 | been fixed by registering an own device, now. | ||
47 | st and osst can coexist, each only accessing the devices it can support by | ||
48 | themselves. | ||
49 | |||
50 | |||
51 | Installation | ||
52 | ------------ | ||
53 | osst got integrated into the linux kernel. Select it during kernel | ||
54 | configuration as module or compile statically into the kernel. | ||
55 | Compile your kernel and install the modules. | ||
56 | |||
57 | Now, your osst driver is inside the kernel or available as a module, | ||
58 | depending on your choice during kernel config. You may still need to create | ||
59 | the device nodes by calling the Makedevs.sh script (see below) manually. | ||
60 | |||
61 | To load your module, you may use the command | ||
62 | modprobe osst | ||
63 | as root. dmesg should show you, whether your OnStream tapes have been | ||
64 | recognized. | ||
65 | |||
66 | If you want to have the module autoloaded on access to /dev/osst, you may | ||
67 | add something like | ||
68 | alias char-major-206 osst | ||
69 | to a file under /etc/modprobe.d/ directory. | ||
70 | |||
71 | You may find it convenient to create a symbolic link | ||
72 | ln -s nosst0 /dev/tape | ||
73 | to make programs assuming a default name of /dev/tape more convenient to | ||
74 | use. | ||
75 | |||
76 | The device nodes for osst have to be created. Use the Makedevs.sh script | ||
77 | attached to this file. | ||
78 | |||
79 | |||
80 | Using it | ||
81 | -------- | ||
82 | You may use the OnStream tape driver with your standard backup software, | ||
83 | which may be tar, cpio, amanda, arkeia, BRU, Lone Tar, ... | ||
84 | by specifying /dev/(n)osst0 as the tape device to use or using the above | ||
85 | symlink trick. The IOCTLs to control tape operation are also mostly | ||
86 | supported and you may try the mt (or mt_st) program to jump between | ||
87 | filemarks, eject the tape, ... | ||
88 | |||
89 | There's one limitation: You need to use a block size of 32kB. | ||
90 | |||
91 | (This limitation is worked on and will be fixed in version 0.8.8 of | ||
92 | this driver.) | ||
93 | |||
94 | If you just want to get started with standard software, here is an example | ||
95 | for creating and restoring a full backup: | ||
96 | # Backup | ||
97 | tar cvf - / --exclude /proc | buffer -s 32k -m 24M -B -t -o /dev/nosst0 | ||
98 | # Restore | ||
99 | buffer -s 32k -m 8M -B -t -i /dev/osst0 | tar xvf - -C / | ||
100 | |||
101 | The buffer command has been used to buffer the data before it goes to the | ||
102 | tape (or the file system) in order to smooth out the data stream and prevent | ||
103 | the tape from needing to stop and rewind. The OnStream does have an internal | ||
104 | buffer and a variable speed which help this, but especially on writing, the | ||
105 | buffering still proves useful in most cases. It also pads the data to | ||
106 | guarantees the block size of 32k. (Otherwise you may pass the -b64 option to | ||
107 | tar.) | ||
108 | Expect something like 1.8MB/s for the SC-x0 drives and 0.9MB/s for the DI-30. | ||
109 | The USB drive will give you about 0.7MB/s. | ||
110 | On a fast machine, you may profit from software data compression (z flag for | ||
111 | tar). | ||
112 | |||
113 | |||
114 | USB and IDE | ||
115 | ----------- | ||
116 | Via the SCSI emulation layers usb-storage and ide-scsi, you can also use the | ||
117 | osst driver to drive the USB-30 and the DI-30 drives. (Unfortunately, there | ||
118 | is no such layer for the parallel port, otherwise the DP-30 would work as | ||
119 | well.) For the USB support, you need the latest 2.4.0-test kernels and the | ||
120 | latest usb-storage driver from | ||
121 | http://www.linux-usb.org/ | ||
122 | http://sourceforge.net/cvs/?group_id=3581 | ||
123 | |||
124 | Note that the ide-tape driver as of 1.16f uses a slightly outdated on-tape | ||
125 | format and therefore is not completely interoperable with osst tapes. | ||
126 | |||
127 | The ADR-x0 line is fully SCSI-2 compliant and is supported by st, not osst. | ||
128 | The on-tape format is supposed to be compatible with the one used by osst. | ||
129 | |||
130 | |||
131 | Feedback and updates | ||
132 | -------------------- | ||
133 | The driver development is coordinated through a mailing list | ||
134 | <osst@linux1.onstream.nl> | ||
135 | a CVS repository and some web pages. | ||
136 | The tester's pages which contain recent news and updated drivers to download | ||
137 | can be found on | ||
138 | http://sourceforge.net/projects/osst/ | ||
139 | |||
140 | If you find any problems, please have a look at the tester's page in order | ||
141 | to see whether the problem is already known and solved. Otherwise, please | ||
142 | report it to the mailing list. Your feedback is welcome. (This holds also | ||
143 | for reports of successful usage, of course.) | ||
144 | In case of trouble, please do always provide the following info: | ||
145 | * driver and kernel version used (see syslog) | ||
146 | * driver messages (syslog) | ||
147 | * SCSI config and OnStream Firmware (/proc/scsi/scsi) | ||
148 | * description of error. Is it reproducible? | ||
149 | * software and commands used | ||
150 | |||
151 | You may subscribe to the mailing list, BTW, it's a majordomo list. | ||
152 | |||
153 | |||
154 | Status | ||
155 | ------ | ||
156 | 0.8.0 was the first widespread BETA release. Since then a lot of reports | ||
157 | have been sent, but mostly reported success or only minor trouble. | ||
158 | All the issues have been addressed. | ||
159 | Check the web pages for more info about the current developments. | ||
160 | 0.9.x is the tree for the 2.3/2.4 kernel. | ||
161 | |||
162 | |||
163 | Acknowledgments | ||
164 | ---------------- | ||
165 | The driver has been started by making a copy of Kai Makisara's st driver. | ||
166 | Most of the development has been done by Willem Riede. The presence of the | ||
167 | userspace program osg (onstreamsg) from Terry Hardie has been rather | ||
168 | helpful. The same holds for Gadi Oxman's ide-tape support for the DI-30. | ||
169 | I did add some patches to those drivers as well and coordinated things a | ||
170 | little bit. | ||
171 | Note that most of them did mostly spend their spare time for the creation of | ||
172 | this driver. | ||
173 | The people from OnStream, especially Jack Bombeeck did support this project | ||
174 | and always tried to answer HW or FW related questions. Furthermore, he | ||
175 | pushed the FW developers to do the right things. | ||
176 | SuSE did support this project by allowing me to work on it during my working | ||
177 | time for them and by integrating the driver into their distro. | ||
178 | |||
179 | More people did help by sending useful comments. Sorry to those who have | ||
180 | been forgotten. Thanks to all the GNU/FSF and Linux developers who made this | ||
181 | platform such an interesting, nice and stable platform. | ||
182 | Thanks go to those who tested the drivers and did send useful reports. Your | ||
183 | help is needed! | ||
184 | |||
185 | |||
186 | Makedevs.sh | ||
187 | ----------- | ||
188 | #!/bin/sh | ||
189 | # Script to create OnStream SC-x0 device nodes (major 206) | ||
190 | # Usage: Makedevs.sh [nos [path to dev]] | ||
191 | # $Id: README.osst.kernel,v 1.4 2000/12/20 14:13:15 garloff Exp $ | ||
192 | major=206 | ||
193 | nrs=4 | ||
194 | dir=/dev | ||
195 | test -z "$1" || nrs=$1 | ||
196 | test -z "$2" || dir=$2 | ||
197 | declare -i nr | ||
198 | nr=0 | ||
199 | test -d $dir || mkdir -p $dir | ||
200 | while test $nr -lt $nrs; do | ||
201 | mknod $dir/osst$nr c $major $nr | ||
202 | chown 0.disk $dir/osst$nr; chmod 660 $dir/osst$nr; | ||
203 | mknod $dir/nosst$nr c $major $[nr+128] | ||
204 | chown 0.disk $dir/nosst$nr; chmod 660 $dir/nosst$nr; | ||
205 | mknod $dir/osst${nr}l c $major $[nr+32] | ||
206 | chown 0.disk $dir/osst${nr}l; chmod 660 $dir/osst${nr}l; | ||
207 | mknod $dir/nosst${nr}l c $major $[nr+160] | ||
208 | chown 0.disk $dir/nosst${nr}l; chmod 660 $dir/nosst${nr}l; | ||
209 | mknod $dir/osst${nr}m c $major $[nr+64] | ||
210 | chown 0.disk $dir/osst${nr}m; chmod 660 $dir/osst${nr}m; | ||
211 | mknod $dir/nosst${nr}m c $major $[nr+192] | ||
212 | chown 0.disk $dir/nosst${nr}m; chmod 660 $dir/nosst${nr}m; | ||
213 | mknod $dir/osst${nr}a c $major $[nr+96] | ||
214 | chown 0.disk $dir/osst${nr}a; chmod 660 $dir/osst${nr}a; | ||
215 | mknod $dir/nosst${nr}a c $major $[nr+224] | ||
216 | chown 0.disk $dir/nosst${nr}a; chmod 660 $dir/nosst${nr}a; | ||
217 | let nr+=1 | ||
218 | done | ||
diff --git a/MAINTAINERS b/MAINTAINERS index 5cfbea4ce575..adfb7ffb40ca 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -11662,16 +11662,6 @@ S: Maintained | |||
11662 | F: drivers/mtd/nand/onenand/ | 11662 | F: drivers/mtd/nand/onenand/ |
11663 | F: include/linux/mtd/onenand*.h | 11663 | F: include/linux/mtd/onenand*.h |
11664 | 11664 | ||
11665 | ONSTREAM SCSI TAPE DRIVER | ||
11666 | M: Willem Riede <osst@riede.org> | ||
11667 | L: osst-users@lists.sourceforge.net | ||
11668 | L: linux-scsi@vger.kernel.org | ||
11669 | S: Maintained | ||
11670 | F: Documentation/scsi/osst.txt | ||
11671 | F: drivers/scsi/osst.* | ||
11672 | F: drivers/scsi/osst_*.h | ||
11673 | F: drivers/scsi/st.h | ||
11674 | |||
11675 | OP-TEE DRIVER | 11665 | OP-TEE DRIVER |
11676 | M: Jens Wiklander <jens.wiklander@linaro.org> | 11666 | M: Jens Wiklander <jens.wiklander@linaro.org> |
11677 | S: Maintained | 11667 | S: Maintained |
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index d528018e6fa8..d81edb6ae9e3 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -98,28 +98,6 @@ config CHR_DEV_ST | |||
98 | To compile this driver as a module, choose M here and read | 98 | To compile this driver as a module, choose M here and read |
99 | <file:Documentation/scsi/scsi.txt>. The module will be called st. | 99 | <file:Documentation/scsi/scsi.txt>. The module will be called st. |
100 | 100 | ||
101 | config CHR_DEV_OSST | ||
102 | tristate "SCSI OnStream SC-x0 tape support" | ||
103 | depends on SCSI | ||
104 | ---help--- | ||
105 | The OnStream SC-x0 SCSI tape drives cannot be driven by the | ||
106 | standard st driver, but instead need this special osst driver and | ||
107 | use the /dev/osstX char device nodes (major 206). Via usb-storage, | ||
108 | you may be able to drive the USB-x0 and DI-x0 drives as well. | ||
109 | Note that there is also a second generation of OnStream | ||
110 | tape drives (ADR-x0) that supports the standard SCSI-2 commands for | ||
111 | tapes (QIC-157) and can be driven by the standard driver st. | ||
112 | For more information, you may have a look at the SCSI-HOWTO | ||
113 | <http://www.tldp.org/docs.html#howto> and | ||
114 | <file:Documentation/scsi/osst.txt> in the kernel source. | ||
115 | More info on the OnStream driver may be found on | ||
116 | <http://sourceforge.net/projects/osst/> | ||
117 | Please also have a look at the standard st docu, as most of it | ||
118 | applies to osst as well. | ||
119 | |||
120 | To compile this driver as a module, choose M here and read | ||
121 | <file:Documentation/scsi/scsi.txt>. The module will be called osst. | ||
122 | |||
123 | config BLK_DEV_SR | 101 | config BLK_DEV_SR |
124 | tristate "SCSI CDROM support" | 102 | tristate "SCSI CDROM support" |
125 | depends on SCSI && BLK_DEV | 103 | depends on SCSI && BLK_DEV |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index 8826111fdf4a..f69ee35af2c8 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -143,7 +143,6 @@ obj-$(CONFIG_SCSI_WD719X) += wd719x.o | |||
143 | obj-$(CONFIG_ARM) += arm/ | 143 | obj-$(CONFIG_ARM) += arm/ |
144 | 144 | ||
145 | obj-$(CONFIG_CHR_DEV_ST) += st.o | 145 | obj-$(CONFIG_CHR_DEV_ST) += st.o |
146 | obj-$(CONFIG_CHR_DEV_OSST) += osst.o | ||
147 | obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o | 146 | obj-$(CONFIG_BLK_DEV_SD) += sd_mod.o |
148 | obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o | 147 | obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o |
149 | obj-$(CONFIG_CHR_DEV_SG) += sg.o | 148 | obj-$(CONFIG_CHR_DEV_SG) += sg.o |
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c deleted file mode 100644 index 4bad54463eb2..000000000000 --- a/drivers/scsi/osst.c +++ /dev/null | |||
@@ -1,6107 +0,0 @@ | |||
1 | /* | ||
2 | SCSI Tape Driver for Linux version 1.1 and newer. See the accompanying | ||
3 | file Documentation/scsi/st.txt for more information. | ||
4 | |||
5 | History: | ||
6 | |||
7 | OnStream SCSI Tape support (osst) cloned from st.c by | ||
8 | Willem Riede (osst@riede.org) Feb 2000 | ||
9 | Fixes ... Kurt Garloff <garloff@suse.de> Mar 2000 | ||
10 | |||
11 | Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. | ||
12 | Contribution and ideas from several people including (in alphabetical | ||
13 | order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, | ||
14 | Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. | ||
15 | |||
16 | Copyright 1992 - 2002 Kai Makisara / 2000 - 2006 Willem Riede | ||
17 | email osst@riede.org | ||
18 | |||
19 | $Header: /cvsroot/osst/Driver/osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $ | ||
20 | |||
21 | Microscopic alterations - Rik Ling, 2000/12/21 | ||
22 | Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara | ||
23 | Some small formal changes - aeb, 950809 | ||
24 | */ | ||
25 | |||
26 | static const char * cvsid = "$Id: osst.c,v 1.73 2005/01/01 21:13:34 wriede Exp $"; | ||
27 | static const char * osst_version = "0.99.4"; | ||
28 | |||
29 | /* The "failure to reconnect" firmware bug */ | ||
30 | #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ | ||
31 | #define OSST_FW_NEED_POLL_MAX 10704 /*(108D)*/ | ||
32 | #define OSST_FW_NEED_POLL(x,d) ((x) >= OSST_FW_NEED_POLL_MIN && (x) <= OSST_FW_NEED_POLL_MAX && d->host->this_id != 7) | ||
33 | |||
34 | #include <linux/module.h> | ||
35 | |||
36 | #include <linux/fs.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/sched/signal.h> | ||
39 | #include <linux/proc_fs.h> | ||
40 | #include <linux/mm.h> | ||
41 | #include <linux/slab.h> | ||
42 | #include <linux/init.h> | ||
43 | #include <linux/string.h> | ||
44 | #include <linux/errno.h> | ||
45 | #include <linux/mtio.h> | ||
46 | #include <linux/ioctl.h> | ||
47 | #include <linux/fcntl.h> | ||
48 | #include <linux/spinlock.h> | ||
49 | #include <linux/vmalloc.h> | ||
50 | #include <linux/blkdev.h> | ||
51 | #include <linux/moduleparam.h> | ||
52 | #include <linux/delay.h> | ||
53 | #include <linux/jiffies.h> | ||
54 | #include <linux/mutex.h> | ||
55 | #include <linux/uaccess.h> | ||
56 | #include <asm/dma.h> | ||
57 | |||
58 | /* The driver prints some debugging information on the console if DEBUG | ||
59 | is defined and non-zero. */ | ||
60 | #define DEBUG 0 | ||
61 | |||
62 | /* The message level for the debug messages is currently set to KERN_NOTICE | ||
63 | so that people can easily see the messages. Later when the debugging messages | ||
64 | in the drivers are more widely classified, this may be changed to KERN_DEBUG. */ | ||
65 | #define OSST_DEB_MSG KERN_NOTICE | ||
66 | |||
67 | #include <scsi/scsi.h> | ||
68 | #include <scsi/scsi_dbg.h> | ||
69 | #include <scsi/scsi_device.h> | ||
70 | #include <scsi/scsi_driver.h> | ||
71 | #include <scsi/scsi_eh.h> | ||
72 | #include <scsi/scsi_host.h> | ||
73 | #include <scsi/scsi_ioctl.h> | ||
74 | |||
75 | #define ST_KILOBYTE 1024 | ||
76 | |||
77 | #include "st.h" | ||
78 | #include "osst.h" | ||
79 | #include "osst_options.h" | ||
80 | #include "osst_detect.h" | ||
81 | |||
82 | static DEFINE_MUTEX(osst_int_mutex); | ||
83 | static int max_dev = 0; | ||
84 | static int write_threshold_kbs = 0; | ||
85 | static int max_sg_segs = 0; | ||
86 | |||
87 | #ifdef MODULE | ||
88 | MODULE_AUTHOR("Willem Riede"); | ||
89 | MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver"); | ||
90 | MODULE_LICENSE("GPL"); | ||
91 | MODULE_ALIAS_CHARDEV_MAJOR(OSST_MAJOR); | ||
92 | MODULE_ALIAS_SCSI_DEVICE(TYPE_TAPE); | ||
93 | |||
94 | module_param(max_dev, int, 0444); | ||
95 | MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)"); | ||
96 | |||
97 | module_param(write_threshold_kbs, int, 0644); | ||
98 | MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 32)"); | ||
99 | |||
100 | module_param(max_sg_segs, int, 0644); | ||
101 | MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)"); | ||
102 | #else | ||
103 | static struct osst_dev_parm { | ||
104 | char *name; | ||
105 | int *val; | ||
106 | } parms[] __initdata = { | ||
107 | { "max_dev", &max_dev }, | ||
108 | { "write_threshold_kbs", &write_threshold_kbs }, | ||
109 | { "max_sg_segs", &max_sg_segs } | ||
110 | }; | ||
111 | #endif | ||
112 | |||
113 | /* Some default definitions have been moved to osst_options.h */ | ||
114 | #define OSST_BUFFER_SIZE (OSST_BUFFER_BLOCKS * ST_KILOBYTE) | ||
115 | #define OSST_WRITE_THRESHOLD (OSST_WRITE_THRESHOLD_BLOCKS * ST_KILOBYTE) | ||
116 | |||
117 | /* The buffer size should fit into the 24 bits for length in the | ||
118 | 6-byte SCSI read and write commands. */ | ||
119 | #if OSST_BUFFER_SIZE >= (2 << 24 - 1) | ||
120 | #error "Buffer size should not exceed (2 << 24 - 1) bytes!" | ||
121 | #endif | ||
122 | |||
123 | #if DEBUG | ||
124 | static int debugging = 1; | ||
125 | /* uncomment define below to test error recovery */ | ||
126 | // #define OSST_INJECT_ERRORS 1 | ||
127 | #endif | ||
128 | |||
129 | /* Do not retry! The drive firmware already retries when appropriate, | ||
130 | and when it tries to tell us something, we had better listen... */ | ||
131 | #define MAX_RETRIES 0 | ||
132 | |||
133 | #define NO_TAPE NOT_READY | ||
134 | |||
135 | #define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1) | ||
136 | #define OSST_WAIT_WRITE_COMPLETE (HZ / 12) | ||
137 | #define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2) | ||
138 | |||
139 | #define OSST_TIMEOUT (200 * HZ) | ||
140 | #define OSST_LONG_TIMEOUT (1800 * HZ) | ||
141 | |||
142 | #define TAPE_NR(x) (iminor(x) & ((1 << ST_MODE_SHIFT)-1)) | ||
143 | #define TAPE_MODE(x) ((iminor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) | ||
144 | #define TAPE_REWIND(x) ((iminor(x) & 0x80) == 0) | ||
145 | #define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1)) | ||
146 | |||
147 | /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower | ||
148 | 24 bits) */ | ||
149 | #define SET_DENS_AND_BLK 0x10001 | ||
150 | |||
151 | static int osst_buffer_size = OSST_BUFFER_SIZE; | ||
152 | static int osst_write_threshold = OSST_WRITE_THRESHOLD; | ||
153 | static int osst_max_sg_segs = OSST_MAX_SG; | ||
154 | static int osst_max_dev = OSST_MAX_TAPES; | ||
155 | static int osst_nr_dev; | ||
156 | |||
157 | static struct osst_tape **os_scsi_tapes = NULL; | ||
158 | static DEFINE_RWLOCK(os_scsi_tapes_lock); | ||
159 | |||
160 | static int modes_defined = 0; | ||
161 | |||
162 | static struct osst_buffer *new_tape_buffer(int, int, int); | ||
163 | static int enlarge_buffer(struct osst_buffer *, int); | ||
164 | static void normalize_buffer(struct osst_buffer *); | ||
165 | static int append_to_buffer(const char __user *, struct osst_buffer *, int); | ||
166 | static int from_buffer(struct osst_buffer *, char __user *, int); | ||
167 | static int osst_zero_buffer_tail(struct osst_buffer *); | ||
168 | static int osst_copy_to_buffer(struct osst_buffer *, unsigned char *); | ||
169 | static int osst_copy_from_buffer(struct osst_buffer *, unsigned char *); | ||
170 | |||
171 | static int osst_probe(struct device *); | ||
172 | static int osst_remove(struct device *); | ||
173 | |||
174 | static struct scsi_driver osst_template = { | ||
175 | .gendrv = { | ||
176 | .name = "osst", | ||
177 | .owner = THIS_MODULE, | ||
178 | .probe = osst_probe, | ||
179 | .remove = osst_remove, | ||
180 | } | ||
181 | }; | ||
182 | |||
183 | static int osst_int_ioctl(struct osst_tape *STp, struct osst_request ** aSRpnt, | ||
184 | unsigned int cmd_in, unsigned long arg); | ||
185 | |||
186 | static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int frame, int skip); | ||
187 | |||
188 | static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt); | ||
189 | |||
190 | static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt); | ||
191 | |||
192 | static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending); | ||
193 | |||
194 | static inline char *tape_name(struct osst_tape *tape) | ||
195 | { | ||
196 | return tape->drive->disk_name; | ||
197 | } | ||
198 | |||
199 | /* Routines that handle the interaction with mid-layer SCSI routines */ | ||
200 | |||
201 | |||
202 | /* Normalize Sense */ | ||
203 | static void osst_analyze_sense(struct osst_request *SRpnt, struct st_cmdstatus *s) | ||
204 | { | ||
205 | const u8 *ucp; | ||
206 | const u8 *sense = SRpnt->sense; | ||
207 | |||
208 | s->have_sense = scsi_normalize_sense(SRpnt->sense, | ||
209 | SCSI_SENSE_BUFFERSIZE, &s->sense_hdr); | ||
210 | s->flags = 0; | ||
211 | |||
212 | if (s->have_sense) { | ||
213 | s->deferred = 0; | ||
214 | s->remainder_valid = | ||
215 | scsi_get_sense_info_fld(sense, SCSI_SENSE_BUFFERSIZE, &s->uremainder64); | ||
216 | switch (sense[0] & 0x7f) { | ||
217 | case 0x71: | ||
218 | s->deferred = 1; | ||
219 | /* fall through */ | ||
220 | case 0x70: | ||
221 | s->fixed_format = 1; | ||
222 | s->flags = sense[2] & 0xe0; | ||
223 | break; | ||
224 | case 0x73: | ||
225 | s->deferred = 1; | ||
226 | /* fall through */ | ||
227 | case 0x72: | ||
228 | s->fixed_format = 0; | ||
229 | ucp = scsi_sense_desc_find(sense, SCSI_SENSE_BUFFERSIZE, 4); | ||
230 | s->flags = ucp ? (ucp[3] & 0xe0) : 0; | ||
231 | break; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* Convert the result to success code */ | ||
237 | static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt) | ||
238 | { | ||
239 | char *name = tape_name(STp); | ||
240 | int result = SRpnt->result; | ||
241 | u8 * sense = SRpnt->sense, scode; | ||
242 | #if DEBUG | ||
243 | const char *stp; | ||
244 | #endif | ||
245 | struct st_cmdstatus *cmdstatp; | ||
246 | |||
247 | if (!result) | ||
248 | return 0; | ||
249 | |||
250 | cmdstatp = &STp->buffer->cmdstat; | ||
251 | osst_analyze_sense(SRpnt, cmdstatp); | ||
252 | |||
253 | if (cmdstatp->have_sense) | ||
254 | scode = STp->buffer->cmdstat.sense_hdr.sense_key; | ||
255 | else | ||
256 | scode = 0; | ||
257 | #if DEBUG | ||
258 | if (debugging) { | ||
259 | printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x\n", | ||
260 | name, result, | ||
261 | SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2], | ||
262 | SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]); | ||
263 | if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n", | ||
264 | name, scode, sense[12], sense[13]); | ||
265 | if (cmdstatp->have_sense) | ||
266 | __scsi_print_sense(STp->device, name, | ||
267 | SRpnt->sense, SCSI_SENSE_BUFFERSIZE); | ||
268 | } | ||
269 | else | ||
270 | #endif | ||
271 | if (cmdstatp->have_sense && ( | ||
272 | scode != NO_SENSE && | ||
273 | scode != RECOVERED_ERROR && | ||
274 | /* scode != UNIT_ATTENTION && */ | ||
275 | scode != BLANK_CHECK && | ||
276 | scode != VOLUME_OVERFLOW && | ||
277 | SRpnt->cmd[0] != MODE_SENSE && | ||
278 | SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */ | ||
279 | if (cmdstatp->have_sense) { | ||
280 | printk(KERN_WARNING "%s:W: Command with sense data:\n", name); | ||
281 | __scsi_print_sense(STp->device, name, | ||
282 | SRpnt->sense, SCSI_SENSE_BUFFERSIZE); | ||
283 | } | ||
284 | else { | ||
285 | static int notyetprinted = 1; | ||
286 | |||
287 | printk(KERN_WARNING | ||
288 | "%s:W: Warning %x (driver bt 0x%x, host bt 0x%x).\n", | ||
289 | name, result, driver_byte(result), | ||
290 | host_byte(result)); | ||
291 | if (notyetprinted) { | ||
292 | notyetprinted = 0; | ||
293 | printk(KERN_INFO | ||
294 | "%s:I: This warning may be caused by your scsi controller,\n", name); | ||
295 | printk(KERN_INFO | ||
296 | "%s:I: it has been reported with some Buslogic cards.\n", name); | ||
297 | } | ||
298 | } | ||
299 | } | ||
300 | STp->pos_unknown |= STp->device->was_reset; | ||
301 | |||
302 | if (cmdstatp->have_sense && scode == RECOVERED_ERROR) { | ||
303 | STp->recover_count++; | ||
304 | STp->recover_erreg++; | ||
305 | #if DEBUG | ||
306 | if (debugging) { | ||
307 | if (SRpnt->cmd[0] == READ_6) | ||
308 | stp = "read"; | ||
309 | else if (SRpnt->cmd[0] == WRITE_6) | ||
310 | stp = "write"; | ||
311 | else | ||
312 | stp = "ioctl"; | ||
313 | printk(OSST_DEB_MSG "%s:D: Recovered %s error (%d).\n", name, stp, | ||
314 | STp->recover_count); | ||
315 | } | ||
316 | #endif | ||
317 | if ((sense[2] & 0xe0) == 0) | ||
318 | return 0; | ||
319 | } | ||
320 | return (-EIO); | ||
321 | } | ||
322 | |||
323 | |||
324 | /* Wakeup from interrupt */ | ||
325 | static void osst_end_async(struct request *req, blk_status_t status) | ||
326 | { | ||
327 | struct scsi_request *rq = scsi_req(req); | ||
328 | struct osst_request *SRpnt = req->end_io_data; | ||
329 | struct osst_tape *STp = SRpnt->stp; | ||
330 | struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; | ||
331 | |||
332 | STp->buffer->cmdstat.midlevel_result = SRpnt->result = rq->result; | ||
333 | #if DEBUG | ||
334 | STp->write_pending = 0; | ||
335 | #endif | ||
336 | if (rq->sense_len) | ||
337 | memcpy(SRpnt->sense, rq->sense, SCSI_SENSE_BUFFERSIZE); | ||
338 | if (SRpnt->waiting) | ||
339 | complete(SRpnt->waiting); | ||
340 | |||
341 | if (SRpnt->bio) { | ||
342 | kfree(mdata->pages); | ||
343 | blk_rq_unmap_user(SRpnt->bio); | ||
344 | } | ||
345 | |||
346 | blk_put_request(req); | ||
347 | } | ||
348 | |||
349 | /* osst_request memory management */ | ||
350 | static struct osst_request *osst_allocate_request(void) | ||
351 | { | ||
352 | return kzalloc(sizeof(struct osst_request), GFP_KERNEL); | ||
353 | } | ||
354 | |||
355 | static void osst_release_request(struct osst_request *streq) | ||
356 | { | ||
357 | kfree(streq); | ||
358 | } | ||
359 | |||
360 | static int osst_execute(struct osst_request *SRpnt, const unsigned char *cmd, | ||
361 | int cmd_len, int data_direction, void *buffer, unsigned bufflen, | ||
362 | int use_sg, int timeout, int retries) | ||
363 | { | ||
364 | struct request *req; | ||
365 | struct scsi_request *rq; | ||
366 | struct page **pages = NULL; | ||
367 | struct rq_map_data *mdata = &SRpnt->stp->buffer->map_data; | ||
368 | |||
369 | int err = 0; | ||
370 | int write = (data_direction == DMA_TO_DEVICE); | ||
371 | |||
372 | req = blk_get_request(SRpnt->stp->device->request_queue, | ||
373 | write ? REQ_OP_SCSI_OUT : REQ_OP_SCSI_IN, 0); | ||
374 | if (IS_ERR(req)) | ||
375 | return DRIVER_ERROR << 24; | ||
376 | |||
377 | rq = scsi_req(req); | ||
378 | req->rq_flags |= RQF_QUIET; | ||
379 | |||
380 | SRpnt->bio = NULL; | ||
381 | |||
382 | if (use_sg) { | ||
383 | struct scatterlist *sg, *sgl = (struct scatterlist *)buffer; | ||
384 | int i; | ||
385 | |||
386 | pages = kcalloc(use_sg, sizeof(struct page *), GFP_KERNEL); | ||
387 | if (!pages) | ||
388 | goto free_req; | ||
389 | |||
390 | for_each_sg(sgl, sg, use_sg, i) | ||
391 | pages[i] = sg_page(sg); | ||
392 | |||
393 | mdata->null_mapped = 1; | ||
394 | |||
395 | mdata->page_order = get_order(sgl[0].length); | ||
396 | mdata->nr_entries = | ||
397 | DIV_ROUND_UP(bufflen, PAGE_SIZE << mdata->page_order); | ||
398 | mdata->offset = 0; | ||
399 | |||
400 | err = blk_rq_map_user(req->q, req, mdata, NULL, bufflen, GFP_KERNEL); | ||
401 | if (err) { | ||
402 | kfree(pages); | ||
403 | goto free_req; | ||
404 | } | ||
405 | SRpnt->bio = req->bio; | ||
406 | mdata->pages = pages; | ||
407 | |||
408 | } else if (bufflen) { | ||
409 | err = blk_rq_map_kern(req->q, req, buffer, bufflen, GFP_KERNEL); | ||
410 | if (err) | ||
411 | goto free_req; | ||
412 | } | ||
413 | |||
414 | rq->cmd_len = cmd_len; | ||
415 | memset(rq->cmd, 0, BLK_MAX_CDB); /* ATAPI hates garbage after CDB */ | ||
416 | memcpy(rq->cmd, cmd, rq->cmd_len); | ||
417 | req->timeout = timeout; | ||
418 | rq->retries = retries; | ||
419 | req->end_io_data = SRpnt; | ||
420 | |||
421 | blk_execute_rq_nowait(req->q, NULL, req, 1, osst_end_async); | ||
422 | return 0; | ||
423 | free_req: | ||
424 | blk_put_request(req); | ||
425 | return DRIVER_ERROR << 24; | ||
426 | } | ||
427 | |||
428 | /* Do the scsi command. Waits until command performed if do_wait is true. | ||
429 | Otherwise osst_write_behind_check() is used to check that the command | ||
430 | has finished. */ | ||
431 | static struct osst_request * osst_do_scsi(struct osst_request *SRpnt, struct osst_tape *STp, | ||
432 | unsigned char *cmd, int bytes, int direction, int timeout, int retries, int do_wait) | ||
433 | { | ||
434 | unsigned char *bp; | ||
435 | unsigned short use_sg; | ||
436 | #ifdef OSST_INJECT_ERRORS | ||
437 | static int inject = 0; | ||
438 | static int repeat = 0; | ||
439 | #endif | ||
440 | struct completion *waiting; | ||
441 | |||
442 | /* if async, make sure there's no command outstanding */ | ||
443 | if (!do_wait && ((STp->buffer)->last_SRpnt)) { | ||
444 | printk(KERN_ERR "%s: Async command already active.\n", | ||
445 | tape_name(STp)); | ||
446 | if (signal_pending(current)) | ||
447 | (STp->buffer)->syscall_result = (-EINTR); | ||
448 | else | ||
449 | (STp->buffer)->syscall_result = (-EBUSY); | ||
450 | return NULL; | ||
451 | } | ||
452 | |||
453 | if (SRpnt == NULL) { | ||
454 | SRpnt = osst_allocate_request(); | ||
455 | if (SRpnt == NULL) { | ||
456 | printk(KERN_ERR "%s: Can't allocate SCSI request.\n", | ||
457 | tape_name(STp)); | ||
458 | if (signal_pending(current)) | ||
459 | (STp->buffer)->syscall_result = (-EINTR); | ||
460 | else | ||
461 | (STp->buffer)->syscall_result = (-EBUSY); | ||
462 | return NULL; | ||
463 | } | ||
464 | SRpnt->stp = STp; | ||
465 | } | ||
466 | |||
467 | /* If async IO, set last_SRpnt. This ptr tells write_behind_check | ||
468 | which IO is outstanding. It's nulled out when the IO completes. */ | ||
469 | if (!do_wait) | ||
470 | (STp->buffer)->last_SRpnt = SRpnt; | ||
471 | |||
472 | waiting = &STp->wait; | ||
473 | init_completion(waiting); | ||
474 | SRpnt->waiting = waiting; | ||
475 | |||
476 | use_sg = (bytes > STp->buffer->sg[0].length) ? STp->buffer->use_sg : 0; | ||
477 | if (use_sg) { | ||
478 | bp = (char *)&(STp->buffer->sg[0]); | ||
479 | if (STp->buffer->sg_segs < use_sg) | ||
480 | use_sg = STp->buffer->sg_segs; | ||
481 | } | ||
482 | else | ||
483 | bp = (STp->buffer)->b_data; | ||
484 | |||
485 | memcpy(SRpnt->cmd, cmd, sizeof(SRpnt->cmd)); | ||
486 | STp->buffer->cmdstat.have_sense = 0; | ||
487 | STp->buffer->syscall_result = 0; | ||
488 | |||
489 | if (osst_execute(SRpnt, cmd, COMMAND_SIZE(cmd[0]), direction, bp, bytes, | ||
490 | use_sg, timeout, retries)) | ||
491 | /* could not allocate the buffer or request was too large */ | ||
492 | (STp->buffer)->syscall_result = (-EBUSY); | ||
493 | else if (do_wait) { | ||
494 | wait_for_completion(waiting); | ||
495 | SRpnt->waiting = NULL; | ||
496 | STp->buffer->syscall_result = osst_chk_result(STp, SRpnt); | ||
497 | #ifdef OSST_INJECT_ERRORS | ||
498 | if (STp->buffer->syscall_result == 0 && | ||
499 | cmd[0] == READ_6 && | ||
500 | cmd[4] && | ||
501 | ( (++ inject % 83) == 29 || | ||
502 | (STp->first_frame_position == 240 | ||
503 | /* or STp->read_error_frame to fail again on the block calculated above */ && | ||
504 | ++repeat < 3))) { | ||
505 | printk(OSST_DEB_MSG "%s:D: Injecting read error\n", tape_name(STp)); | ||
506 | STp->buffer->last_result_fatal = 1; | ||
507 | } | ||
508 | #endif | ||
509 | } | ||
510 | return SRpnt; | ||
511 | } | ||
512 | |||
513 | |||
514 | /* Handle the write-behind checking (downs the semaphore) */ | ||
515 | static void osst_write_behind_check(struct osst_tape *STp) | ||
516 | { | ||
517 | struct osst_buffer * STbuffer; | ||
518 | |||
519 | STbuffer = STp->buffer; | ||
520 | |||
521 | #if DEBUG | ||
522 | if (STp->write_pending) | ||
523 | STp->nbr_waits++; | ||
524 | else | ||
525 | STp->nbr_finished++; | ||
526 | #endif | ||
527 | wait_for_completion(&(STp->wait)); | ||
528 | STp->buffer->last_SRpnt->waiting = NULL; | ||
529 | |||
530 | STp->buffer->syscall_result = osst_chk_result(STp, STp->buffer->last_SRpnt); | ||
531 | |||
532 | if (STp->buffer->syscall_result) | ||
533 | STp->buffer->syscall_result = | ||
534 | osst_write_error_recovery(STp, &(STp->buffer->last_SRpnt), 1); | ||
535 | else | ||
536 | STp->first_frame_position++; | ||
537 | |||
538 | osst_release_request(STp->buffer->last_SRpnt); | ||
539 | |||
540 | if (STbuffer->writing < STbuffer->buffer_bytes) | ||
541 | printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n"); | ||
542 | |||
543 | STbuffer->last_SRpnt = NULL; | ||
544 | STbuffer->buffer_bytes -= STbuffer->writing; | ||
545 | STbuffer->writing = 0; | ||
546 | |||
547 | return; | ||
548 | } | ||
549 | |||
550 | |||
551 | |||
552 | /* Onstream specific Routines */ | ||
553 | /* | ||
554 | * Initialize the OnStream AUX | ||
555 | */ | ||
556 | static void osst_init_aux(struct osst_tape * STp, int frame_type, int frame_seq_number, | ||
557 | int logical_blk_num, int blk_sz, int blk_cnt) | ||
558 | { | ||
559 | os_aux_t *aux = STp->buffer->aux; | ||
560 | os_partition_t *par = &aux->partition; | ||
561 | os_dat_t *dat = &aux->dat; | ||
562 | |||
563 | if (STp->raw) return; | ||
564 | |||
565 | memset(aux, 0, sizeof(*aux)); | ||
566 | aux->format_id = htonl(0); | ||
567 | memcpy(aux->application_sig, "LIN4", 4); | ||
568 | aux->hdwr = htonl(0); | ||
569 | aux->frame_type = frame_type; | ||
570 | |||
571 | switch (frame_type) { | ||
572 | case OS_FRAME_TYPE_HEADER: | ||
573 | aux->update_frame_cntr = htonl(STp->update_frame_cntr); | ||
574 | par->partition_num = OS_CONFIG_PARTITION; | ||
575 | par->par_desc_ver = OS_PARTITION_VERSION; | ||
576 | par->wrt_pass_cntr = htons(0xffff); | ||
577 | /* 0-4 = reserved, 5-9 = header, 2990-2994 = header, 2995-2999 = reserved */ | ||
578 | par->first_frame_ppos = htonl(0); | ||
579 | par->last_frame_ppos = htonl(0xbb7); | ||
580 | aux->frame_seq_num = htonl(0); | ||
581 | aux->logical_blk_num_high = htonl(0); | ||
582 | aux->logical_blk_num = htonl(0); | ||
583 | aux->next_mark_ppos = htonl(STp->first_mark_ppos); | ||
584 | break; | ||
585 | case OS_FRAME_TYPE_DATA: | ||
586 | case OS_FRAME_TYPE_MARKER: | ||
587 | dat->dat_sz = 8; | ||
588 | dat->reserved1 = 0; | ||
589 | dat->entry_cnt = 1; | ||
590 | dat->reserved3 = 0; | ||
591 | dat->dat_list[0].blk_sz = htonl(blk_sz); | ||
592 | dat->dat_list[0].blk_cnt = htons(blk_cnt); | ||
593 | dat->dat_list[0].flags = frame_type==OS_FRAME_TYPE_MARKER? | ||
594 | OS_DAT_FLAGS_MARK:OS_DAT_FLAGS_DATA; | ||
595 | dat->dat_list[0].reserved = 0; | ||
596 | /* fall through */ | ||
597 | case OS_FRAME_TYPE_EOD: | ||
598 | aux->update_frame_cntr = htonl(0); | ||
599 | par->partition_num = OS_DATA_PARTITION; | ||
600 | par->par_desc_ver = OS_PARTITION_VERSION; | ||
601 | par->wrt_pass_cntr = htons(STp->wrt_pass_cntr); | ||
602 | par->first_frame_ppos = htonl(STp->first_data_ppos); | ||
603 | par->last_frame_ppos = htonl(STp->capacity); | ||
604 | aux->frame_seq_num = htonl(frame_seq_number); | ||
605 | aux->logical_blk_num_high = htonl(0); | ||
606 | aux->logical_blk_num = htonl(logical_blk_num); | ||
607 | break; | ||
608 | default: ; /* probably FILL */ | ||
609 | } | ||
610 | aux->filemark_cnt = htonl(STp->filemark_cnt); | ||
611 | aux->phys_fm = htonl(0xffffffff); | ||
612 | aux->last_mark_ppos = htonl(STp->last_mark_ppos); | ||
613 | aux->last_mark_lbn = htonl(STp->last_mark_lbn); | ||
614 | } | ||
615 | |||
616 | /* | ||
617 | * Verify that we have the correct tape frame | ||
618 | */ | ||
619 | static int osst_verify_frame(struct osst_tape * STp, int frame_seq_number, int quiet) | ||
620 | { | ||
621 | char * name = tape_name(STp); | ||
622 | os_aux_t * aux = STp->buffer->aux; | ||
623 | os_partition_t * par = &(aux->partition); | ||
624 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
625 | unsigned int blk_cnt, blk_sz, i; | ||
626 | |||
627 | if (STp->raw) { | ||
628 | if (STp->buffer->syscall_result) { | ||
629 | for (i=0; i < STp->buffer->sg_segs; i++) | ||
630 | memset(page_address(sg_page(&STp->buffer->sg[i])), | ||
631 | 0, STp->buffer->sg[i].length); | ||
632 | strcpy(STp->buffer->b_data, "READ ERROR ON FRAME"); | ||
633 | } else | ||
634 | STp->buffer->buffer_bytes = OS_FRAME_SIZE; | ||
635 | return 1; | ||
636 | } | ||
637 | if (STp->buffer->syscall_result) { | ||
638 | #if DEBUG | ||
639 | printk(OSST_DEB_MSG "%s:D: Skipping frame, read error\n", name); | ||
640 | #endif | ||
641 | return 0; | ||
642 | } | ||
643 | if (ntohl(aux->format_id) != 0) { | ||
644 | #if DEBUG | ||
645 | printk(OSST_DEB_MSG "%s:D: Skipping frame, format_id %u\n", name, ntohl(aux->format_id)); | ||
646 | #endif | ||
647 | goto err_out; | ||
648 | } | ||
649 | if (memcmp(aux->application_sig, STp->application_sig, 4) != 0 && | ||
650 | (memcmp(aux->application_sig, "LIN3", 4) != 0 || STp->linux_media_version != 4)) { | ||
651 | #if DEBUG | ||
652 | printk(OSST_DEB_MSG "%s:D: Skipping frame, incorrect application signature\n", name); | ||
653 | #endif | ||
654 | goto err_out; | ||
655 | } | ||
656 | if (par->partition_num != OS_DATA_PARTITION) { | ||
657 | if (!STp->linux_media || STp->linux_media_version != 2) { | ||
658 | #if DEBUG | ||
659 | printk(OSST_DEB_MSG "%s:D: Skipping frame, partition num %d\n", | ||
660 | name, par->partition_num); | ||
661 | #endif | ||
662 | goto err_out; | ||
663 | } | ||
664 | } | ||
665 | if (par->par_desc_ver != OS_PARTITION_VERSION) { | ||
666 | #if DEBUG | ||
667 | printk(OSST_DEB_MSG "%s:D: Skipping frame, partition version %d\n", name, par->par_desc_ver); | ||
668 | #endif | ||
669 | goto err_out; | ||
670 | } | ||
671 | if (ntohs(par->wrt_pass_cntr) != STp->wrt_pass_cntr) { | ||
672 | #if DEBUG | ||
673 | printk(OSST_DEB_MSG "%s:D: Skipping frame, wrt_pass_cntr %d (expected %d)\n", | ||
674 | name, ntohs(par->wrt_pass_cntr), STp->wrt_pass_cntr); | ||
675 | #endif | ||
676 | goto err_out; | ||
677 | } | ||
678 | if (aux->frame_type != OS_FRAME_TYPE_DATA && | ||
679 | aux->frame_type != OS_FRAME_TYPE_EOD && | ||
680 | aux->frame_type != OS_FRAME_TYPE_MARKER) { | ||
681 | if (!quiet) { | ||
682 | #if DEBUG | ||
683 | printk(OSST_DEB_MSG "%s:D: Skipping frame, frame type %x\n", name, aux->frame_type); | ||
684 | #endif | ||
685 | } | ||
686 | goto err_out; | ||
687 | } | ||
688 | if (aux->frame_type == OS_FRAME_TYPE_EOD && | ||
689 | STp->first_frame_position < STp->eod_frame_ppos) { | ||
690 | printk(KERN_INFO "%s:I: Skipping premature EOD frame %d\n", name, | ||
691 | STp->first_frame_position); | ||
692 | goto err_out; | ||
693 | } | ||
694 | if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { | ||
695 | if (!quiet) { | ||
696 | #if DEBUG | ||
697 | printk(OSST_DEB_MSG "%s:D: Skipping frame, sequence number %u (expected %d)\n", | ||
698 | name, ntohl(aux->frame_seq_num), frame_seq_number); | ||
699 | #endif | ||
700 | } | ||
701 | goto err_out; | ||
702 | } | ||
703 | if (aux->frame_type == OS_FRAME_TYPE_MARKER) { | ||
704 | STps->eof = ST_FM_HIT; | ||
705 | |||
706 | i = ntohl(aux->filemark_cnt); | ||
707 | if (STp->header_cache != NULL && i < OS_FM_TAB_MAX && (i > STp->filemark_cnt || | ||
708 | STp->first_frame_position - 1 != ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i]))) { | ||
709 | #if DEBUG | ||
710 | printk(OSST_DEB_MSG "%s:D: %s filemark %d at frame pos %d\n", name, | ||
711 | STp->header_cache->dat_fm_tab.fm_tab_ent[i] == 0?"Learned":"Corrected", | ||
712 | i, STp->first_frame_position - 1); | ||
713 | #endif | ||
714 | STp->header_cache->dat_fm_tab.fm_tab_ent[i] = htonl(STp->first_frame_position - 1); | ||
715 | if (i >= STp->filemark_cnt) | ||
716 | STp->filemark_cnt = i+1; | ||
717 | } | ||
718 | } | ||
719 | if (aux->frame_type == OS_FRAME_TYPE_EOD) { | ||
720 | STps->eof = ST_EOD_1; | ||
721 | STp->frame_in_buffer = 1; | ||
722 | } | ||
723 | if (aux->frame_type == OS_FRAME_TYPE_DATA) { | ||
724 | blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt); | ||
725 | blk_sz = ntohl(aux->dat.dat_list[0].blk_sz); | ||
726 | STp->buffer->buffer_bytes = blk_cnt * blk_sz; | ||
727 | STp->buffer->read_pointer = 0; | ||
728 | STp->frame_in_buffer = 1; | ||
729 | |||
730 | /* See what block size was used to write file */ | ||
731 | if (STp->block_size != blk_sz && blk_sz > 0) { | ||
732 | printk(KERN_INFO | ||
733 | "%s:I: File was written with block size %d%c, currently %d%c, adjusted to match.\n", | ||
734 | name, blk_sz<1024?blk_sz:blk_sz/1024,blk_sz<1024?'b':'k', | ||
735 | STp->block_size<1024?STp->block_size:STp->block_size/1024, | ||
736 | STp->block_size<1024?'b':'k'); | ||
737 | STp->block_size = blk_sz; | ||
738 | STp->buffer->buffer_blocks = OS_DATA_SIZE / blk_sz; | ||
739 | } | ||
740 | STps->eof = ST_NOEOF; | ||
741 | } | ||
742 | STp->frame_seq_number = ntohl(aux->frame_seq_num); | ||
743 | STp->logical_blk_num = ntohl(aux->logical_blk_num); | ||
744 | return 1; | ||
745 | |||
746 | err_out: | ||
747 | if (STp->read_error_frame == 0) | ||
748 | STp->read_error_frame = STp->first_frame_position - 1; | ||
749 | return 0; | ||
750 | } | ||
751 | |||
752 | /* | ||
753 | * Wait for the unit to become Ready | ||
754 | */ | ||
755 | static int osst_wait_ready(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
756 | unsigned timeout, int initial_delay) | ||
757 | { | ||
758 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
759 | struct osst_request * SRpnt; | ||
760 | unsigned long startwait = jiffies; | ||
761 | #if DEBUG | ||
762 | int dbg = debugging; | ||
763 | char * name = tape_name(STp); | ||
764 | |||
765 | printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name); | ||
766 | #endif | ||
767 | |||
768 | if (initial_delay > 0) | ||
769 | msleep(jiffies_to_msecs(initial_delay)); | ||
770 | |||
771 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
772 | cmd[0] = TEST_UNIT_READY; | ||
773 | |||
774 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
775 | *aSRpnt = SRpnt; | ||
776 | if (!SRpnt) return (-EBUSY); | ||
777 | |||
778 | while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && | ||
779 | (( SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && | ||
780 | (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8) ) || | ||
781 | ( SRpnt->sense[2] == 6 && SRpnt->sense[12] == 0x28 && | ||
782 | SRpnt->sense[13] == 0 ) )) { | ||
783 | #if DEBUG | ||
784 | if (debugging) { | ||
785 | printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait ready\n", name); | ||
786 | printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); | ||
787 | debugging = 0; | ||
788 | } | ||
789 | #endif | ||
790 | msleep(100); | ||
791 | |||
792 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
793 | cmd[0] = TEST_UNIT_READY; | ||
794 | |||
795 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
796 | } | ||
797 | *aSRpnt = SRpnt; | ||
798 | #if DEBUG | ||
799 | debugging = dbg; | ||
800 | #endif | ||
801 | if ( STp->buffer->syscall_result && | ||
802 | osst_write_error_recovery(STp, aSRpnt, 0) ) { | ||
803 | #if DEBUG | ||
804 | printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait ready\n", name); | ||
805 | printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, | ||
806 | STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], | ||
807 | SRpnt->sense[12], SRpnt->sense[13]); | ||
808 | #endif | ||
809 | return (-EIO); | ||
810 | } | ||
811 | #if DEBUG | ||
812 | printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait ready\n", name); | ||
813 | #endif | ||
814 | return 0; | ||
815 | } | ||
816 | |||
817 | /* | ||
818 | * Wait for a tape to be inserted in the unit | ||
819 | */ | ||
820 | static int osst_wait_for_medium(struct osst_tape * STp, struct osst_request ** aSRpnt, unsigned timeout) | ||
821 | { | ||
822 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
823 | struct osst_request * SRpnt; | ||
824 | unsigned long startwait = jiffies; | ||
825 | #if DEBUG | ||
826 | int dbg = debugging; | ||
827 | char * name = tape_name(STp); | ||
828 | |||
829 | printk(OSST_DEB_MSG "%s:D: Reached onstream wait for medium\n", name); | ||
830 | #endif | ||
831 | |||
832 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
833 | cmd[0] = TEST_UNIT_READY; | ||
834 | |||
835 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
836 | *aSRpnt = SRpnt; | ||
837 | if (!SRpnt) return (-EBUSY); | ||
838 | |||
839 | while ( STp->buffer->syscall_result && time_before(jiffies, startwait + timeout*HZ) && | ||
840 | SRpnt->sense[2] == 2 && SRpnt->sense[12] == 0x3a && SRpnt->sense[13] == 0 ) { | ||
841 | #if DEBUG | ||
842 | if (debugging) { | ||
843 | printk(OSST_DEB_MSG "%s:D: Sleeping in onstream wait medium\n", name); | ||
844 | printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); | ||
845 | debugging = 0; | ||
846 | } | ||
847 | #endif | ||
848 | msleep(100); | ||
849 | |||
850 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
851 | cmd[0] = TEST_UNIT_READY; | ||
852 | |||
853 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
854 | } | ||
855 | *aSRpnt = SRpnt; | ||
856 | #if DEBUG | ||
857 | debugging = dbg; | ||
858 | #endif | ||
859 | if ( STp->buffer->syscall_result && SRpnt->sense[2] != 2 && | ||
860 | SRpnt->sense[12] != 4 && SRpnt->sense[13] == 1) { | ||
861 | #if DEBUG | ||
862 | printk(OSST_DEB_MSG "%s:D: Abnormal exit from onstream wait medium\n", name); | ||
863 | printk(OSST_DEB_MSG "%s:D: Result = %d, Sense: 0=%02x, 2=%02x, 12=%02x, 13=%02x\n", name, | ||
864 | STp->buffer->syscall_result, SRpnt->sense[0], SRpnt->sense[2], | ||
865 | SRpnt->sense[12], SRpnt->sense[13]); | ||
866 | #endif | ||
867 | return 0; | ||
868 | } | ||
869 | #if DEBUG | ||
870 | printk(OSST_DEB_MSG "%s:D: Normal exit from onstream wait medium\n", name); | ||
871 | #endif | ||
872 | return 1; | ||
873 | } | ||
874 | |||
875 | static int osst_position_tape_and_confirm(struct osst_tape * STp, struct osst_request ** aSRpnt, int frame) | ||
876 | { | ||
877 | int retval; | ||
878 | |||
879 | osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */ | ||
880 | retval = osst_set_frame_position(STp, aSRpnt, frame, 0); | ||
881 | if (retval) return (retval); | ||
882 | osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE); | ||
883 | return (osst_get_frame_position(STp, aSRpnt)); | ||
884 | } | ||
885 | |||
886 | /* | ||
887 | * Wait for write(s) to complete | ||
888 | */ | ||
889 | static int osst_flush_drive_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
890 | { | ||
891 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
892 | struct osst_request * SRpnt; | ||
893 | int result = 0; | ||
894 | int delay = OSST_WAIT_WRITE_COMPLETE; | ||
895 | #if DEBUG | ||
896 | char * name = tape_name(STp); | ||
897 | |||
898 | printk(OSST_DEB_MSG "%s:D: Reached onstream flush drive buffer (write filemark)\n", name); | ||
899 | #endif | ||
900 | |||
901 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
902 | cmd[0] = WRITE_FILEMARKS; | ||
903 | cmd[1] = 1; | ||
904 | |||
905 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
906 | *aSRpnt = SRpnt; | ||
907 | if (!SRpnt) return (-EBUSY); | ||
908 | if (STp->buffer->syscall_result) { | ||
909 | if ((SRpnt->sense[2] & 0x0f) == 2 && SRpnt->sense[12] == 4) { | ||
910 | if (SRpnt->sense[13] == 8) { | ||
911 | delay = OSST_WAIT_LONG_WRITE_COMPLETE; | ||
912 | } | ||
913 | } else | ||
914 | result = osst_write_error_recovery(STp, aSRpnt, 0); | ||
915 | } | ||
916 | result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay); | ||
917 | STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; | ||
918 | |||
919 | return (result); | ||
920 | } | ||
921 | |||
922 | #define OSST_POLL_PER_SEC 10 | ||
923 | static int osst_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int curr, int minlast, int to) | ||
924 | { | ||
925 | unsigned long startwait = jiffies; | ||
926 | char * name = tape_name(STp); | ||
927 | #if DEBUG | ||
928 | char notyetprinted = 1; | ||
929 | #endif | ||
930 | if (minlast >= 0 && STp->ps[STp->partition].rw != ST_READING) | ||
931 | printk(KERN_ERR "%s:A: Waiting for frame without having initialized read!\n", name); | ||
932 | |||
933 | while (time_before (jiffies, startwait + to*HZ)) | ||
934 | { | ||
935 | int result; | ||
936 | result = osst_get_frame_position(STp, aSRpnt); | ||
937 | if (result == -EIO) | ||
938 | if ((result = osst_write_error_recovery(STp, aSRpnt, 0)) == 0) | ||
939 | return 0; /* successful recovery leaves drive ready for frame */ | ||
940 | if (result < 0) break; | ||
941 | if (STp->first_frame_position == curr && | ||
942 | ((minlast < 0 && | ||
943 | (signed)STp->last_frame_position > (signed)curr + minlast) || | ||
944 | (minlast >= 0 && STp->cur_frames > minlast) | ||
945 | ) && result >= 0) | ||
946 | { | ||
947 | #if DEBUG | ||
948 | if (debugging || time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC)) | ||
949 | printk (OSST_DEB_MSG | ||
950 | "%s:D: Succ wait f fr %i (>%i): %i-%i %i (%i): %3li.%li s\n", | ||
951 | name, curr, curr+minlast, STp->first_frame_position, | ||
952 | STp->last_frame_position, STp->cur_frames, | ||
953 | result, (jiffies-startwait)/HZ, | ||
954 | (((jiffies-startwait)%HZ)*10)/HZ); | ||
955 | #endif | ||
956 | return 0; | ||
957 | } | ||
958 | #if DEBUG | ||
959 | if (time_after_eq(jiffies, startwait + 2*HZ/OSST_POLL_PER_SEC) && notyetprinted) | ||
960 | { | ||
961 | printk (OSST_DEB_MSG "%s:D: Wait for frame %i (>%i): %i-%i %i (%i)\n", | ||
962 | name, curr, curr+minlast, STp->first_frame_position, | ||
963 | STp->last_frame_position, STp->cur_frames, result); | ||
964 | notyetprinted--; | ||
965 | } | ||
966 | #endif | ||
967 | msleep(1000 / OSST_POLL_PER_SEC); | ||
968 | } | ||
969 | #if DEBUG | ||
970 | printk (OSST_DEB_MSG "%s:D: Fail wait f fr %i (>%i): %i-%i %i: %3li.%li s\n", | ||
971 | name, curr, curr+minlast, STp->first_frame_position, | ||
972 | STp->last_frame_position, STp->cur_frames, | ||
973 | (jiffies-startwait)/HZ, (((jiffies-startwait)%HZ)*10)/HZ); | ||
974 | #endif | ||
975 | return -EBUSY; | ||
976 | } | ||
977 | |||
978 | static int osst_recover_wait_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int writing) | ||
979 | { | ||
980 | struct osst_request * SRpnt; | ||
981 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
982 | unsigned long startwait = jiffies; | ||
983 | int retval = 1; | ||
984 | char * name = tape_name(STp); | ||
985 | |||
986 | if (writing) { | ||
987 | char mybuf[24]; | ||
988 | char * olddata = STp->buffer->b_data; | ||
989 | int oldsize = STp->buffer->buffer_size; | ||
990 | |||
991 | /* write zero fm then read pos - if shows write error, try to recover - if no progress, wait */ | ||
992 | |||
993 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
994 | cmd[0] = WRITE_FILEMARKS; | ||
995 | cmd[1] = 1; | ||
996 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, | ||
997 | MAX_RETRIES, 1); | ||
998 | |||
999 | while (retval && time_before (jiffies, startwait + 5*60*HZ)) { | ||
1000 | |||
1001 | if (STp->buffer->syscall_result && (SRpnt->sense[2] & 0x0f) != 2) { | ||
1002 | |||
1003 | /* some failure - not just not-ready */ | ||
1004 | retval = osst_write_error_recovery(STp, aSRpnt, 0); | ||
1005 | break; | ||
1006 | } | ||
1007 | schedule_timeout_interruptible(HZ / OSST_POLL_PER_SEC); | ||
1008 | |||
1009 | STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; | ||
1010 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1011 | cmd[0] = READ_POSITION; | ||
1012 | |||
1013 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 20, DMA_FROM_DEVICE, STp->timeout, | ||
1014 | MAX_RETRIES, 1); | ||
1015 | |||
1016 | retval = ( STp->buffer->syscall_result || (STp->buffer)->b_data[15] > 25 ); | ||
1017 | STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; | ||
1018 | } | ||
1019 | if (retval) | ||
1020 | printk(KERN_ERR "%s:E: Device did not succeed to write buffered data\n", name); | ||
1021 | } else | ||
1022 | /* TODO - figure out which error conditions can be handled */ | ||
1023 | if (STp->buffer->syscall_result) | ||
1024 | printk(KERN_WARNING | ||
1025 | "%s:W: Recover_wait_frame(read) cannot handle %02x:%02x:%02x\n", name, | ||
1026 | (*aSRpnt)->sense[ 2] & 0x0f, | ||
1027 | (*aSRpnt)->sense[12], | ||
1028 | (*aSRpnt)->sense[13]); | ||
1029 | |||
1030 | return retval; | ||
1031 | } | ||
1032 | |||
1033 | /* | ||
1034 | * Read the next OnStream tape frame at the current location | ||
1035 | */ | ||
1036 | static int osst_read_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int timeout) | ||
1037 | { | ||
1038 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
1039 | struct osst_request * SRpnt; | ||
1040 | int retval = 0; | ||
1041 | #if DEBUG | ||
1042 | os_aux_t * aux = STp->buffer->aux; | ||
1043 | char * name = tape_name(STp); | ||
1044 | #endif | ||
1045 | |||
1046 | if (STp->poll) | ||
1047 | if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, 0, timeout)) | ||
1048 | retval = osst_recover_wait_frame(STp, aSRpnt, 0); | ||
1049 | |||
1050 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1051 | cmd[0] = READ_6; | ||
1052 | cmd[1] = 1; | ||
1053 | cmd[4] = 1; | ||
1054 | |||
1055 | #if DEBUG | ||
1056 | if (debugging) | ||
1057 | printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name); | ||
1058 | #endif | ||
1059 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, | ||
1060 | STp->timeout, MAX_RETRIES, 1); | ||
1061 | *aSRpnt = SRpnt; | ||
1062 | if (!SRpnt) | ||
1063 | return (-EBUSY); | ||
1064 | |||
1065 | if ((STp->buffer)->syscall_result) { | ||
1066 | retval = 1; | ||
1067 | if (STp->read_error_frame == 0) { | ||
1068 | STp->read_error_frame = STp->first_frame_position; | ||
1069 | #if DEBUG | ||
1070 | printk(OSST_DEB_MSG "%s:D: Recording read error at %d\n", name, STp->read_error_frame); | ||
1071 | #endif | ||
1072 | } | ||
1073 | #if DEBUG | ||
1074 | if (debugging) | ||
1075 | printk(OSST_DEB_MSG "%s:D: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", | ||
1076 | name, | ||
1077 | SRpnt->sense[0], SRpnt->sense[1], | ||
1078 | SRpnt->sense[2], SRpnt->sense[3], | ||
1079 | SRpnt->sense[4], SRpnt->sense[5], | ||
1080 | SRpnt->sense[6], SRpnt->sense[7]); | ||
1081 | #endif | ||
1082 | } | ||
1083 | else | ||
1084 | STp->first_frame_position++; | ||
1085 | #if DEBUG | ||
1086 | if (debugging) { | ||
1087 | char sig[8]; int i; | ||
1088 | for (i=0;i<4;i++) | ||
1089 | sig[i] = aux->application_sig[i]<32?'^':aux->application_sig[i]; | ||
1090 | sig[4] = '\0'; | ||
1091 | printk(OSST_DEB_MSG | ||
1092 | "%s:D: AUX: %s UpdFrCt#%d Wpass#%d %s FrSeq#%d LogBlk#%d Qty=%d Sz=%d\n", name, sig, | ||
1093 | ntohl(aux->update_frame_cntr), ntohs(aux->partition.wrt_pass_cntr), | ||
1094 | aux->frame_type==1?"EOD":aux->frame_type==2?"MARK": | ||
1095 | aux->frame_type==8?"HEADR":aux->frame_type==0x80?"DATA":"FILL", | ||
1096 | ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), | ||
1097 | ntohs(aux->dat.dat_list[0].blk_cnt), ntohl(aux->dat.dat_list[0].blk_sz) ); | ||
1098 | if (aux->frame_type==2) | ||
1099 | printk(OSST_DEB_MSG "%s:D: mark_cnt=%d, last_mark_ppos=%d, last_mark_lbn=%d\n", name, | ||
1100 | ntohl(aux->filemark_cnt), ntohl(aux->last_mark_ppos), ntohl(aux->last_mark_lbn)); | ||
1101 | printk(OSST_DEB_MSG "%s:D: Exit read frame from OnStream tape with code %d\n", name, retval); | ||
1102 | } | ||
1103 | #endif | ||
1104 | return (retval); | ||
1105 | } | ||
1106 | |||
1107 | static int osst_initiate_read(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
1108 | { | ||
1109 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
1110 | struct osst_request * SRpnt ; | ||
1111 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
1112 | int retval = 0; | ||
1113 | char * name = tape_name(STp); | ||
1114 | |||
1115 | if (STps->rw != ST_READING) { /* Initialize read operation */ | ||
1116 | if (STps->rw == ST_WRITING || STp->dirty) { | ||
1117 | STp->write_type = OS_WRITE_DATA; | ||
1118 | osst_flush_write_buffer(STp, aSRpnt); | ||
1119 | osst_flush_drive_buffer(STp, aSRpnt); | ||
1120 | } | ||
1121 | STps->rw = ST_READING; | ||
1122 | STp->frame_in_buffer = 0; | ||
1123 | |||
1124 | /* | ||
1125 | * Issue a read 0 command to get the OnStream drive | ||
1126 | * read frames into its buffer. | ||
1127 | */ | ||
1128 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1129 | cmd[0] = READ_6; | ||
1130 | cmd[1] = 1; | ||
1131 | |||
1132 | #if DEBUG | ||
1133 | printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name); | ||
1134 | #endif | ||
1135 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
1136 | *aSRpnt = SRpnt; | ||
1137 | if ((retval = STp->buffer->syscall_result)) | ||
1138 | printk(KERN_WARNING "%s:W: Error starting read ahead\n", name); | ||
1139 | } | ||
1140 | |||
1141 | return retval; | ||
1142 | } | ||
1143 | |||
1144 | static int osst_get_logical_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
1145 | int frame_seq_number, int quiet) | ||
1146 | { | ||
1147 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
1148 | char * name = tape_name(STp); | ||
1149 | int cnt = 0, | ||
1150 | bad = 0, | ||
1151 | past = 0, | ||
1152 | x, | ||
1153 | position; | ||
1154 | |||
1155 | /* | ||
1156 | * If we want just any frame (-1) and there is a frame in the buffer, return it | ||
1157 | */ | ||
1158 | if (frame_seq_number == -1 && STp->frame_in_buffer) { | ||
1159 | #if DEBUG | ||
1160 | printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number); | ||
1161 | #endif | ||
1162 | return (STps->eof); | ||
1163 | } | ||
1164 | /* | ||
1165 | * Search and wait for the next logical tape frame | ||
1166 | */ | ||
1167 | while (1) { | ||
1168 | if (cnt++ > 400) { | ||
1169 | printk(KERN_ERR "%s:E: Couldn't find logical frame %d, aborting\n", | ||
1170 | name, frame_seq_number); | ||
1171 | if (STp->read_error_frame) { | ||
1172 | osst_set_frame_position(STp, aSRpnt, STp->read_error_frame, 0); | ||
1173 | #if DEBUG | ||
1174 | printk(OSST_DEB_MSG "%s:D: Repositioning tape to bad frame %d\n", | ||
1175 | name, STp->read_error_frame); | ||
1176 | #endif | ||
1177 | STp->read_error_frame = 0; | ||
1178 | STp->abort_count++; | ||
1179 | } | ||
1180 | return (-EIO); | ||
1181 | } | ||
1182 | #if DEBUG | ||
1183 | if (debugging) | ||
1184 | printk(OSST_DEB_MSG "%s:D: Looking for frame %d, attempt %d\n", | ||
1185 | name, frame_seq_number, cnt); | ||
1186 | #endif | ||
1187 | if ( osst_initiate_read(STp, aSRpnt) | ||
1188 | || ( (!STp->frame_in_buffer) && osst_read_frame(STp, aSRpnt, 30) ) ) { | ||
1189 | if (STp->raw) | ||
1190 | return (-EIO); | ||
1191 | position = osst_get_frame_position(STp, aSRpnt); | ||
1192 | if (position >= 0xbae && position < 0xbb8) | ||
1193 | position = 0xbb8; | ||
1194 | else if (position > STp->eod_frame_ppos || ++bad == 10) { | ||
1195 | position = STp->read_error_frame - 1; | ||
1196 | bad = 0; | ||
1197 | } | ||
1198 | else { | ||
1199 | position += 29; | ||
1200 | cnt += 19; | ||
1201 | } | ||
1202 | #if DEBUG | ||
1203 | printk(OSST_DEB_MSG "%s:D: Bad frame detected, positioning tape to block %d\n", | ||
1204 | name, position); | ||
1205 | #endif | ||
1206 | osst_set_frame_position(STp, aSRpnt, position, 0); | ||
1207 | continue; | ||
1208 | } | ||
1209 | if (osst_verify_frame(STp, frame_seq_number, quiet)) | ||
1210 | break; | ||
1211 | if (osst_verify_frame(STp, -1, quiet)) { | ||
1212 | x = ntohl(STp->buffer->aux->frame_seq_num); | ||
1213 | if (STp->fast_open) { | ||
1214 | printk(KERN_WARNING | ||
1215 | "%s:W: Found logical frame %d instead of %d after fast open\n", | ||
1216 | name, x, frame_seq_number); | ||
1217 | STp->header_ok = 0; | ||
1218 | STp->read_error_frame = 0; | ||
1219 | return (-EIO); | ||
1220 | } | ||
1221 | if (x > frame_seq_number) { | ||
1222 | if (++past > 3) { | ||
1223 | /* positioning backwards did not bring us to the desired frame */ | ||
1224 | position = STp->read_error_frame - 1; | ||
1225 | } | ||
1226 | else { | ||
1227 | position = osst_get_frame_position(STp, aSRpnt) | ||
1228 | + frame_seq_number - x - 1; | ||
1229 | |||
1230 | if (STp->first_frame_position >= 3000 && position < 3000) | ||
1231 | position -= 10; | ||
1232 | } | ||
1233 | #if DEBUG | ||
1234 | printk(OSST_DEB_MSG | ||
1235 | "%s:D: Found logical frame %d while looking for %d: back up %d\n", | ||
1236 | name, x, frame_seq_number, | ||
1237 | STp->first_frame_position - position); | ||
1238 | #endif | ||
1239 | osst_set_frame_position(STp, aSRpnt, position, 0); | ||
1240 | cnt += 10; | ||
1241 | } | ||
1242 | else | ||
1243 | past = 0; | ||
1244 | } | ||
1245 | if (osst_get_frame_position(STp, aSRpnt) == 0xbaf) { | ||
1246 | #if DEBUG | ||
1247 | printk(OSST_DEB_MSG "%s:D: Skipping config partition\n", name); | ||
1248 | #endif | ||
1249 | osst_set_frame_position(STp, aSRpnt, 0xbb8, 0); | ||
1250 | cnt--; | ||
1251 | } | ||
1252 | STp->frame_in_buffer = 0; | ||
1253 | } | ||
1254 | if (cnt > 1) { | ||
1255 | STp->recover_count++; | ||
1256 | STp->recover_erreg++; | ||
1257 | printk(KERN_WARNING "%s:I: Don't worry, Read error at position %d recovered\n", | ||
1258 | name, STp->read_error_frame); | ||
1259 | } | ||
1260 | STp->read_count++; | ||
1261 | |||
1262 | #if DEBUG | ||
1263 | if (debugging || STps->eof) | ||
1264 | printk(OSST_DEB_MSG | ||
1265 | "%s:D: Exit get logical frame (%d=>%d) from OnStream tape with code %d\n", | ||
1266 | name, frame_seq_number, STp->frame_seq_number, STps->eof); | ||
1267 | #endif | ||
1268 | STp->fast_open = 0; | ||
1269 | STp->read_error_frame = 0; | ||
1270 | return (STps->eof); | ||
1271 | } | ||
1272 | |||
1273 | static int osst_seek_logical_blk(struct osst_tape * STp, struct osst_request ** aSRpnt, int logical_blk_num) | ||
1274 | { | ||
1275 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
1276 | char * name = tape_name(STp); | ||
1277 | int retries = 0; | ||
1278 | int frame_seq_estimate, ppos_estimate, move; | ||
1279 | |||
1280 | if (logical_blk_num < 0) logical_blk_num = 0; | ||
1281 | #if DEBUG | ||
1282 | printk(OSST_DEB_MSG "%s:D: Seeking logical block %d (now at %d, size %d%c)\n", | ||
1283 | name, logical_blk_num, STp->logical_blk_num, | ||
1284 | STp->block_size<1024?STp->block_size:STp->block_size/1024, | ||
1285 | STp->block_size<1024?'b':'k'); | ||
1286 | #endif | ||
1287 | /* Do we know where we are? */ | ||
1288 | if (STps->drv_block >= 0) { | ||
1289 | move = logical_blk_num - STp->logical_blk_num; | ||
1290 | if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; | ||
1291 | move /= (OS_DATA_SIZE / STp->block_size); | ||
1292 | frame_seq_estimate = STp->frame_seq_number + move; | ||
1293 | } else | ||
1294 | frame_seq_estimate = logical_blk_num * STp->block_size / OS_DATA_SIZE; | ||
1295 | |||
1296 | if (frame_seq_estimate < 2980) ppos_estimate = frame_seq_estimate + 10; | ||
1297 | else ppos_estimate = frame_seq_estimate + 20; | ||
1298 | while (++retries < 10) { | ||
1299 | if (ppos_estimate > STp->eod_frame_ppos-2) { | ||
1300 | frame_seq_estimate += STp->eod_frame_ppos - 2 - ppos_estimate; | ||
1301 | ppos_estimate = STp->eod_frame_ppos - 2; | ||
1302 | } | ||
1303 | if (frame_seq_estimate < 0) { | ||
1304 | frame_seq_estimate = 0; | ||
1305 | ppos_estimate = 10; | ||
1306 | } | ||
1307 | osst_set_frame_position(STp, aSRpnt, ppos_estimate, 0); | ||
1308 | if (osst_get_logical_frame(STp, aSRpnt, frame_seq_estimate, 1) >= 0) { | ||
1309 | /* we've located the estimated frame, now does it have our block? */ | ||
1310 | if (logical_blk_num < STp->logical_blk_num || | ||
1311 | logical_blk_num >= STp->logical_blk_num + ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt)) { | ||
1312 | if (STps->eof == ST_FM_HIT) | ||
1313 | move = logical_blk_num < STp->logical_blk_num? -2 : 1; | ||
1314 | else { | ||
1315 | move = logical_blk_num - STp->logical_blk_num; | ||
1316 | if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; | ||
1317 | move /= (OS_DATA_SIZE / STp->block_size); | ||
1318 | } | ||
1319 | if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1; | ||
1320 | #if DEBUG | ||
1321 | printk(OSST_DEB_MSG | ||
1322 | "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", | ||
1323 | name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, | ||
1324 | STp->logical_blk_num, logical_blk_num, move); | ||
1325 | #endif | ||
1326 | frame_seq_estimate += move; | ||
1327 | ppos_estimate += move; | ||
1328 | continue; | ||
1329 | } else { | ||
1330 | STp->buffer->read_pointer = (logical_blk_num - STp->logical_blk_num) * STp->block_size; | ||
1331 | STp->buffer->buffer_bytes -= STp->buffer->read_pointer; | ||
1332 | STp->logical_blk_num = logical_blk_num; | ||
1333 | #if DEBUG | ||
1334 | printk(OSST_DEB_MSG | ||
1335 | "%s:D: Seek success at ppos %d fsq %d in_buf %d, bytes %d, ptr %d*%d\n", | ||
1336 | name, ppos_estimate, STp->frame_seq_number, STp->frame_in_buffer, | ||
1337 | STp->buffer->buffer_bytes, STp->buffer->read_pointer / STp->block_size, | ||
1338 | STp->block_size); | ||
1339 | #endif | ||
1340 | STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); | ||
1341 | if (STps->eof == ST_FM_HIT) { | ||
1342 | STps->drv_file++; | ||
1343 | STps->drv_block = 0; | ||
1344 | } else { | ||
1345 | STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? | ||
1346 | STp->logical_blk_num - | ||
1347 | (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): | ||
1348 | -1; | ||
1349 | } | ||
1350 | STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; | ||
1351 | return 0; | ||
1352 | } | ||
1353 | } | ||
1354 | if (osst_get_logical_frame(STp, aSRpnt, -1, 1) < 0) | ||
1355 | goto error; | ||
1356 | /* we are not yet at the estimated frame, adjust our estimate of its physical position */ | ||
1357 | #if DEBUG | ||
1358 | printk(OSST_DEB_MSG "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d)\n", | ||
1359 | name, retries, ppos_estimate, STp->frame_seq_number, frame_seq_estimate, | ||
1360 | STp->logical_blk_num, logical_blk_num); | ||
1361 | #endif | ||
1362 | if (frame_seq_estimate != STp->frame_seq_number) | ||
1363 | ppos_estimate += frame_seq_estimate - STp->frame_seq_number; | ||
1364 | else | ||
1365 | break; | ||
1366 | } | ||
1367 | error: | ||
1368 | printk(KERN_ERR "%s:E: Couldn't seek to logical block %d (at %d), %d retries\n", | ||
1369 | name, logical_blk_num, STp->logical_blk_num, retries); | ||
1370 | return (-EIO); | ||
1371 | } | ||
1372 | |||
1373 | /* The values below are based on the OnStream frame payload size of 32K == 2**15, | ||
1374 | * that is, OSST_FRAME_SHIFT + OSST_SECTOR_SHIFT must be 15. With a minimum block | ||
1375 | * size of 512 bytes, we need to be able to resolve 32K/512 == 64 == 2**6 positions | ||
1376 | * inside each frame. Finally, OSST_SECTOR_MASK == 2**OSST_FRAME_SHIFT - 1. | ||
1377 | */ | ||
1378 | #define OSST_FRAME_SHIFT 6 | ||
1379 | #define OSST_SECTOR_SHIFT 9 | ||
1380 | #define OSST_SECTOR_MASK 0x03F | ||
1381 | |||
1382 | static int osst_get_sector(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
1383 | { | ||
1384 | int sector; | ||
1385 | #if DEBUG | ||
1386 | char * name = tape_name(STp); | ||
1387 | |||
1388 | printk(OSST_DEB_MSG | ||
1389 | "%s:D: Positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, %cptr %d, eof %d\n", | ||
1390 | name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, | ||
1391 | STp->ps[STp->partition].drv_file, STp->ps[STp->partition].drv_block, | ||
1392 | STp->ps[STp->partition].rw == ST_WRITING?'w':'r', | ||
1393 | STp->ps[STp->partition].rw == ST_WRITING?STp->buffer->buffer_bytes: | ||
1394 | STp->buffer->read_pointer, STp->ps[STp->partition].eof); | ||
1395 | #endif | ||
1396 | /* do we know where we are inside a file? */ | ||
1397 | if (STp->ps[STp->partition].drv_block >= 0) { | ||
1398 | sector = (STp->frame_in_buffer ? STp->first_frame_position-1 : | ||
1399 | STp->first_frame_position) << OSST_FRAME_SHIFT; | ||
1400 | if (STp->ps[STp->partition].rw == ST_WRITING) | ||
1401 | sector |= (STp->buffer->buffer_bytes >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; | ||
1402 | else | ||
1403 | sector |= (STp->buffer->read_pointer >> OSST_SECTOR_SHIFT) & OSST_SECTOR_MASK; | ||
1404 | } else { | ||
1405 | sector = osst_get_frame_position(STp, aSRpnt); | ||
1406 | if (sector > 0) | ||
1407 | sector <<= OSST_FRAME_SHIFT; | ||
1408 | } | ||
1409 | return sector; | ||
1410 | } | ||
1411 | |||
1412 | static int osst_seek_sector(struct osst_tape * STp, struct osst_request ** aSRpnt, int sector) | ||
1413 | { | ||
1414 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
1415 | int frame = sector >> OSST_FRAME_SHIFT, | ||
1416 | offset = (sector & OSST_SECTOR_MASK) << OSST_SECTOR_SHIFT, | ||
1417 | r; | ||
1418 | #if DEBUG | ||
1419 | char * name = tape_name(STp); | ||
1420 | |||
1421 | printk(OSST_DEB_MSG "%s:D: Seeking sector %d in frame %d at offset %d\n", | ||
1422 | name, sector, frame, offset); | ||
1423 | #endif | ||
1424 | if (frame < 0 || frame >= STp->capacity) return (-ENXIO); | ||
1425 | |||
1426 | if (frame <= STp->first_data_ppos) { | ||
1427 | STp->frame_seq_number = STp->logical_blk_num = STps->drv_file = STps->drv_block = 0; | ||
1428 | return (osst_set_frame_position(STp, aSRpnt, frame, 0)); | ||
1429 | } | ||
1430 | r = osst_set_frame_position(STp, aSRpnt, offset?frame:frame-1, 0); | ||
1431 | if (r < 0) return r; | ||
1432 | |||
1433 | r = osst_get_logical_frame(STp, aSRpnt, -1, 1); | ||
1434 | if (r < 0) return r; | ||
1435 | |||
1436 | if (osst_get_frame_position(STp, aSRpnt) != (offset?frame+1:frame)) return (-EIO); | ||
1437 | |||
1438 | if (offset) { | ||
1439 | STp->logical_blk_num += offset / STp->block_size; | ||
1440 | STp->buffer->read_pointer = offset; | ||
1441 | STp->buffer->buffer_bytes -= offset; | ||
1442 | } else { | ||
1443 | STp->frame_seq_number++; | ||
1444 | STp->frame_in_buffer = 0; | ||
1445 | STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); | ||
1446 | STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; | ||
1447 | } | ||
1448 | STps->drv_file = ntohl(STp->buffer->aux->filemark_cnt); | ||
1449 | if (STps->eof == ST_FM_HIT) { | ||
1450 | STps->drv_file++; | ||
1451 | STps->drv_block = 0; | ||
1452 | } else { | ||
1453 | STps->drv_block = ntohl(STp->buffer->aux->last_mark_lbn)? | ||
1454 | STp->logical_blk_num - | ||
1455 | (STps->drv_file ? ntohl(STp->buffer->aux->last_mark_lbn) + 1 : 0): | ||
1456 | -1; | ||
1457 | } | ||
1458 | STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_NOEOF; | ||
1459 | #if DEBUG | ||
1460 | printk(OSST_DEB_MSG | ||
1461 | "%s:D: Now positioned at ppos %d, frame %d, lbn %d, file %d, blk %d, rptr %d, eof %d\n", | ||
1462 | name, STp->first_frame_position, STp->frame_seq_number, STp->logical_blk_num, | ||
1463 | STps->drv_file, STps->drv_block, STp->buffer->read_pointer, STps->eof); | ||
1464 | #endif | ||
1465 | return 0; | ||
1466 | } | ||
1467 | |||
1468 | /* | ||
1469 | * Read back the drive's internal buffer contents, as a part | ||
1470 | * of the write error recovery mechanism for old OnStream | ||
1471 | * firmware revisions. | ||
1472 | * Precondition for this function to work: all frames in the | ||
1473 | * drive's buffer must be of one type (DATA, MARK or EOD)! | ||
1474 | */ | ||
1475 | static int osst_read_back_buffer_and_rewrite(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
1476 | unsigned int frame, unsigned int skip, int pending) | ||
1477 | { | ||
1478 | struct osst_request * SRpnt = * aSRpnt; | ||
1479 | unsigned char * buffer, * p; | ||
1480 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
1481 | int flag, new_frame, i; | ||
1482 | int nframes = STp->cur_frames; | ||
1483 | int blks_per_frame = ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); | ||
1484 | int frame_seq_number = ntohl(STp->buffer->aux->frame_seq_num) | ||
1485 | - (nframes + pending - 1); | ||
1486 | int logical_blk_num = ntohl(STp->buffer->aux->logical_blk_num) | ||
1487 | - (nframes + pending - 1) * blks_per_frame; | ||
1488 | char * name = tape_name(STp); | ||
1489 | unsigned long startwait = jiffies; | ||
1490 | #if DEBUG | ||
1491 | int dbg = debugging; | ||
1492 | #endif | ||
1493 | |||
1494 | if ((buffer = vmalloc(array_size((nframes + 1), OS_DATA_SIZE))) == NULL) | ||
1495 | return (-EIO); | ||
1496 | |||
1497 | printk(KERN_INFO "%s:I: Reading back %d frames from drive buffer%s\n", | ||
1498 | name, nframes, pending?" and one that was pending":""); | ||
1499 | |||
1500 | osst_copy_from_buffer(STp->buffer, (p = &buffer[nframes * OS_DATA_SIZE])); | ||
1501 | #if DEBUG | ||
1502 | if (pending && debugging) | ||
1503 | printk(OSST_DEB_MSG "%s:D: Pending frame %d (lblk %d), data %02x %02x %02x %02x\n", | ||
1504 | name, frame_seq_number + nframes, | ||
1505 | logical_blk_num + nframes * blks_per_frame, | ||
1506 | p[0], p[1], p[2], p[3]); | ||
1507 | #endif | ||
1508 | for (i = 0, p = buffer; i < nframes; i++, p += OS_DATA_SIZE) { | ||
1509 | |||
1510 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1511 | cmd[0] = 0x3C; /* Buffer Read */ | ||
1512 | cmd[1] = 6; /* Retrieve Faulty Block */ | ||
1513 | cmd[7] = 32768 >> 8; | ||
1514 | cmd[8] = 32768 & 0xff; | ||
1515 | |||
1516 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_FROM_DEVICE, | ||
1517 | STp->timeout, MAX_RETRIES, 1); | ||
1518 | |||
1519 | if ((STp->buffer)->syscall_result || !SRpnt) { | ||
1520 | printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); | ||
1521 | vfree(buffer); | ||
1522 | *aSRpnt = SRpnt; | ||
1523 | return (-EIO); | ||
1524 | } | ||
1525 | osst_copy_from_buffer(STp->buffer, p); | ||
1526 | #if DEBUG | ||
1527 | if (debugging) | ||
1528 | printk(OSST_DEB_MSG "%s:D: Read back logical frame %d, data %02x %02x %02x %02x\n", | ||
1529 | name, frame_seq_number + i, p[0], p[1], p[2], p[3]); | ||
1530 | #endif | ||
1531 | } | ||
1532 | *aSRpnt = SRpnt; | ||
1533 | osst_get_frame_position(STp, aSRpnt); | ||
1534 | |||
1535 | #if DEBUG | ||
1536 | printk(OSST_DEB_MSG "%s:D: Frames left in buffer: %d\n", name, STp->cur_frames); | ||
1537 | #endif | ||
1538 | /* Write synchronously so we can be sure we're OK again and don't have to recover recursively */ | ||
1539 | /* In the header we don't actually re-write the frames that fail, just the ones after them */ | ||
1540 | |||
1541 | for (flag=1, new_frame=frame, p=buffer, i=0; i < nframes + pending; ) { | ||
1542 | |||
1543 | if (flag) { | ||
1544 | if (STp->write_type == OS_WRITE_HEADER) { | ||
1545 | i += skip; | ||
1546 | p += skip * OS_DATA_SIZE; | ||
1547 | } | ||
1548 | else if (new_frame < 2990 && new_frame+skip+nframes+pending >= 2990) | ||
1549 | new_frame = 3000-i; | ||
1550 | else | ||
1551 | new_frame += skip; | ||
1552 | #if DEBUG | ||
1553 | printk(OSST_DEB_MSG "%s:D: Position to frame %d, write fseq %d\n", | ||
1554 | name, new_frame+i, frame_seq_number+i); | ||
1555 | #endif | ||
1556 | osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); | ||
1557 | osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE); | ||
1558 | osst_get_frame_position(STp, aSRpnt); | ||
1559 | SRpnt = * aSRpnt; | ||
1560 | |||
1561 | if (new_frame > frame + 1000) { | ||
1562 | printk(KERN_ERR "%s:E: Failed to find writable tape media\n", name); | ||
1563 | vfree(buffer); | ||
1564 | return (-EIO); | ||
1565 | } | ||
1566 | if ( i >= nframes + pending ) break; | ||
1567 | flag = 0; | ||
1568 | } | ||
1569 | osst_copy_to_buffer(STp->buffer, p); | ||
1570 | /* | ||
1571 | * IMPORTANT: for error recovery to work, _never_ queue frames with mixed frame type! | ||
1572 | */ | ||
1573 | osst_init_aux(STp, STp->buffer->aux->frame_type, frame_seq_number+i, | ||
1574 | logical_blk_num + i*blks_per_frame, | ||
1575 | ntohl(STp->buffer->aux->dat.dat_list[0].blk_sz), blks_per_frame); | ||
1576 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1577 | cmd[0] = WRITE_6; | ||
1578 | cmd[1] = 1; | ||
1579 | cmd[4] = 1; | ||
1580 | |||
1581 | #if DEBUG | ||
1582 | if (debugging) | ||
1583 | printk(OSST_DEB_MSG | ||
1584 | "%s:D: About to write frame %d, seq %d, lbn %d, data %02x %02x %02x %02x\n", | ||
1585 | name, new_frame+i, frame_seq_number+i, logical_blk_num + i*blks_per_frame, | ||
1586 | p[0], p[1], p[2], p[3]); | ||
1587 | #endif | ||
1588 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, | ||
1589 | STp->timeout, MAX_RETRIES, 1); | ||
1590 | |||
1591 | if (STp->buffer->syscall_result) | ||
1592 | flag = 1; | ||
1593 | else { | ||
1594 | p += OS_DATA_SIZE; i++; | ||
1595 | |||
1596 | /* if we just sent the last frame, wait till all successfully written */ | ||
1597 | if ( i == nframes + pending ) { | ||
1598 | #if DEBUG | ||
1599 | printk(OSST_DEB_MSG "%s:D: Check re-write successful\n", name); | ||
1600 | #endif | ||
1601 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1602 | cmd[0] = WRITE_FILEMARKS; | ||
1603 | cmd[1] = 1; | ||
1604 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, | ||
1605 | STp->timeout, MAX_RETRIES, 1); | ||
1606 | #if DEBUG | ||
1607 | if (debugging) { | ||
1608 | printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); | ||
1609 | printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); | ||
1610 | debugging = 0; | ||
1611 | } | ||
1612 | #endif | ||
1613 | flag = STp->buffer->syscall_result; | ||
1614 | while ( !flag && time_before(jiffies, startwait + 60*HZ) ) { | ||
1615 | |||
1616 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1617 | cmd[0] = TEST_UNIT_READY; | ||
1618 | |||
1619 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, STp->timeout, | ||
1620 | MAX_RETRIES, 1); | ||
1621 | |||
1622 | if (SRpnt->sense[2] == 2 && SRpnt->sense[12] == 4 && | ||
1623 | (SRpnt->sense[13] == 1 || SRpnt->sense[13] == 8)) { | ||
1624 | /* in the process of becoming ready */ | ||
1625 | msleep(100); | ||
1626 | continue; | ||
1627 | } | ||
1628 | if (STp->buffer->syscall_result) | ||
1629 | flag = 1; | ||
1630 | break; | ||
1631 | } | ||
1632 | #if DEBUG | ||
1633 | debugging = dbg; | ||
1634 | printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); | ||
1635 | #endif | ||
1636 | } | ||
1637 | } | ||
1638 | *aSRpnt = SRpnt; | ||
1639 | if (flag) { | ||
1640 | if ((SRpnt->sense[ 2] & 0x0f) == 13 && | ||
1641 | SRpnt->sense[12] == 0 && | ||
1642 | SRpnt->sense[13] == 2) { | ||
1643 | printk(KERN_ERR "%s:E: Volume overflow in write error recovery\n", name); | ||
1644 | vfree(buffer); | ||
1645 | return (-EIO); /* hit end of tape = fail */ | ||
1646 | } | ||
1647 | i = ((SRpnt->sense[3] << 24) | | ||
1648 | (SRpnt->sense[4] << 16) | | ||
1649 | (SRpnt->sense[5] << 8) | | ||
1650 | SRpnt->sense[6] ) - new_frame; | ||
1651 | p = &buffer[i * OS_DATA_SIZE]; | ||
1652 | #if DEBUG | ||
1653 | printk(OSST_DEB_MSG "%s:D: Additional write error at %d\n", name, new_frame+i); | ||
1654 | #endif | ||
1655 | osst_get_frame_position(STp, aSRpnt); | ||
1656 | #if DEBUG | ||
1657 | printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d, buffer = %d\n", | ||
1658 | name, STp->first_frame_position, STp->last_frame_position, STp->cur_frames); | ||
1659 | #endif | ||
1660 | } | ||
1661 | } | ||
1662 | if (flag) { | ||
1663 | /* error recovery did not successfully complete */ | ||
1664 | printk(KERN_ERR "%s:D: Write error recovery failed in %s\n", name, | ||
1665 | STp->write_type == OS_WRITE_HEADER?"header":"body"); | ||
1666 | } | ||
1667 | if (!pending) | ||
1668 | osst_copy_to_buffer(STp->buffer, p); /* so buffer content == at entry in all cases */ | ||
1669 | vfree(buffer); | ||
1670 | return 0; | ||
1671 | } | ||
1672 | |||
1673 | static int osst_reposition_and_retry(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
1674 | unsigned int frame, unsigned int skip, int pending) | ||
1675 | { | ||
1676 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
1677 | struct osst_request * SRpnt; | ||
1678 | char * name = tape_name(STp); | ||
1679 | int expected = 0; | ||
1680 | int attempts = 1000 / skip; | ||
1681 | int flag = 1; | ||
1682 | unsigned long startwait = jiffies; | ||
1683 | #if DEBUG | ||
1684 | int dbg = debugging; | ||
1685 | #endif | ||
1686 | |||
1687 | while (attempts && time_before(jiffies, startwait + 60*HZ)) { | ||
1688 | if (flag) { | ||
1689 | #if DEBUG | ||
1690 | debugging = dbg; | ||
1691 | #endif | ||
1692 | if (frame < 2990 && frame+skip+STp->cur_frames+pending >= 2990) | ||
1693 | frame = 3000-skip; | ||
1694 | expected = frame+skip+STp->cur_frames+pending; | ||
1695 | #if DEBUG | ||
1696 | printk(OSST_DEB_MSG "%s:D: Position to fppos %d, re-write from fseq %d\n", | ||
1697 | name, frame+skip, STp->frame_seq_number-STp->cur_frames-pending); | ||
1698 | #endif | ||
1699 | osst_set_frame_position(STp, aSRpnt, frame + skip, 1); | ||
1700 | flag = 0; | ||
1701 | attempts--; | ||
1702 | schedule_timeout_interruptible(msecs_to_jiffies(100)); | ||
1703 | } | ||
1704 | if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ | ||
1705 | #if DEBUG | ||
1706 | printk(OSST_DEB_MSG "%s:D: Addl error, host %d, tape %d, buffer %d\n", | ||
1707 | name, STp->first_frame_position, | ||
1708 | STp->last_frame_position, STp->cur_frames); | ||
1709 | #endif | ||
1710 | frame = STp->last_frame_position; | ||
1711 | flag = 1; | ||
1712 | continue; | ||
1713 | } | ||
1714 | if (pending && STp->cur_frames < 50) { | ||
1715 | |||
1716 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
1717 | cmd[0] = WRITE_6; | ||
1718 | cmd[1] = 1; | ||
1719 | cmd[4] = 1; | ||
1720 | #if DEBUG | ||
1721 | printk(OSST_DEB_MSG "%s:D: About to write pending fseq %d at fppos %d\n", | ||
1722 | name, STp->frame_seq_number-1, STp->first_frame_position); | ||
1723 | #endif | ||
1724 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, | ||
1725 | STp->timeout, MAX_RETRIES, 1); | ||
1726 | *aSRpnt = SRpnt; | ||
1727 | |||
1728 | if (STp->buffer->syscall_result) { /* additional write error */ | ||
1729 | if ((SRpnt->sense[ 2] & 0x0f) == 13 && | ||
1730 | SRpnt->sense[12] == 0 && | ||
1731 | SRpnt->sense[13] == 2) { | ||
1732 | printk(KERN_ERR | ||
1733 | "%s:E: Volume overflow in write error recovery\n", | ||
1734 | name); | ||
1735 | break; /* hit end of tape = fail */ | ||
1736 | } | ||
1737 | flag = 1; | ||
1738 | } | ||
1739 | else | ||
1740 | pending = 0; | ||
1741 | |||
1742 | continue; | ||
1743 | } | ||
1744 | if (STp->cur_frames == 0) { | ||
1745 | #if DEBUG | ||
1746 | debugging = dbg; | ||
1747 | printk(OSST_DEB_MSG "%s:D: Wait re-write finished\n", name); | ||
1748 | #endif | ||
1749 | if (STp->first_frame_position != expected) { | ||
1750 | printk(KERN_ERR "%s:A: Actual position %d - expected %d\n", | ||
1751 | name, STp->first_frame_position, expected); | ||
1752 | return (-EIO); | ||
1753 | } | ||
1754 | return 0; | ||
1755 | } | ||
1756 | #if DEBUG | ||
1757 | if (debugging) { | ||
1758 | printk(OSST_DEB_MSG "%s:D: Sleeping in re-write wait ready\n", name); | ||
1759 | printk(OSST_DEB_MSG "%s:D: Turning off debugging for a while\n", name); | ||
1760 | debugging = 0; | ||
1761 | } | ||
1762 | #endif | ||
1763 | schedule_timeout_interruptible(msecs_to_jiffies(100)); | ||
1764 | } | ||
1765 | printk(KERN_ERR "%s:E: Failed to find valid tape media\n", name); | ||
1766 | #if DEBUG | ||
1767 | debugging = dbg; | ||
1768 | #endif | ||
1769 | return (-EIO); | ||
1770 | } | ||
1771 | |||
1772 | /* | ||
1773 | * Error recovery algorithm for the OnStream tape. | ||
1774 | */ | ||
1775 | |||
1776 | static int osst_write_error_recovery(struct osst_tape * STp, struct osst_request ** aSRpnt, int pending) | ||
1777 | { | ||
1778 | struct osst_request * SRpnt = * aSRpnt; | ||
1779 | struct st_partstat * STps = & STp->ps[STp->partition]; | ||
1780 | char * name = tape_name(STp); | ||
1781 | int retval = 0; | ||
1782 | int rw_state; | ||
1783 | unsigned int frame, skip; | ||
1784 | |||
1785 | rw_state = STps->rw; | ||
1786 | |||
1787 | if ((SRpnt->sense[ 2] & 0x0f) != 3 | ||
1788 | || SRpnt->sense[12] != 12 | ||
1789 | || SRpnt->sense[13] != 0) { | ||
1790 | #if DEBUG | ||
1791 | printk(OSST_DEB_MSG "%s:D: Write error recovery cannot handle %02x:%02x:%02x\n", name, | ||
1792 | SRpnt->sense[2], SRpnt->sense[12], SRpnt->sense[13]); | ||
1793 | #endif | ||
1794 | return (-EIO); | ||
1795 | } | ||
1796 | frame = (SRpnt->sense[3] << 24) | | ||
1797 | (SRpnt->sense[4] << 16) | | ||
1798 | (SRpnt->sense[5] << 8) | | ||
1799 | SRpnt->sense[6]; | ||
1800 | skip = SRpnt->sense[9]; | ||
1801 | |||
1802 | #if DEBUG | ||
1803 | printk(OSST_DEB_MSG "%s:D: Detected physical bad frame at %u, advised to skip %d\n", name, frame, skip); | ||
1804 | #endif | ||
1805 | osst_get_frame_position(STp, aSRpnt); | ||
1806 | #if DEBUG | ||
1807 | printk(OSST_DEB_MSG "%s:D: reported frame positions: host = %d, tape = %d\n", | ||
1808 | name, STp->first_frame_position, STp->last_frame_position); | ||
1809 | #endif | ||
1810 | switch (STp->write_type) { | ||
1811 | case OS_WRITE_DATA: | ||
1812 | case OS_WRITE_EOD: | ||
1813 | case OS_WRITE_NEW_MARK: | ||
1814 | printk(KERN_WARNING | ||
1815 | "%s:I: Relocating %d buffered logical frames from position %u to %u\n", | ||
1816 | name, STp->cur_frames, frame, (frame + skip > 3000 && frame < 3000)?3000:frame + skip); | ||
1817 | if (STp->os_fw_rev >= 10600) | ||
1818 | retval = osst_reposition_and_retry(STp, aSRpnt, frame, skip, pending); | ||
1819 | else | ||
1820 | retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, skip, pending); | ||
1821 | printk(KERN_WARNING "%s:%s: %sWrite error%srecovered\n", name, | ||
1822 | retval?"E" :"I", | ||
1823 | retval?"" :"Don't worry, ", | ||
1824 | retval?" not ":" "); | ||
1825 | break; | ||
1826 | case OS_WRITE_LAST_MARK: | ||
1827 | printk(KERN_ERR "%s:E: Bad frame in update last marker, fatal\n", name); | ||
1828 | osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); | ||
1829 | retval = -EIO; | ||
1830 | break; | ||
1831 | case OS_WRITE_HEADER: | ||
1832 | printk(KERN_WARNING "%s:I: Bad frame in header partition, skipped\n", name); | ||
1833 | retval = osst_read_back_buffer_and_rewrite(STp, aSRpnt, frame, 1, pending); | ||
1834 | break; | ||
1835 | default: | ||
1836 | printk(KERN_INFO "%s:I: Bad frame in filler, ignored\n", name); | ||
1837 | osst_set_frame_position(STp, aSRpnt, frame + STp->cur_frames + pending, 0); | ||
1838 | } | ||
1839 | osst_get_frame_position(STp, aSRpnt); | ||
1840 | #if DEBUG | ||
1841 | printk(OSST_DEB_MSG "%s:D: Positioning complete, cur_frames %d, pos %d, tape pos %d\n", | ||
1842 | name, STp->cur_frames, STp->first_frame_position, STp->last_frame_position); | ||
1843 | printk(OSST_DEB_MSG "%s:D: next logical frame to write: %d\n", name, STp->logical_blk_num); | ||
1844 | #endif | ||
1845 | if (retval == 0) { | ||
1846 | STp->recover_count++; | ||
1847 | STp->recover_erreg++; | ||
1848 | } else | ||
1849 | STp->abort_count++; | ||
1850 | |||
1851 | STps->rw = rw_state; | ||
1852 | return retval; | ||
1853 | } | ||
1854 | |||
1855 | static int osst_space_over_filemarks_backward(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
1856 | int mt_op, int mt_count) | ||
1857 | { | ||
1858 | char * name = tape_name(STp); | ||
1859 | int cnt; | ||
1860 | int last_mark_ppos = -1; | ||
1861 | |||
1862 | #if DEBUG | ||
1863 | printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_backwards %d %d\n", name, mt_op, mt_count); | ||
1864 | #endif | ||
1865 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
1866 | #if DEBUG | ||
1867 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_bwd\n", name); | ||
1868 | #endif | ||
1869 | return -EIO; | ||
1870 | } | ||
1871 | if (STp->linux_media_version >= 4) { | ||
1872 | /* | ||
1873 | * direct lookup in header filemark list | ||
1874 | */ | ||
1875 | cnt = ntohl(STp->buffer->aux->filemark_cnt); | ||
1876 | if (STp->header_ok && | ||
1877 | STp->header_cache != NULL && | ||
1878 | (cnt - mt_count) >= 0 && | ||
1879 | (cnt - mt_count) < OS_FM_TAB_MAX && | ||
1880 | (cnt - mt_count) < STp->filemark_cnt && | ||
1881 | STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == STp->buffer->aux->last_mark_ppos) | ||
1882 | |||
1883 | last_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt - mt_count]); | ||
1884 | #if DEBUG | ||
1885 | if (STp->header_cache == NULL || (cnt - mt_count) < 0 || (cnt - mt_count) >= OS_FM_TAB_MAX) | ||
1886 | printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, | ||
1887 | STp->header_cache == NULL?"lack of header cache":"count out of range"); | ||
1888 | else | ||
1889 | printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", | ||
1890 | name, cnt, | ||
1891 | ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || | ||
1892 | (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt-1] == | ||
1893 | STp->buffer->aux->last_mark_ppos))?"match":"error", | ||
1894 | mt_count, last_mark_ppos); | ||
1895 | #endif | ||
1896 | if (last_mark_ppos > 10 && last_mark_ppos < STp->eod_frame_ppos) { | ||
1897 | osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); | ||
1898 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
1899 | #if DEBUG | ||
1900 | printk(OSST_DEB_MSG | ||
1901 | "%s:D: Couldn't get logical blk num in space_filemarks\n", name); | ||
1902 | #endif | ||
1903 | return (-EIO); | ||
1904 | } | ||
1905 | if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { | ||
1906 | printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", | ||
1907 | name, last_mark_ppos); | ||
1908 | return (-EIO); | ||
1909 | } | ||
1910 | goto found; | ||
1911 | } | ||
1912 | #if DEBUG | ||
1913 | printk(OSST_DEB_MSG "%s:D: Reverting to scan filemark backwards\n", name); | ||
1914 | #endif | ||
1915 | } | ||
1916 | cnt = 0; | ||
1917 | while (cnt != mt_count) { | ||
1918 | last_mark_ppos = ntohl(STp->buffer->aux->last_mark_ppos); | ||
1919 | if (last_mark_ppos == -1) | ||
1920 | return (-EIO); | ||
1921 | #if DEBUG | ||
1922 | printk(OSST_DEB_MSG "%s:D: Positioning to last mark at %d\n", name, last_mark_ppos); | ||
1923 | #endif | ||
1924 | osst_position_tape_and_confirm(STp, aSRpnt, last_mark_ppos); | ||
1925 | cnt++; | ||
1926 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
1927 | #if DEBUG | ||
1928 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); | ||
1929 | #endif | ||
1930 | return (-EIO); | ||
1931 | } | ||
1932 | if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { | ||
1933 | printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", | ||
1934 | name, last_mark_ppos); | ||
1935 | return (-EIO); | ||
1936 | } | ||
1937 | } | ||
1938 | found: | ||
1939 | if (mt_op == MTBSFM) { | ||
1940 | STp->frame_seq_number++; | ||
1941 | STp->frame_in_buffer = 0; | ||
1942 | STp->buffer->buffer_bytes = 0; | ||
1943 | STp->buffer->read_pointer = 0; | ||
1944 | STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); | ||
1945 | } | ||
1946 | return 0; | ||
1947 | } | ||
1948 | |||
1949 | /* | ||
1950 | * ADRL 1.1 compatible "slow" space filemarks fwd version | ||
1951 | * | ||
1952 | * Just scans for the filemark sequentially. | ||
1953 | */ | ||
1954 | static int osst_space_over_filemarks_forward_slow(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
1955 | int mt_op, int mt_count) | ||
1956 | { | ||
1957 | int cnt = 0; | ||
1958 | #if DEBUG | ||
1959 | char * name = tape_name(STp); | ||
1960 | |||
1961 | printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_slow %d %d\n", name, mt_op, mt_count); | ||
1962 | #endif | ||
1963 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
1964 | #if DEBUG | ||
1965 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); | ||
1966 | #endif | ||
1967 | return (-EIO); | ||
1968 | } | ||
1969 | while (1) { | ||
1970 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
1971 | #if DEBUG | ||
1972 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", name); | ||
1973 | #endif | ||
1974 | return (-EIO); | ||
1975 | } | ||
1976 | if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) | ||
1977 | cnt++; | ||
1978 | if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { | ||
1979 | #if DEBUG | ||
1980 | printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); | ||
1981 | #endif | ||
1982 | if (STp->first_frame_position > STp->eod_frame_ppos+1) { | ||
1983 | #if DEBUG | ||
1984 | printk(OSST_DEB_MSG "%s:D: EOD position corrected (%d=>%d)\n", | ||
1985 | name, STp->eod_frame_ppos, STp->first_frame_position-1); | ||
1986 | #endif | ||
1987 | STp->eod_frame_ppos = STp->first_frame_position-1; | ||
1988 | } | ||
1989 | return (-EIO); | ||
1990 | } | ||
1991 | if (cnt == mt_count) | ||
1992 | break; | ||
1993 | STp->frame_in_buffer = 0; | ||
1994 | } | ||
1995 | if (mt_op == MTFSF) { | ||
1996 | STp->frame_seq_number++; | ||
1997 | STp->frame_in_buffer = 0; | ||
1998 | STp->buffer->buffer_bytes = 0; | ||
1999 | STp->buffer->read_pointer = 0; | ||
2000 | STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); | ||
2001 | } | ||
2002 | return 0; | ||
2003 | } | ||
2004 | |||
2005 | /* | ||
2006 | * Fast linux specific version of OnStream FSF | ||
2007 | */ | ||
2008 | static int osst_space_over_filemarks_forward_fast(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
2009 | int mt_op, int mt_count) | ||
2010 | { | ||
2011 | char * name = tape_name(STp); | ||
2012 | int cnt = 0, | ||
2013 | next_mark_ppos = -1; | ||
2014 | |||
2015 | #if DEBUG | ||
2016 | printk(OSST_DEB_MSG "%s:D: Reached space_over_filemarks_forward_fast %d %d\n", name, mt_op, mt_count); | ||
2017 | #endif | ||
2018 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
2019 | #if DEBUG | ||
2020 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks_fwd\n", name); | ||
2021 | #endif | ||
2022 | return (-EIO); | ||
2023 | } | ||
2024 | |||
2025 | if (STp->linux_media_version >= 4) { | ||
2026 | /* | ||
2027 | * direct lookup in header filemark list | ||
2028 | */ | ||
2029 | cnt = ntohl(STp->buffer->aux->filemark_cnt) - 1; | ||
2030 | if (STp->header_ok && | ||
2031 | STp->header_cache != NULL && | ||
2032 | (cnt + mt_count) < OS_FM_TAB_MAX && | ||
2033 | (cnt + mt_count) < STp->filemark_cnt && | ||
2034 | ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || | ||
2035 | (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == STp->buffer->aux->last_mark_ppos))) | ||
2036 | |||
2037 | next_mark_ppos = ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[cnt + mt_count]); | ||
2038 | #if DEBUG | ||
2039 | if (STp->header_cache == NULL || (cnt + mt_count) >= OS_FM_TAB_MAX) | ||
2040 | printk(OSST_DEB_MSG "%s:D: Filemark lookup fail due to %s\n", name, | ||
2041 | STp->header_cache == NULL?"lack of header cache":"count out of range"); | ||
2042 | else | ||
2043 | printk(OSST_DEB_MSG "%s:D: Filemark lookup: prev mark %d (%s), skip %d to %d\n", | ||
2044 | name, cnt, | ||
2045 | ((cnt == -1 && ntohl(STp->buffer->aux->last_mark_ppos) == -1) || | ||
2046 | (STp->header_cache->dat_fm_tab.fm_tab_ent[cnt] == | ||
2047 | STp->buffer->aux->last_mark_ppos))?"match":"error", | ||
2048 | mt_count, next_mark_ppos); | ||
2049 | #endif | ||
2050 | if (next_mark_ppos <= 10 || next_mark_ppos > STp->eod_frame_ppos) { | ||
2051 | #if DEBUG | ||
2052 | printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); | ||
2053 | #endif | ||
2054 | return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); | ||
2055 | } else { | ||
2056 | osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); | ||
2057 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
2058 | #if DEBUG | ||
2059 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", | ||
2060 | name); | ||
2061 | #endif | ||
2062 | return (-EIO); | ||
2063 | } | ||
2064 | if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { | ||
2065 | printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", | ||
2066 | name, next_mark_ppos); | ||
2067 | return (-EIO); | ||
2068 | } | ||
2069 | if (ntohl(STp->buffer->aux->filemark_cnt) != cnt + mt_count) { | ||
2070 | printk(KERN_WARNING "%s:W: Expected to find marker %d at ppos %d, not %d\n", | ||
2071 | name, cnt+mt_count, next_mark_ppos, | ||
2072 | ntohl(STp->buffer->aux->filemark_cnt)); | ||
2073 | return (-EIO); | ||
2074 | } | ||
2075 | } | ||
2076 | } else { | ||
2077 | /* | ||
2078 | * Find nearest (usually previous) marker, then jump from marker to marker | ||
2079 | */ | ||
2080 | while (1) { | ||
2081 | if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER) | ||
2082 | break; | ||
2083 | if (STp->buffer->aux->frame_type == OS_FRAME_TYPE_EOD) { | ||
2084 | #if DEBUG | ||
2085 | printk(OSST_DEB_MSG "%s:D: space_fwd: EOD reached\n", name); | ||
2086 | #endif | ||
2087 | return (-EIO); | ||
2088 | } | ||
2089 | if (ntohl(STp->buffer->aux->filemark_cnt) == 0) { | ||
2090 | if (STp->first_mark_ppos == -1) { | ||
2091 | #if DEBUG | ||
2092 | printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); | ||
2093 | #endif | ||
2094 | return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count); | ||
2095 | } | ||
2096 | osst_position_tape_and_confirm(STp, aSRpnt, STp->first_mark_ppos); | ||
2097 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
2098 | #if DEBUG | ||
2099 | printk(OSST_DEB_MSG | ||
2100 | "%s:D: Couldn't get logical blk num in space_filemarks_fwd_fast\n", | ||
2101 | name); | ||
2102 | #endif | ||
2103 | return (-EIO); | ||
2104 | } | ||
2105 | if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { | ||
2106 | printk(KERN_WARNING "%s:W: Expected to find filemark at %d\n", | ||
2107 | name, STp->first_mark_ppos); | ||
2108 | return (-EIO); | ||
2109 | } | ||
2110 | } else { | ||
2111 | if (osst_space_over_filemarks_backward(STp, aSRpnt, MTBSF, 1) < 0) | ||
2112 | return (-EIO); | ||
2113 | mt_count++; | ||
2114 | } | ||
2115 | } | ||
2116 | cnt++; | ||
2117 | while (cnt != mt_count) { | ||
2118 | next_mark_ppos = ntohl(STp->buffer->aux->next_mark_ppos); | ||
2119 | if (!next_mark_ppos || next_mark_ppos > STp->eod_frame_ppos) { | ||
2120 | #if DEBUG | ||
2121 | printk(OSST_DEB_MSG "%s:D: Reverting to slow filemark space\n", name); | ||
2122 | #endif | ||
2123 | return osst_space_over_filemarks_forward_slow(STp, aSRpnt, mt_op, mt_count - cnt); | ||
2124 | } | ||
2125 | #if DEBUG | ||
2126 | else printk(OSST_DEB_MSG "%s:D: Positioning to next mark at %d\n", name, next_mark_ppos); | ||
2127 | #endif | ||
2128 | osst_position_tape_and_confirm(STp, aSRpnt, next_mark_ppos); | ||
2129 | cnt++; | ||
2130 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
2131 | #if DEBUG | ||
2132 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in space_filemarks\n", | ||
2133 | name); | ||
2134 | #endif | ||
2135 | return (-EIO); | ||
2136 | } | ||
2137 | if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_MARKER) { | ||
2138 | printk(KERN_WARNING "%s:W: Expected to find marker at ppos %d, not found\n", | ||
2139 | name, next_mark_ppos); | ||
2140 | return (-EIO); | ||
2141 | } | ||
2142 | } | ||
2143 | } | ||
2144 | if (mt_op == MTFSF) { | ||
2145 | STp->frame_seq_number++; | ||
2146 | STp->frame_in_buffer = 0; | ||
2147 | STp->buffer->buffer_bytes = 0; | ||
2148 | STp->buffer->read_pointer = 0; | ||
2149 | STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); | ||
2150 | } | ||
2151 | return 0; | ||
2152 | } | ||
2153 | |||
2154 | /* | ||
2155 | * In debug mode, we want to see as many errors as possible | ||
2156 | * to test the error recovery mechanism. | ||
2157 | */ | ||
2158 | #if DEBUG | ||
2159 | static void osst_set_retries(struct osst_tape * STp, struct osst_request ** aSRpnt, int retries) | ||
2160 | { | ||
2161 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
2162 | struct osst_request * SRpnt = * aSRpnt; | ||
2163 | char * name = tape_name(STp); | ||
2164 | |||
2165 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
2166 | cmd[0] = MODE_SELECT; | ||
2167 | cmd[1] = 0x10; | ||
2168 | cmd[4] = NUMBER_RETRIES_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
2169 | |||
2170 | (STp->buffer)->b_data[0] = cmd[4] - 1; | ||
2171 | (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ | ||
2172 | (STp->buffer)->b_data[2] = 0; /* Reserved */ | ||
2173 | (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ | ||
2174 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = NUMBER_RETRIES_PAGE | (1 << 7); | ||
2175 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 2; | ||
2176 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 4; | ||
2177 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = retries; | ||
2178 | |||
2179 | if (debugging) | ||
2180 | printk(OSST_DEB_MSG "%s:D: Setting number of retries on OnStream tape to %d\n", name, retries); | ||
2181 | |||
2182 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); | ||
2183 | *aSRpnt = SRpnt; | ||
2184 | |||
2185 | if ((STp->buffer)->syscall_result) | ||
2186 | printk (KERN_ERR "%s:D: Couldn't set retries to %d\n", name, retries); | ||
2187 | } | ||
2188 | #endif | ||
2189 | |||
2190 | |||
2191 | static int osst_write_filemark(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
2192 | { | ||
2193 | int result; | ||
2194 | int this_mark_ppos = STp->first_frame_position; | ||
2195 | int this_mark_lbn = STp->logical_blk_num; | ||
2196 | #if DEBUG | ||
2197 | char * name = tape_name(STp); | ||
2198 | #endif | ||
2199 | |||
2200 | if (STp->raw) return 0; | ||
2201 | |||
2202 | STp->write_type = OS_WRITE_NEW_MARK; | ||
2203 | #if DEBUG | ||
2204 | printk(OSST_DEB_MSG "%s:D: Writing Filemark %i at fppos %d (fseq %d, lblk %d)\n", | ||
2205 | name, STp->filemark_cnt, this_mark_ppos, STp->frame_seq_number, this_mark_lbn); | ||
2206 | #endif | ||
2207 | STp->dirty = 1; | ||
2208 | result = osst_flush_write_buffer(STp, aSRpnt); | ||
2209 | result |= osst_flush_drive_buffer(STp, aSRpnt); | ||
2210 | STp->last_mark_ppos = this_mark_ppos; | ||
2211 | STp->last_mark_lbn = this_mark_lbn; | ||
2212 | if (STp->header_cache != NULL && STp->filemark_cnt < OS_FM_TAB_MAX) | ||
2213 | STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt] = htonl(this_mark_ppos); | ||
2214 | if (STp->filemark_cnt++ == 0) | ||
2215 | STp->first_mark_ppos = this_mark_ppos; | ||
2216 | return result; | ||
2217 | } | ||
2218 | |||
2219 | static int osst_write_eod(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
2220 | { | ||
2221 | int result; | ||
2222 | #if DEBUG | ||
2223 | char * name = tape_name(STp); | ||
2224 | #endif | ||
2225 | |||
2226 | if (STp->raw) return 0; | ||
2227 | |||
2228 | STp->write_type = OS_WRITE_EOD; | ||
2229 | STp->eod_frame_ppos = STp->first_frame_position; | ||
2230 | #if DEBUG | ||
2231 | printk(OSST_DEB_MSG "%s:D: Writing EOD at fppos %d (fseq %d, lblk %d)\n", name, | ||
2232 | STp->eod_frame_ppos, STp->frame_seq_number, STp->logical_blk_num); | ||
2233 | #endif | ||
2234 | STp->dirty = 1; | ||
2235 | |||
2236 | result = osst_flush_write_buffer(STp, aSRpnt); | ||
2237 | result |= osst_flush_drive_buffer(STp, aSRpnt); | ||
2238 | STp->eod_frame_lfa = --(STp->frame_seq_number); | ||
2239 | return result; | ||
2240 | } | ||
2241 | |||
2242 | static int osst_write_filler(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) | ||
2243 | { | ||
2244 | char * name = tape_name(STp); | ||
2245 | |||
2246 | #if DEBUG | ||
2247 | printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where); | ||
2248 | #endif | ||
2249 | osst_wait_ready(STp, aSRpnt, 60 * 5, 0); | ||
2250 | osst_set_frame_position(STp, aSRpnt, where, 0); | ||
2251 | STp->write_type = OS_WRITE_FILLER; | ||
2252 | while (count--) { | ||
2253 | memcpy(STp->buffer->b_data, "Filler", 6); | ||
2254 | STp->buffer->buffer_bytes = 6; | ||
2255 | STp->dirty = 1; | ||
2256 | if (osst_flush_write_buffer(STp, aSRpnt)) { | ||
2257 | printk(KERN_INFO "%s:I: Couldn't write filler frame\n", name); | ||
2258 | return (-EIO); | ||
2259 | } | ||
2260 | } | ||
2261 | #if DEBUG | ||
2262 | printk(OSST_DEB_MSG "%s:D: Exiting onstream write filler group\n", name); | ||
2263 | #endif | ||
2264 | return osst_flush_drive_buffer(STp, aSRpnt); | ||
2265 | } | ||
2266 | |||
2267 | static int __osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int where, int count) | ||
2268 | { | ||
2269 | char * name = tape_name(STp); | ||
2270 | int result; | ||
2271 | |||
2272 | #if DEBUG | ||
2273 | printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where); | ||
2274 | #endif | ||
2275 | osst_wait_ready(STp, aSRpnt, 60 * 5, 0); | ||
2276 | osst_set_frame_position(STp, aSRpnt, where, 0); | ||
2277 | STp->write_type = OS_WRITE_HEADER; | ||
2278 | while (count--) { | ||
2279 | osst_copy_to_buffer(STp->buffer, (unsigned char *)STp->header_cache); | ||
2280 | STp->buffer->buffer_bytes = sizeof(os_header_t); | ||
2281 | STp->dirty = 1; | ||
2282 | if (osst_flush_write_buffer(STp, aSRpnt)) { | ||
2283 | printk(KERN_INFO "%s:I: Couldn't write header frame\n", name); | ||
2284 | return (-EIO); | ||
2285 | } | ||
2286 | } | ||
2287 | result = osst_flush_drive_buffer(STp, aSRpnt); | ||
2288 | #if DEBUG | ||
2289 | printk(OSST_DEB_MSG "%s:D: Write onstream header group %s\n", name, result?"failed":"done"); | ||
2290 | #endif | ||
2291 | return result; | ||
2292 | } | ||
2293 | |||
2294 | static int osst_write_header(struct osst_tape * STp, struct osst_request ** aSRpnt, int locate_eod) | ||
2295 | { | ||
2296 | os_header_t * header; | ||
2297 | int result; | ||
2298 | char * name = tape_name(STp); | ||
2299 | |||
2300 | #if DEBUG | ||
2301 | printk(OSST_DEB_MSG "%s:D: Writing tape header\n", name); | ||
2302 | #endif | ||
2303 | if (STp->raw) return 0; | ||
2304 | |||
2305 | if (STp->header_cache == NULL) { | ||
2306 | if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { | ||
2307 | printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); | ||
2308 | return (-ENOMEM); | ||
2309 | } | ||
2310 | memset(STp->header_cache, 0, sizeof(os_header_t)); | ||
2311 | #if DEBUG | ||
2312 | printk(OSST_DEB_MSG "%s:D: Allocated and cleared memory for header cache\n", name); | ||
2313 | #endif | ||
2314 | } | ||
2315 | if (STp->header_ok) STp->update_frame_cntr++; | ||
2316 | else STp->update_frame_cntr = 0; | ||
2317 | |||
2318 | header = STp->header_cache; | ||
2319 | strcpy(header->ident_str, "ADR_SEQ"); | ||
2320 | header->major_rev = 1; | ||
2321 | header->minor_rev = 4; | ||
2322 | header->ext_trk_tb_off = htons(17192); | ||
2323 | header->pt_par_num = 1; | ||
2324 | header->partition[0].partition_num = OS_DATA_PARTITION; | ||
2325 | header->partition[0].par_desc_ver = OS_PARTITION_VERSION; | ||
2326 | header->partition[0].wrt_pass_cntr = htons(STp->wrt_pass_cntr); | ||
2327 | header->partition[0].first_frame_ppos = htonl(STp->first_data_ppos); | ||
2328 | header->partition[0].last_frame_ppos = htonl(STp->capacity); | ||
2329 | header->partition[0].eod_frame_ppos = htonl(STp->eod_frame_ppos); | ||
2330 | header->cfg_col_width = htonl(20); | ||
2331 | header->dat_col_width = htonl(1500); | ||
2332 | header->qfa_col_width = htonl(0); | ||
2333 | header->ext_track_tb.nr_stream_part = 1; | ||
2334 | header->ext_track_tb.et_ent_sz = 32; | ||
2335 | header->ext_track_tb.dat_ext_trk_ey.et_part_num = 0; | ||
2336 | header->ext_track_tb.dat_ext_trk_ey.fmt = 1; | ||
2337 | header->ext_track_tb.dat_ext_trk_ey.fm_tab_off = htons(17736); | ||
2338 | header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi = 0; | ||
2339 | header->ext_track_tb.dat_ext_trk_ey.last_hlb = htonl(STp->eod_frame_lfa); | ||
2340 | header->ext_track_tb.dat_ext_trk_ey.last_pp = htonl(STp->eod_frame_ppos); | ||
2341 | header->dat_fm_tab.fm_part_num = 0; | ||
2342 | header->dat_fm_tab.fm_tab_ent_sz = 4; | ||
2343 | header->dat_fm_tab.fm_tab_ent_cnt = htons(STp->filemark_cnt<OS_FM_TAB_MAX? | ||
2344 | STp->filemark_cnt:OS_FM_TAB_MAX); | ||
2345 | |||
2346 | result = __osst_write_header(STp, aSRpnt, 0xbae, 5); | ||
2347 | if (STp->update_frame_cntr == 0) | ||
2348 | osst_write_filler(STp, aSRpnt, 0xbb3, 5); | ||
2349 | result &= __osst_write_header(STp, aSRpnt, 5, 5); | ||
2350 | |||
2351 | if (locate_eod) { | ||
2352 | #if DEBUG | ||
2353 | printk(OSST_DEB_MSG "%s:D: Locating back to eod frame addr %d\n", name, STp->eod_frame_ppos); | ||
2354 | #endif | ||
2355 | osst_set_frame_position(STp, aSRpnt, STp->eod_frame_ppos, 0); | ||
2356 | } | ||
2357 | if (result) | ||
2358 | printk(KERN_ERR "%s:E: Write header failed\n", name); | ||
2359 | else { | ||
2360 | memcpy(STp->application_sig, "LIN4", 4); | ||
2361 | STp->linux_media = 1; | ||
2362 | STp->linux_media_version = 4; | ||
2363 | STp->header_ok = 1; | ||
2364 | } | ||
2365 | return result; | ||
2366 | } | ||
2367 | |||
2368 | static int osst_reset_header(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
2369 | { | ||
2370 | if (STp->header_cache != NULL) | ||
2371 | memset(STp->header_cache, 0, sizeof(os_header_t)); | ||
2372 | |||
2373 | STp->logical_blk_num = STp->frame_seq_number = 0; | ||
2374 | STp->frame_in_buffer = 0; | ||
2375 | STp->eod_frame_ppos = STp->first_data_ppos = 0x0000000A; | ||
2376 | STp->filemark_cnt = 0; | ||
2377 | STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; | ||
2378 | return osst_write_header(STp, aSRpnt, 1); | ||
2379 | } | ||
2380 | |||
2381 | static int __osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt, int ppos) | ||
2382 | { | ||
2383 | char * name = tape_name(STp); | ||
2384 | os_header_t * header; | ||
2385 | os_aux_t * aux; | ||
2386 | char id_string[8]; | ||
2387 | int linux_media_version, | ||
2388 | update_frame_cntr; | ||
2389 | |||
2390 | if (STp->raw) | ||
2391 | return 1; | ||
2392 | |||
2393 | if (ppos == 5 || ppos == 0xbae || STp->buffer->syscall_result) { | ||
2394 | if (osst_set_frame_position(STp, aSRpnt, ppos, 0)) | ||
2395 | printk(KERN_WARNING "%s:W: Couldn't position tape\n", name); | ||
2396 | osst_wait_ready(STp, aSRpnt, 60 * 15, 0); | ||
2397 | if (osst_initiate_read (STp, aSRpnt)) { | ||
2398 | printk(KERN_WARNING "%s:W: Couldn't initiate read\n", name); | ||
2399 | return 0; | ||
2400 | } | ||
2401 | } | ||
2402 | if (osst_read_frame(STp, aSRpnt, 180)) { | ||
2403 | #if DEBUG | ||
2404 | printk(OSST_DEB_MSG "%s:D: Couldn't read header frame\n", name); | ||
2405 | #endif | ||
2406 | return 0; | ||
2407 | } | ||
2408 | header = (os_header_t *) STp->buffer->b_data; /* warning: only first segment addressable */ | ||
2409 | aux = STp->buffer->aux; | ||
2410 | if (aux->frame_type != OS_FRAME_TYPE_HEADER) { | ||
2411 | #if DEBUG | ||
2412 | printk(OSST_DEB_MSG "%s:D: Skipping non-header frame (%d)\n", name, ppos); | ||
2413 | #endif | ||
2414 | return 0; | ||
2415 | } | ||
2416 | if (ntohl(aux->frame_seq_num) != 0 || | ||
2417 | ntohl(aux->logical_blk_num) != 0 || | ||
2418 | aux->partition.partition_num != OS_CONFIG_PARTITION || | ||
2419 | ntohl(aux->partition.first_frame_ppos) != 0 || | ||
2420 | ntohl(aux->partition.last_frame_ppos) != 0xbb7 ) { | ||
2421 | #if DEBUG | ||
2422 | printk(OSST_DEB_MSG "%s:D: Invalid header frame (%d,%d,%d,%d,%d)\n", name, | ||
2423 | ntohl(aux->frame_seq_num), ntohl(aux->logical_blk_num), | ||
2424 | aux->partition.partition_num, ntohl(aux->partition.first_frame_ppos), | ||
2425 | ntohl(aux->partition.last_frame_ppos)); | ||
2426 | #endif | ||
2427 | return 0; | ||
2428 | } | ||
2429 | if (strncmp(header->ident_str, "ADR_SEQ", 7) != 0 && | ||
2430 | strncmp(header->ident_str, "ADR-SEQ", 7) != 0) { | ||
2431 | strlcpy(id_string, header->ident_str, 8); | ||
2432 | #if DEBUG | ||
2433 | printk(OSST_DEB_MSG "%s:D: Invalid header identification string %s\n", name, id_string); | ||
2434 | #endif | ||
2435 | return 0; | ||
2436 | } | ||
2437 | update_frame_cntr = ntohl(aux->update_frame_cntr); | ||
2438 | if (update_frame_cntr < STp->update_frame_cntr) { | ||
2439 | #if DEBUG | ||
2440 | printk(OSST_DEB_MSG "%s:D: Skipping frame %d with update_frame_counter %d<%d\n", | ||
2441 | name, ppos, update_frame_cntr, STp->update_frame_cntr); | ||
2442 | #endif | ||
2443 | return 0; | ||
2444 | } | ||
2445 | if (header->major_rev != 1 || header->minor_rev != 4 ) { | ||
2446 | #if DEBUG | ||
2447 | printk(OSST_DEB_MSG "%s:D: %s revision %d.%d detected (1.4 supported)\n", | ||
2448 | name, (header->major_rev != 1 || header->minor_rev < 2 || | ||
2449 | header->minor_rev > 4 )? "Invalid" : "Warning:", | ||
2450 | header->major_rev, header->minor_rev); | ||
2451 | #endif | ||
2452 | if (header->major_rev != 1 || header->minor_rev < 2 || header->minor_rev > 4) | ||
2453 | return 0; | ||
2454 | } | ||
2455 | #if DEBUG | ||
2456 | if (header->pt_par_num != 1) | ||
2457 | printk(KERN_INFO "%s:W: %d partitions defined, only one supported\n", | ||
2458 | name, header->pt_par_num); | ||
2459 | #endif | ||
2460 | memcpy(id_string, aux->application_sig, 4); | ||
2461 | id_string[4] = 0; | ||
2462 | if (memcmp(id_string, "LIN", 3) == 0) { | ||
2463 | STp->linux_media = 1; | ||
2464 | linux_media_version = id_string[3] - '0'; | ||
2465 | if (linux_media_version != 4) | ||
2466 | printk(KERN_INFO "%s:I: Linux media version %d detected (current 4)\n", | ||
2467 | name, linux_media_version); | ||
2468 | } else { | ||
2469 | printk(KERN_WARNING "%s:W: Non Linux media detected (%s)\n", name, id_string); | ||
2470 | return 0; | ||
2471 | } | ||
2472 | if (linux_media_version < STp->linux_media_version) { | ||
2473 | #if DEBUG | ||
2474 | printk(OSST_DEB_MSG "%s:D: Skipping frame %d with linux_media_version %d\n", | ||
2475 | name, ppos, linux_media_version); | ||
2476 | #endif | ||
2477 | return 0; | ||
2478 | } | ||
2479 | if (linux_media_version > STp->linux_media_version) { | ||
2480 | #if DEBUG | ||
2481 | printk(OSST_DEB_MSG "%s:D: Frame %d sets linux_media_version to %d\n", | ||
2482 | name, ppos, linux_media_version); | ||
2483 | #endif | ||
2484 | memcpy(STp->application_sig, id_string, 5); | ||
2485 | STp->linux_media_version = linux_media_version; | ||
2486 | STp->update_frame_cntr = -1; | ||
2487 | } | ||
2488 | if (update_frame_cntr > STp->update_frame_cntr) { | ||
2489 | #if DEBUG | ||
2490 | printk(OSST_DEB_MSG "%s:D: Frame %d sets update_frame_counter to %d\n", | ||
2491 | name, ppos, update_frame_cntr); | ||
2492 | #endif | ||
2493 | if (STp->header_cache == NULL) { | ||
2494 | if ((STp->header_cache = vmalloc(sizeof(os_header_t))) == NULL) { | ||
2495 | printk(KERN_ERR "%s:E: Failed to allocate header cache\n", name); | ||
2496 | return 0; | ||
2497 | } | ||
2498 | #if DEBUG | ||
2499 | printk(OSST_DEB_MSG "%s:D: Allocated memory for header cache\n", name); | ||
2500 | #endif | ||
2501 | } | ||
2502 | osst_copy_from_buffer(STp->buffer, (unsigned char *)STp->header_cache); | ||
2503 | header = STp->header_cache; /* further accesses from cached (full) copy */ | ||
2504 | |||
2505 | STp->wrt_pass_cntr = ntohs(header->partition[0].wrt_pass_cntr); | ||
2506 | STp->first_data_ppos = ntohl(header->partition[0].first_frame_ppos); | ||
2507 | STp->eod_frame_ppos = ntohl(header->partition[0].eod_frame_ppos); | ||
2508 | STp->eod_frame_lfa = ntohl(header->ext_track_tb.dat_ext_trk_ey.last_hlb); | ||
2509 | STp->filemark_cnt = ntohl(aux->filemark_cnt); | ||
2510 | STp->first_mark_ppos = ntohl(aux->next_mark_ppos); | ||
2511 | STp->last_mark_ppos = ntohl(aux->last_mark_ppos); | ||
2512 | STp->last_mark_lbn = ntohl(aux->last_mark_lbn); | ||
2513 | STp->update_frame_cntr = update_frame_cntr; | ||
2514 | #if DEBUG | ||
2515 | printk(OSST_DEB_MSG "%s:D: Detected write pass %d, update frame counter %d, filemark counter %d\n", | ||
2516 | name, STp->wrt_pass_cntr, STp->update_frame_cntr, STp->filemark_cnt); | ||
2517 | printk(OSST_DEB_MSG "%s:D: first data frame on tape = %d, last = %d, eod frame = %d\n", name, | ||
2518 | STp->first_data_ppos, | ||
2519 | ntohl(header->partition[0].last_frame_ppos), | ||
2520 | ntohl(header->partition[0].eod_frame_ppos)); | ||
2521 | printk(OSST_DEB_MSG "%s:D: first mark on tape = %d, last = %d, eod frame = %d\n", | ||
2522 | name, STp->first_mark_ppos, STp->last_mark_ppos, STp->eod_frame_ppos); | ||
2523 | #endif | ||
2524 | if (header->minor_rev < 4 && STp->linux_media_version == 4) { | ||
2525 | #if DEBUG | ||
2526 | printk(OSST_DEB_MSG "%s:D: Moving filemark list to ADR 1.4 location\n", name); | ||
2527 | #endif | ||
2528 | memcpy((void *)header->dat_fm_tab.fm_tab_ent, | ||
2529 | (void *)header->old_filemark_list, sizeof(header->dat_fm_tab.fm_tab_ent)); | ||
2530 | memset((void *)header->old_filemark_list, 0, sizeof(header->old_filemark_list)); | ||
2531 | } | ||
2532 | if (header->minor_rev == 4 && | ||
2533 | (header->ext_trk_tb_off != htons(17192) || | ||
2534 | header->partition[0].partition_num != OS_DATA_PARTITION || | ||
2535 | header->partition[0].par_desc_ver != OS_PARTITION_VERSION || | ||
2536 | header->partition[0].last_frame_ppos != htonl(STp->capacity) || | ||
2537 | header->cfg_col_width != htonl(20) || | ||
2538 | header->dat_col_width != htonl(1500) || | ||
2539 | header->qfa_col_width != htonl(0) || | ||
2540 | header->ext_track_tb.nr_stream_part != 1 || | ||
2541 | header->ext_track_tb.et_ent_sz != 32 || | ||
2542 | header->ext_track_tb.dat_ext_trk_ey.et_part_num != OS_DATA_PARTITION || | ||
2543 | header->ext_track_tb.dat_ext_trk_ey.fmt != 1 || | ||
2544 | header->ext_track_tb.dat_ext_trk_ey.fm_tab_off != htons(17736) || | ||
2545 | header->ext_track_tb.dat_ext_trk_ey.last_hlb_hi != 0 || | ||
2546 | header->ext_track_tb.dat_ext_trk_ey.last_pp != htonl(STp->eod_frame_ppos) || | ||
2547 | header->dat_fm_tab.fm_part_num != OS_DATA_PARTITION || | ||
2548 | header->dat_fm_tab.fm_tab_ent_sz != 4 || | ||
2549 | header->dat_fm_tab.fm_tab_ent_cnt != | ||
2550 | htons(STp->filemark_cnt<OS_FM_TAB_MAX?STp->filemark_cnt:OS_FM_TAB_MAX))) | ||
2551 | printk(KERN_WARNING "%s:W: Failed consistency check ADR 1.4 format\n", name); | ||
2552 | |||
2553 | } | ||
2554 | |||
2555 | return 1; | ||
2556 | } | ||
2557 | |||
2558 | static int osst_analyze_headers(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
2559 | { | ||
2560 | int position, ppos; | ||
2561 | int first, last; | ||
2562 | int valid = 0; | ||
2563 | char * name = tape_name(STp); | ||
2564 | |||
2565 | position = osst_get_frame_position(STp, aSRpnt); | ||
2566 | |||
2567 | if (STp->raw) { | ||
2568 | STp->header_ok = STp->linux_media = 1; | ||
2569 | STp->linux_media_version = 0; | ||
2570 | return 1; | ||
2571 | } | ||
2572 | STp->header_ok = STp->linux_media = STp->linux_media_version = 0; | ||
2573 | STp->wrt_pass_cntr = STp->update_frame_cntr = -1; | ||
2574 | STp->eod_frame_ppos = STp->first_data_ppos = -1; | ||
2575 | STp->first_mark_ppos = STp->last_mark_ppos = STp->last_mark_lbn = -1; | ||
2576 | #if DEBUG | ||
2577 | printk(OSST_DEB_MSG "%s:D: Reading header\n", name); | ||
2578 | #endif | ||
2579 | |||
2580 | /* optimization for speed - if we are positioned at ppos 10, read second group first */ | ||
2581 | /* TODO try the ADR 1.1 locations for the second group if we have no valid one yet... */ | ||
2582 | |||
2583 | first = position==10?0xbae: 5; | ||
2584 | last = position==10?0xbb3:10; | ||
2585 | |||
2586 | for (ppos = first; ppos < last; ppos++) | ||
2587 | if (__osst_analyze_headers(STp, aSRpnt, ppos)) | ||
2588 | valid = 1; | ||
2589 | |||
2590 | first = position==10? 5:0xbae; | ||
2591 | last = position==10?10:0xbb3; | ||
2592 | |||
2593 | for (ppos = first; ppos < last; ppos++) | ||
2594 | if (__osst_analyze_headers(STp, aSRpnt, ppos)) | ||
2595 | valid = 1; | ||
2596 | |||
2597 | if (!valid) { | ||
2598 | printk(KERN_ERR "%s:E: Failed to find valid ADRL header, new media?\n", name); | ||
2599 | STp->eod_frame_ppos = STp->first_data_ppos = 0; | ||
2600 | osst_set_frame_position(STp, aSRpnt, 10, 0); | ||
2601 | return 0; | ||
2602 | } | ||
2603 | if (position <= STp->first_data_ppos) { | ||
2604 | position = STp->first_data_ppos; | ||
2605 | STp->ps[0].drv_file = STp->ps[0].drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; | ||
2606 | } | ||
2607 | osst_set_frame_position(STp, aSRpnt, position, 0); | ||
2608 | STp->header_ok = 1; | ||
2609 | |||
2610 | return 1; | ||
2611 | } | ||
2612 | |||
2613 | static int osst_verify_position(struct osst_tape * STp, struct osst_request ** aSRpnt) | ||
2614 | { | ||
2615 | int frame_position = STp->first_frame_position; | ||
2616 | int frame_seq_numbr = STp->frame_seq_number; | ||
2617 | int logical_blk_num = STp->logical_blk_num; | ||
2618 | int halfway_frame = STp->frame_in_buffer; | ||
2619 | int read_pointer = STp->buffer->read_pointer; | ||
2620 | int prev_mark_ppos = -1; | ||
2621 | int actual_mark_ppos, i, n; | ||
2622 | #if DEBUG | ||
2623 | char * name = tape_name(STp); | ||
2624 | |||
2625 | printk(OSST_DEB_MSG "%s:D: Verify that the tape is really the one we think before writing\n", name); | ||
2626 | #endif | ||
2627 | osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); | ||
2628 | if (osst_get_logical_frame(STp, aSRpnt, -1, 0) < 0) { | ||
2629 | #if DEBUG | ||
2630 | printk(OSST_DEB_MSG "%s:D: Couldn't get logical blk num in verify_position\n", name); | ||
2631 | #endif | ||
2632 | return (-EIO); | ||
2633 | } | ||
2634 | if (STp->linux_media_version >= 4) { | ||
2635 | for (i=0; i<STp->filemark_cnt; i++) | ||
2636 | if ((n=ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[i])) < frame_position) | ||
2637 | prev_mark_ppos = n; | ||
2638 | } else | ||
2639 | prev_mark_ppos = frame_position - 1; /* usually - we don't really know */ | ||
2640 | actual_mark_ppos = STp->buffer->aux->frame_type == OS_FRAME_TYPE_MARKER ? | ||
2641 | frame_position - 1 : ntohl(STp->buffer->aux->last_mark_ppos); | ||
2642 | if (frame_position != STp->first_frame_position || | ||
2643 | frame_seq_numbr != STp->frame_seq_number + (halfway_frame?0:1) || | ||
2644 | prev_mark_ppos != actual_mark_ppos ) { | ||
2645 | #if DEBUG | ||
2646 | printk(OSST_DEB_MSG "%s:D: Block mismatch: fppos %d-%d, fseq %d-%d, mark %d-%d\n", name, | ||
2647 | STp->first_frame_position, frame_position, | ||
2648 | STp->frame_seq_number + (halfway_frame?0:1), | ||
2649 | frame_seq_numbr, actual_mark_ppos, prev_mark_ppos); | ||
2650 | #endif | ||
2651 | return (-EIO); | ||
2652 | } | ||
2653 | if (halfway_frame) { | ||
2654 | /* prepare buffer for append and rewrite on top of original */ | ||
2655 | osst_set_frame_position(STp, aSRpnt, frame_position - 1, 0); | ||
2656 | STp->buffer->buffer_bytes = read_pointer; | ||
2657 | STp->ps[STp->partition].rw = ST_WRITING; | ||
2658 | STp->dirty = 1; | ||
2659 | } | ||
2660 | STp->frame_in_buffer = halfway_frame; | ||
2661 | STp->frame_seq_number = frame_seq_numbr; | ||
2662 | STp->logical_blk_num = logical_blk_num; | ||
2663 | return 0; | ||
2664 | } | ||
2665 | |||
2666 | /* Acc. to OnStream, the vers. numbering is the following: | ||
2667 | * X.XX for released versions (X=digit), | ||
2668 | * XXXY for unreleased versions (Y=letter) | ||
2669 | * Ordering 1.05 < 106A < 106B < ... < 106a < ... < 1.06 | ||
2670 | * This fn makes monoton numbers out of this scheme ... | ||
2671 | */ | ||
2672 | static unsigned int osst_parse_firmware_rev (const char * str) | ||
2673 | { | ||
2674 | if (str[1] == '.') { | ||
2675 | return (str[0]-'0')*10000 | ||
2676 | +(str[2]-'0')*1000 | ||
2677 | +(str[3]-'0')*100; | ||
2678 | } else { | ||
2679 | return (str[0]-'0')*10000 | ||
2680 | +(str[1]-'0')*1000 | ||
2681 | +(str[2]-'0')*100 - 100 | ||
2682 | +(str[3]-'@'); | ||
2683 | } | ||
2684 | } | ||
2685 | |||
2686 | /* | ||
2687 | * Configure the OnStream SCII tape drive for default operation | ||
2688 | */ | ||
2689 | static int osst_configure_onstream(struct osst_tape *STp, struct osst_request ** aSRpnt) | ||
2690 | { | ||
2691 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
2692 | char * name = tape_name(STp); | ||
2693 | struct osst_request * SRpnt = * aSRpnt; | ||
2694 | osst_mode_parameter_header_t * header; | ||
2695 | osst_block_size_page_t * bs; | ||
2696 | osst_capabilities_page_t * cp; | ||
2697 | osst_tape_paramtr_page_t * prm; | ||
2698 | int drive_buffer_size; | ||
2699 | |||
2700 | if (STp->ready != ST_READY) { | ||
2701 | #if DEBUG | ||
2702 | printk(OSST_DEB_MSG "%s:D: Not Ready\n", name); | ||
2703 | #endif | ||
2704 | return (-EIO); | ||
2705 | } | ||
2706 | |||
2707 | if (STp->os_fw_rev < 10600) { | ||
2708 | printk(KERN_INFO "%s:I: Old OnStream firmware revision detected (%s),\n", name, STp->device->rev); | ||
2709 | printk(KERN_INFO "%s:I: an upgrade to version 1.06 or above is recommended\n", name); | ||
2710 | } | ||
2711 | |||
2712 | /* | ||
2713 | * Configure 32.5KB (data+aux) frame size. | ||
2714 | * Get the current frame size from the block size mode page | ||
2715 | */ | ||
2716 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
2717 | cmd[0] = MODE_SENSE; | ||
2718 | cmd[1] = 8; | ||
2719 | cmd[2] = BLOCK_SIZE_PAGE; | ||
2720 | cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
2721 | |||
2722 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); | ||
2723 | if (SRpnt == NULL) { | ||
2724 | #if DEBUG | ||
2725 | printk(OSST_DEB_MSG "osst :D: Busy\n"); | ||
2726 | #endif | ||
2727 | return (-EBUSY); | ||
2728 | } | ||
2729 | *aSRpnt = SRpnt; | ||
2730 | if ((STp->buffer)->syscall_result != 0) { | ||
2731 | printk (KERN_ERR "%s:E: Can't get tape block size mode page\n", name); | ||
2732 | return (-EIO); | ||
2733 | } | ||
2734 | |||
2735 | header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; | ||
2736 | bs = (osst_block_size_page_t *) ((STp->buffer)->b_data + sizeof(osst_mode_parameter_header_t) + header->bdl); | ||
2737 | |||
2738 | #if DEBUG | ||
2739 | printk(OSST_DEB_MSG "%s:D: 32KB play back: %s\n", name, bs->play32 ? "Yes" : "No"); | ||
2740 | printk(OSST_DEB_MSG "%s:D: 32.5KB play back: %s\n", name, bs->play32_5 ? "Yes" : "No"); | ||
2741 | printk(OSST_DEB_MSG "%s:D: 32KB record: %s\n", name, bs->record32 ? "Yes" : "No"); | ||
2742 | printk(OSST_DEB_MSG "%s:D: 32.5KB record: %s\n", name, bs->record32_5 ? "Yes" : "No"); | ||
2743 | #endif | ||
2744 | |||
2745 | /* | ||
2746 | * Configure default auto columns mode, 32.5KB transfer mode | ||
2747 | */ | ||
2748 | bs->one = 1; | ||
2749 | bs->play32 = 0; | ||
2750 | bs->play32_5 = 1; | ||
2751 | bs->record32 = 0; | ||
2752 | bs->record32_5 = 1; | ||
2753 | |||
2754 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
2755 | cmd[0] = MODE_SELECT; | ||
2756 | cmd[1] = 0x10; | ||
2757 | cmd[4] = BLOCK_SIZE_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
2758 | |||
2759 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); | ||
2760 | *aSRpnt = SRpnt; | ||
2761 | if ((STp->buffer)->syscall_result != 0) { | ||
2762 | printk (KERN_ERR "%s:E: Couldn't set tape block size mode page\n", name); | ||
2763 | return (-EIO); | ||
2764 | } | ||
2765 | |||
2766 | #if DEBUG | ||
2767 | printk(KERN_INFO "%s:D: Drive Block Size changed to 32.5K\n", name); | ||
2768 | /* | ||
2769 | * In debug mode, we want to see as many errors as possible | ||
2770 | * to test the error recovery mechanism. | ||
2771 | */ | ||
2772 | osst_set_retries(STp, aSRpnt, 0); | ||
2773 | SRpnt = * aSRpnt; | ||
2774 | #endif | ||
2775 | |||
2776 | /* | ||
2777 | * Set vendor name to 'LIN4' for "Linux support version 4". | ||
2778 | */ | ||
2779 | |||
2780 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
2781 | cmd[0] = MODE_SELECT; | ||
2782 | cmd[1] = 0x10; | ||
2783 | cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
2784 | |||
2785 | header->mode_data_length = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH - 1; | ||
2786 | header->medium_type = 0; /* Medium Type - ignoring */ | ||
2787 | header->dsp = 0; /* Reserved */ | ||
2788 | header->bdl = 0; /* Block Descriptor Length */ | ||
2789 | |||
2790 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = VENDOR_IDENT_PAGE | (1 << 7); | ||
2791 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 6; | ||
2792 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 'L'; | ||
2793 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 'I'; | ||
2794 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 4] = 'N'; | ||
2795 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 5] = '4'; | ||
2796 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 6] = 0; | ||
2797 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 7] = 0; | ||
2798 | |||
2799 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); | ||
2800 | *aSRpnt = SRpnt; | ||
2801 | |||
2802 | if ((STp->buffer)->syscall_result != 0) { | ||
2803 | printk (KERN_ERR "%s:E: Couldn't set vendor name to %s\n", name, | ||
2804 | (char *) ((STp->buffer)->b_data + MODE_HEADER_LENGTH + 2)); | ||
2805 | return (-EIO); | ||
2806 | } | ||
2807 | |||
2808 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
2809 | cmd[0] = MODE_SENSE; | ||
2810 | cmd[1] = 8; | ||
2811 | cmd[2] = CAPABILITIES_PAGE; | ||
2812 | cmd[4] = CAPABILITIES_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
2813 | |||
2814 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); | ||
2815 | *aSRpnt = SRpnt; | ||
2816 | |||
2817 | if ((STp->buffer)->syscall_result != 0) { | ||
2818 | printk (KERN_ERR "%s:E: Can't get capabilities page\n", name); | ||
2819 | return (-EIO); | ||
2820 | } | ||
2821 | |||
2822 | header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; | ||
2823 | cp = (osst_capabilities_page_t *) ((STp->buffer)->b_data + | ||
2824 | sizeof(osst_mode_parameter_header_t) + header->bdl); | ||
2825 | |||
2826 | drive_buffer_size = ntohs(cp->buffer_size) / 2; | ||
2827 | |||
2828 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
2829 | cmd[0] = MODE_SENSE; | ||
2830 | cmd[1] = 8; | ||
2831 | cmd[2] = TAPE_PARAMTR_PAGE; | ||
2832 | cmd[4] = TAPE_PARAMTR_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
2833 | |||
2834 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); | ||
2835 | *aSRpnt = SRpnt; | ||
2836 | |||
2837 | if ((STp->buffer)->syscall_result != 0) { | ||
2838 | printk (KERN_ERR "%s:E: Can't get tape parameter page\n", name); | ||
2839 | return (-EIO); | ||
2840 | } | ||
2841 | |||
2842 | header = (osst_mode_parameter_header_t *) (STp->buffer)->b_data; | ||
2843 | prm = (osst_tape_paramtr_page_t *) ((STp->buffer)->b_data + | ||
2844 | sizeof(osst_mode_parameter_header_t) + header->bdl); | ||
2845 | |||
2846 | STp->density = prm->density; | ||
2847 | STp->capacity = ntohs(prm->segtrk) * ntohs(prm->trks); | ||
2848 | #if DEBUG | ||
2849 | printk(OSST_DEB_MSG "%s:D: Density %d, tape length: %dMB, drive buffer size: %dKB\n", | ||
2850 | name, STp->density, STp->capacity / 32, drive_buffer_size); | ||
2851 | #endif | ||
2852 | |||
2853 | return 0; | ||
2854 | |||
2855 | } | ||
2856 | |||
2857 | |||
2858 | /* Step over EOF if it has been inadvertently crossed (ioctl not used because | ||
2859 | it messes up the block number). */ | ||
2860 | static int cross_eof(struct osst_tape *STp, struct osst_request ** aSRpnt, int forward) | ||
2861 | { | ||
2862 | int result; | ||
2863 | char * name = tape_name(STp); | ||
2864 | |||
2865 | #if DEBUG | ||
2866 | if (debugging) | ||
2867 | printk(OSST_DEB_MSG "%s:D: Stepping over filemark %s.\n", | ||
2868 | name, forward ? "forward" : "backward"); | ||
2869 | #endif | ||
2870 | |||
2871 | if (forward) { | ||
2872 | /* assumes that the filemark is already read by the drive, so this is low cost */ | ||
2873 | result = osst_space_over_filemarks_forward_slow(STp, aSRpnt, MTFSF, 1); | ||
2874 | } | ||
2875 | else | ||
2876 | /* assumes this is only called if we just read the filemark! */ | ||
2877 | result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - 1); | ||
2878 | |||
2879 | if (result < 0) | ||
2880 | printk(KERN_WARNING "%s:W: Stepping over filemark %s failed.\n", | ||
2881 | name, forward ? "forward" : "backward"); | ||
2882 | |||
2883 | return result; | ||
2884 | } | ||
2885 | |||
2886 | |||
2887 | /* Get the tape position. */ | ||
2888 | |||
2889 | static int osst_get_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt) | ||
2890 | { | ||
2891 | unsigned char scmd[MAX_COMMAND_SIZE]; | ||
2892 | struct osst_request * SRpnt; | ||
2893 | int result = 0; | ||
2894 | char * name = tape_name(STp); | ||
2895 | |||
2896 | /* KG: We want to be able to use it for checking Write Buffer availability | ||
2897 | * and thus don't want to risk to overwrite anything. Exchange buffers ... */ | ||
2898 | char mybuf[24]; | ||
2899 | char * olddata = STp->buffer->b_data; | ||
2900 | int oldsize = STp->buffer->buffer_size; | ||
2901 | |||
2902 | if (STp->ready != ST_READY) return (-EIO); | ||
2903 | |||
2904 | memset (scmd, 0, MAX_COMMAND_SIZE); | ||
2905 | scmd[0] = READ_POSITION; | ||
2906 | |||
2907 | STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; | ||
2908 | SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, DMA_FROM_DEVICE, | ||
2909 | STp->timeout, MAX_RETRIES, 1); | ||
2910 | if (!SRpnt) { | ||
2911 | STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; | ||
2912 | return (-EBUSY); | ||
2913 | } | ||
2914 | *aSRpnt = SRpnt; | ||
2915 | |||
2916 | if (STp->buffer->syscall_result) | ||
2917 | result = ((SRpnt->sense[2] & 0x0f) == 3) ? -EIO : -EINVAL; /* 3: Write Error */ | ||
2918 | |||
2919 | if (result == -EINVAL) | ||
2920 | printk(KERN_ERR "%s:E: Can't read tape position.\n", name); | ||
2921 | else { | ||
2922 | if (result == -EIO) { /* re-read position - this needs to preserve media errors */ | ||
2923 | unsigned char mysense[16]; | ||
2924 | memcpy (mysense, SRpnt->sense, 16); | ||
2925 | memset (scmd, 0, MAX_COMMAND_SIZE); | ||
2926 | scmd[0] = READ_POSITION; | ||
2927 | STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; | ||
2928 | SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, DMA_FROM_DEVICE, | ||
2929 | STp->timeout, MAX_RETRIES, 1); | ||
2930 | #if DEBUG | ||
2931 | printk(OSST_DEB_MSG "%s:D: Reread position, reason=[%02x:%02x:%02x], result=[%s%02x:%02x:%02x]\n", | ||
2932 | name, mysense[2], mysense[12], mysense[13], STp->buffer->syscall_result?"":"ok:", | ||
2933 | SRpnt->sense[2],SRpnt->sense[12],SRpnt->sense[13]); | ||
2934 | #endif | ||
2935 | if (!STp->buffer->syscall_result) | ||
2936 | memcpy (SRpnt->sense, mysense, 16); | ||
2937 | else | ||
2938 | printk(KERN_WARNING "%s:W: Double error in get position\n", name); | ||
2939 | } | ||
2940 | STp->first_frame_position = ((STp->buffer)->b_data[4] << 24) | ||
2941 | + ((STp->buffer)->b_data[5] << 16) | ||
2942 | + ((STp->buffer)->b_data[6] << 8) | ||
2943 | + (STp->buffer)->b_data[7]; | ||
2944 | STp->last_frame_position = ((STp->buffer)->b_data[ 8] << 24) | ||
2945 | + ((STp->buffer)->b_data[ 9] << 16) | ||
2946 | + ((STp->buffer)->b_data[10] << 8) | ||
2947 | + (STp->buffer)->b_data[11]; | ||
2948 | STp->cur_frames = (STp->buffer)->b_data[15]; | ||
2949 | #if DEBUG | ||
2950 | if (debugging) { | ||
2951 | printk(OSST_DEB_MSG "%s:D: Drive Positions: host %d, tape %d%s, buffer %d\n", name, | ||
2952 | STp->first_frame_position, STp->last_frame_position, | ||
2953 | ((STp->buffer)->b_data[0]&0x80)?" (BOP)": | ||
2954 | ((STp->buffer)->b_data[0]&0x40)?" (EOP)":"", | ||
2955 | STp->cur_frames); | ||
2956 | } | ||
2957 | #endif | ||
2958 | if (STp->cur_frames == 0 && STp->first_frame_position != STp->last_frame_position) { | ||
2959 | #if DEBUG | ||
2960 | printk(OSST_DEB_MSG "%s:D: Correcting read position %d, %d, %d\n", name, | ||
2961 | STp->first_frame_position, STp->last_frame_position, STp->cur_frames); | ||
2962 | #endif | ||
2963 | STp->first_frame_position = STp->last_frame_position; | ||
2964 | } | ||
2965 | } | ||
2966 | STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; | ||
2967 | |||
2968 | return (result == 0 ? STp->first_frame_position : result); | ||
2969 | } | ||
2970 | |||
2971 | |||
2972 | /* Set the tape block */ | ||
2973 | static int osst_set_frame_position(struct osst_tape *STp, struct osst_request ** aSRpnt, int ppos, int skip) | ||
2974 | { | ||
2975 | unsigned char scmd[MAX_COMMAND_SIZE]; | ||
2976 | struct osst_request * SRpnt; | ||
2977 | struct st_partstat * STps; | ||
2978 | int result = 0; | ||
2979 | int pp = (ppos == 3000 && !skip)? 0 : ppos; | ||
2980 | char * name = tape_name(STp); | ||
2981 | |||
2982 | if (STp->ready != ST_READY) return (-EIO); | ||
2983 | |||
2984 | STps = &(STp->ps[STp->partition]); | ||
2985 | |||
2986 | if (ppos < 0 || ppos > STp->capacity) { | ||
2987 | printk(KERN_WARNING "%s:W: Reposition request %d out of range\n", name, ppos); | ||
2988 | pp = ppos = ppos < 0 ? 0 : (STp->capacity - 1); | ||
2989 | result = (-EINVAL); | ||
2990 | } | ||
2991 | |||
2992 | do { | ||
2993 | #if DEBUG | ||
2994 | if (debugging) | ||
2995 | printk(OSST_DEB_MSG "%s:D: Setting ppos to %d.\n", name, pp); | ||
2996 | #endif | ||
2997 | memset (scmd, 0, MAX_COMMAND_SIZE); | ||
2998 | scmd[0] = SEEK_10; | ||
2999 | scmd[1] = 1; | ||
3000 | scmd[3] = (pp >> 24); | ||
3001 | scmd[4] = (pp >> 16); | ||
3002 | scmd[5] = (pp >> 8); | ||
3003 | scmd[6] = pp; | ||
3004 | if (skip) | ||
3005 | scmd[9] = 0x80; | ||
3006 | |||
3007 | SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, DMA_NONE, STp->long_timeout, | ||
3008 | MAX_RETRIES, 1); | ||
3009 | if (!SRpnt) | ||
3010 | return (-EBUSY); | ||
3011 | *aSRpnt = SRpnt; | ||
3012 | |||
3013 | if ((STp->buffer)->syscall_result != 0) { | ||
3014 | #if DEBUG | ||
3015 | printk(OSST_DEB_MSG "%s:D: SEEK command from %d to %d failed.\n", | ||
3016 | name, STp->first_frame_position, pp); | ||
3017 | #endif | ||
3018 | result = (-EIO); | ||
3019 | } | ||
3020 | if (pp != ppos) | ||
3021 | osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); | ||
3022 | } while ((pp != ppos) && (pp = ppos)); | ||
3023 | STp->first_frame_position = STp->last_frame_position = ppos; | ||
3024 | STps->eof = ST_NOEOF; | ||
3025 | STps->at_sm = 0; | ||
3026 | STps->rw = ST_IDLE; | ||
3027 | STp->frame_in_buffer = 0; | ||
3028 | return result; | ||
3029 | } | ||
3030 | |||
3031 | static int osst_write_trailer(struct osst_tape *STp, struct osst_request ** aSRpnt, int leave_at_EOT) | ||
3032 | { | ||
3033 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
3034 | int result = 0; | ||
3035 | |||
3036 | if (STp->write_type != OS_WRITE_NEW_MARK) { | ||
3037 | /* true unless the user wrote the filemark for us */ | ||
3038 | result = osst_flush_drive_buffer(STp, aSRpnt); | ||
3039 | if (result < 0) goto out; | ||
3040 | result = osst_write_filemark(STp, aSRpnt); | ||
3041 | if (result < 0) goto out; | ||
3042 | |||
3043 | if (STps->drv_file >= 0) | ||
3044 | STps->drv_file++ ; | ||
3045 | STps->drv_block = 0; | ||
3046 | } | ||
3047 | result = osst_write_eod(STp, aSRpnt); | ||
3048 | osst_write_header(STp, aSRpnt, leave_at_EOT); | ||
3049 | |||
3050 | STps->eof = ST_FM; | ||
3051 | out: | ||
3052 | return result; | ||
3053 | } | ||
3054 | |||
3055 | /* osst versions of st functions - augmented and stripped to suit OnStream only */ | ||
3056 | |||
3057 | /* Flush the write buffer (never need to write if variable blocksize). */ | ||
3058 | static int osst_flush_write_buffer(struct osst_tape *STp, struct osst_request ** aSRpnt) | ||
3059 | { | ||
3060 | int offset, transfer, blks = 0; | ||
3061 | int result = 0; | ||
3062 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
3063 | struct osst_request * SRpnt = *aSRpnt; | ||
3064 | struct st_partstat * STps; | ||
3065 | char * name = tape_name(STp); | ||
3066 | |||
3067 | if ((STp->buffer)->writing) { | ||
3068 | if (SRpnt == (STp->buffer)->last_SRpnt) | ||
3069 | #if DEBUG | ||
3070 | { printk(OSST_DEB_MSG | ||
3071 | "%s:D: aSRpnt points to osst_request that write_behind_check will release -- cleared\n", name); | ||
3072 | #endif | ||
3073 | *aSRpnt = SRpnt = NULL; | ||
3074 | #if DEBUG | ||
3075 | } else if (SRpnt) | ||
3076 | printk(OSST_DEB_MSG | ||
3077 | "%s:D: aSRpnt does not point to osst_request that write_behind_check will release -- strange\n", name); | ||
3078 | #endif | ||
3079 | osst_write_behind_check(STp); | ||
3080 | if ((STp->buffer)->syscall_result) { | ||
3081 | #if DEBUG | ||
3082 | if (debugging) | ||
3083 | printk(OSST_DEB_MSG "%s:D: Async write error (flush) %x.\n", | ||
3084 | name, (STp->buffer)->midlevel_result); | ||
3085 | #endif | ||
3086 | if ((STp->buffer)->midlevel_result == INT_MAX) | ||
3087 | return (-ENOSPC); | ||
3088 | return (-EIO); | ||
3089 | } | ||
3090 | } | ||
3091 | |||
3092 | result = 0; | ||
3093 | if (STp->dirty == 1) { | ||
3094 | |||
3095 | STp->write_count++; | ||
3096 | STps = &(STp->ps[STp->partition]); | ||
3097 | STps->rw = ST_WRITING; | ||
3098 | offset = STp->buffer->buffer_bytes; | ||
3099 | blks = (offset + STp->block_size - 1) / STp->block_size; | ||
3100 | transfer = OS_FRAME_SIZE; | ||
3101 | |||
3102 | if (offset < OS_DATA_SIZE) | ||
3103 | osst_zero_buffer_tail(STp->buffer); | ||
3104 | |||
3105 | if (STp->poll) | ||
3106 | if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -50, 120)) | ||
3107 | result = osst_recover_wait_frame(STp, aSRpnt, 1); | ||
3108 | |||
3109 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
3110 | cmd[0] = WRITE_6; | ||
3111 | cmd[1] = 1; | ||
3112 | cmd[4] = 1; | ||
3113 | |||
3114 | switch (STp->write_type) { | ||
3115 | case OS_WRITE_DATA: | ||
3116 | #if DEBUG | ||
3117 | if (debugging) | ||
3118 | printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", | ||
3119 | name, blks, STp->frame_seq_number, | ||
3120 | STp->logical_blk_num - blks, STp->logical_blk_num - 1); | ||
3121 | #endif | ||
3122 | osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, | ||
3123 | STp->logical_blk_num - blks, STp->block_size, blks); | ||
3124 | break; | ||
3125 | case OS_WRITE_EOD: | ||
3126 | osst_init_aux(STp, OS_FRAME_TYPE_EOD, STp->frame_seq_number++, | ||
3127 | STp->logical_blk_num, 0, 0); | ||
3128 | break; | ||
3129 | case OS_WRITE_NEW_MARK: | ||
3130 | osst_init_aux(STp, OS_FRAME_TYPE_MARKER, STp->frame_seq_number++, | ||
3131 | STp->logical_blk_num++, 0, blks=1); | ||
3132 | break; | ||
3133 | case OS_WRITE_HEADER: | ||
3134 | osst_init_aux(STp, OS_FRAME_TYPE_HEADER, 0, 0, 0, blks=0); | ||
3135 | break; | ||
3136 | default: /* probably FILLER */ | ||
3137 | osst_init_aux(STp, OS_FRAME_TYPE_FILL, 0, 0, 0, 0); | ||
3138 | } | ||
3139 | #if DEBUG | ||
3140 | if (debugging) | ||
3141 | printk(OSST_DEB_MSG "%s:D: Flushing %d bytes, Transferring %d bytes in %d lblocks.\n", | ||
3142 | name, offset, transfer, blks); | ||
3143 | #endif | ||
3144 | |||
3145 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, transfer, DMA_TO_DEVICE, | ||
3146 | STp->timeout, MAX_RETRIES, 1); | ||
3147 | *aSRpnt = SRpnt; | ||
3148 | if (!SRpnt) | ||
3149 | return (-EBUSY); | ||
3150 | |||
3151 | if ((STp->buffer)->syscall_result != 0) { | ||
3152 | #if DEBUG | ||
3153 | printk(OSST_DEB_MSG | ||
3154 | "%s:D: write sense [0]=0x%02x [2]=%02x [12]=%02x [13]=%02x\n", | ||
3155 | name, SRpnt->sense[0], SRpnt->sense[2], | ||
3156 | SRpnt->sense[12], SRpnt->sense[13]); | ||
3157 | #endif | ||
3158 | if ((SRpnt->sense[0] & 0x70) == 0x70 && | ||
3159 | (SRpnt->sense[2] & 0x40) && /* FIXME - SC-30 drive doesn't assert EOM bit */ | ||
3160 | (SRpnt->sense[2] & 0x0f) == NO_SENSE) { | ||
3161 | STp->dirty = 0; | ||
3162 | (STp->buffer)->buffer_bytes = 0; | ||
3163 | result = (-ENOSPC); | ||
3164 | } | ||
3165 | else { | ||
3166 | if (osst_write_error_recovery(STp, aSRpnt, 1)) { | ||
3167 | printk(KERN_ERR "%s:E: Error on flush write.\n", name); | ||
3168 | result = (-EIO); | ||
3169 | } | ||
3170 | } | ||
3171 | STps->drv_block = (-1); /* FIXME - even if write recovery succeeds? */ | ||
3172 | } | ||
3173 | else { | ||
3174 | STp->first_frame_position++; | ||
3175 | STp->dirty = 0; | ||
3176 | (STp->buffer)->buffer_bytes = 0; | ||
3177 | } | ||
3178 | } | ||
3179 | #if DEBUG | ||
3180 | printk(OSST_DEB_MSG "%s:D: Exit flush write buffer with code %d\n", name, result); | ||
3181 | #endif | ||
3182 | return result; | ||
3183 | } | ||
3184 | |||
3185 | |||
3186 | /* Flush the tape buffer. The tape will be positioned correctly unless | ||
3187 | seek_next is true. */ | ||
3188 | static int osst_flush_buffer(struct osst_tape * STp, struct osst_request ** aSRpnt, int seek_next) | ||
3189 | { | ||
3190 | struct st_partstat * STps; | ||
3191 | int backspace = 0, result = 0; | ||
3192 | #if DEBUG | ||
3193 | char * name = tape_name(STp); | ||
3194 | #endif | ||
3195 | |||
3196 | /* | ||
3197 | * If there was a bus reset, block further access | ||
3198 | * to this device. | ||
3199 | */ | ||
3200 | if( STp->pos_unknown) | ||
3201 | return (-EIO); | ||
3202 | |||
3203 | if (STp->ready != ST_READY) | ||
3204 | return 0; | ||
3205 | |||
3206 | STps = &(STp->ps[STp->partition]); | ||
3207 | if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */ | ||
3208 | STp->write_type = OS_WRITE_DATA; | ||
3209 | return osst_flush_write_buffer(STp, aSRpnt); | ||
3210 | } | ||
3211 | if (STp->block_size == 0) | ||
3212 | return 0; | ||
3213 | |||
3214 | #if DEBUG | ||
3215 | printk(OSST_DEB_MSG "%s:D: Reached flush (read) buffer\n", name); | ||
3216 | #endif | ||
3217 | |||
3218 | if (!STp->can_bsr) { | ||
3219 | backspace = ((STp->buffer)->buffer_bytes + (STp->buffer)->read_pointer) / STp->block_size - | ||
3220 | ((STp->buffer)->read_pointer + STp->block_size - 1 ) / STp->block_size ; | ||
3221 | (STp->buffer)->buffer_bytes = 0; | ||
3222 | (STp->buffer)->read_pointer = 0; | ||
3223 | STp->frame_in_buffer = 0; /* FIXME is this relevant w. OSST? */ | ||
3224 | } | ||
3225 | |||
3226 | if (!seek_next) { | ||
3227 | if (STps->eof == ST_FM_HIT) { | ||
3228 | result = cross_eof(STp, aSRpnt, 0); /* Back over the EOF hit */ | ||
3229 | if (!result) | ||
3230 | STps->eof = ST_NOEOF; | ||
3231 | else { | ||
3232 | if (STps->drv_file >= 0) | ||
3233 | STps->drv_file++; | ||
3234 | STps->drv_block = 0; | ||
3235 | } | ||
3236 | } | ||
3237 | if (!result && backspace > 0) /* TODO -- design and run a test case for this */ | ||
3238 | result = osst_seek_logical_blk(STp, aSRpnt, STp->logical_blk_num - backspace); | ||
3239 | } | ||
3240 | else if (STps->eof == ST_FM_HIT) { | ||
3241 | if (STps->drv_file >= 0) | ||
3242 | STps->drv_file++; | ||
3243 | STps->drv_block = 0; | ||
3244 | STps->eof = ST_NOEOF; | ||
3245 | } | ||
3246 | |||
3247 | return result; | ||
3248 | } | ||
3249 | |||
3250 | static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpnt, int synchronous) | ||
3251 | { | ||
3252 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
3253 | struct osst_request * SRpnt; | ||
3254 | int blks; | ||
3255 | #if DEBUG | ||
3256 | char * name = tape_name(STp); | ||
3257 | #endif | ||
3258 | |||
3259 | if ((!STp-> raw) && (STp->first_frame_position == 0xbae)) { /* _must_ preserve buffer! */ | ||
3260 | #if DEBUG | ||
3261 | printk(OSST_DEB_MSG "%s:D: Reaching config partition.\n", name); | ||
3262 | #endif | ||
3263 | if (osst_flush_drive_buffer(STp, aSRpnt) < 0) { | ||
3264 | return (-EIO); | ||
3265 | } | ||
3266 | /* error recovery may have bumped us past the header partition */ | ||
3267 | if (osst_get_frame_position(STp, aSRpnt) < 0xbb8) { | ||
3268 | #if DEBUG | ||
3269 | printk(OSST_DEB_MSG "%s:D: Skipping over config partition.\n", name); | ||
3270 | #endif | ||
3271 | osst_position_tape_and_confirm(STp, aSRpnt, 0xbb8); | ||
3272 | } | ||
3273 | } | ||
3274 | |||
3275 | if (STp->poll) | ||
3276 | if (osst_wait_frame (STp, aSRpnt, STp->first_frame_position, -48, 120)) | ||
3277 | if (osst_recover_wait_frame(STp, aSRpnt, 1)) | ||
3278 | return (-EIO); | ||
3279 | |||
3280 | // osst_build_stats(STp, &SRpnt); | ||
3281 | |||
3282 | STp->ps[STp->partition].rw = ST_WRITING; | ||
3283 | STp->write_type = OS_WRITE_DATA; | ||
3284 | |||
3285 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
3286 | cmd[0] = WRITE_6; | ||
3287 | cmd[1] = 1; | ||
3288 | cmd[4] = 1; /* one frame at a time... */ | ||
3289 | blks = STp->buffer->buffer_bytes / STp->block_size; | ||
3290 | #if DEBUG | ||
3291 | if (debugging) | ||
3292 | printk(OSST_DEB_MSG "%s:D: Writing %d blocks to frame %d, lblks %d-%d\n", name, blks, | ||
3293 | STp->frame_seq_number, STp->logical_blk_num - blks, STp->logical_blk_num - 1); | ||
3294 | #endif | ||
3295 | osst_init_aux(STp, OS_FRAME_TYPE_DATA, STp->frame_seq_number++, | ||
3296 | STp->logical_blk_num - blks, STp->block_size, blks); | ||
3297 | |||
3298 | #if DEBUG | ||
3299 | if (!synchronous) | ||
3300 | STp->write_pending = 1; | ||
3301 | #endif | ||
3302 | SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, DMA_TO_DEVICE, STp->timeout, | ||
3303 | MAX_RETRIES, synchronous); | ||
3304 | if (!SRpnt) | ||
3305 | return (-EBUSY); | ||
3306 | *aSRpnt = SRpnt; | ||
3307 | |||
3308 | if (synchronous) { | ||
3309 | if (STp->buffer->syscall_result != 0) { | ||
3310 | #if DEBUG | ||
3311 | if (debugging) | ||
3312 | printk(OSST_DEB_MSG "%s:D: Error on write:\n", name); | ||
3313 | #endif | ||
3314 | if ((SRpnt->sense[0] & 0x70) == 0x70 && | ||
3315 | (SRpnt->sense[2] & 0x40)) { | ||
3316 | if ((SRpnt->sense[2] & 0x0f) == VOLUME_OVERFLOW) | ||
3317 | return (-ENOSPC); | ||
3318 | } | ||
3319 | else { | ||
3320 | if (osst_write_error_recovery(STp, aSRpnt, 1)) | ||
3321 | return (-EIO); | ||
3322 | } | ||
3323 | } | ||
3324 | else | ||
3325 | STp->first_frame_position++; | ||
3326 | } | ||
3327 | |||
3328 | STp->write_count++; | ||
3329 | |||
3330 | return 0; | ||
3331 | } | ||
3332 | |||
3333 | /* Lock or unlock the drive door. Don't use when struct osst_request allocated. */ | ||
3334 | static int do_door_lock(struct osst_tape * STp, int do_lock) | ||
3335 | { | ||
3336 | int retval; | ||
3337 | |||
3338 | #if DEBUG | ||
3339 | printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl"); | ||
3340 | #endif | ||
3341 | |||
3342 | retval = scsi_set_medium_removal(STp->device, | ||
3343 | do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW); | ||
3344 | if (!retval) | ||
3345 | STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED; | ||
3346 | else | ||
3347 | STp->door_locked = ST_LOCK_FAILS; | ||
3348 | return retval; | ||
3349 | } | ||
3350 | |||
3351 | /* Set the internal state after reset */ | ||
3352 | static void reset_state(struct osst_tape *STp) | ||
3353 | { | ||
3354 | int i; | ||
3355 | struct st_partstat *STps; | ||
3356 | |||
3357 | STp->pos_unknown = 0; | ||
3358 | for (i = 0; i < ST_NBR_PARTITIONS; i++) { | ||
3359 | STps = &(STp->ps[i]); | ||
3360 | STps->rw = ST_IDLE; | ||
3361 | STps->eof = ST_NOEOF; | ||
3362 | STps->at_sm = 0; | ||
3363 | STps->last_block_valid = 0; | ||
3364 | STps->drv_block = -1; | ||
3365 | STps->drv_file = -1; | ||
3366 | } | ||
3367 | } | ||
3368 | |||
3369 | |||
3370 | /* Entry points to osst */ | ||
3371 | |||
3372 | /* Write command */ | ||
3373 | static ssize_t osst_write(struct file * filp, const char __user * buf, size_t count, loff_t *ppos) | ||
3374 | { | ||
3375 | ssize_t total, retval = 0; | ||
3376 | ssize_t i, do_count, blks, transfer; | ||
3377 | int write_threshold; | ||
3378 | int doing_write = 0; | ||
3379 | const char __user * b_point; | ||
3380 | struct osst_request * SRpnt = NULL; | ||
3381 | struct st_modedef * STm; | ||
3382 | struct st_partstat * STps; | ||
3383 | struct osst_tape * STp = filp->private_data; | ||
3384 | char * name = tape_name(STp); | ||
3385 | |||
3386 | |||
3387 | if (mutex_lock_interruptible(&STp->lock)) | ||
3388 | return (-ERESTARTSYS); | ||
3389 | |||
3390 | /* | ||
3391 | * If we are in the middle of error recovery, don't let anyone | ||
3392 | * else try and use this device. Also, if error recovery fails, it | ||
3393 | * may try and take the device offline, in which case all further | ||
3394 | * access to the device is prohibited. | ||
3395 | */ | ||
3396 | if( !scsi_block_when_processing_errors(STp->device) ) { | ||
3397 | retval = (-ENXIO); | ||
3398 | goto out; | ||
3399 | } | ||
3400 | |||
3401 | if (STp->ready != ST_READY) { | ||
3402 | if (STp->ready == ST_NO_TAPE) | ||
3403 | retval = (-ENOMEDIUM); | ||
3404 | else | ||
3405 | retval = (-EIO); | ||
3406 | goto out; | ||
3407 | } | ||
3408 | STm = &(STp->modes[STp->current_mode]); | ||
3409 | if (!STm->defined) { | ||
3410 | retval = (-ENXIO); | ||
3411 | goto out; | ||
3412 | } | ||
3413 | if (count == 0) | ||
3414 | goto out; | ||
3415 | |||
3416 | /* | ||
3417 | * If there was a bus reset, block further access | ||
3418 | * to this device. | ||
3419 | */ | ||
3420 | if (STp->pos_unknown) { | ||
3421 | retval = (-EIO); | ||
3422 | goto out; | ||
3423 | } | ||
3424 | |||
3425 | #if DEBUG | ||
3426 | if (!STp->in_use) { | ||
3427 | printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); | ||
3428 | retval = (-EIO); | ||
3429 | goto out; | ||
3430 | } | ||
3431 | #endif | ||
3432 | |||
3433 | if (STp->write_prot) { | ||
3434 | retval = (-EACCES); | ||
3435 | goto out; | ||
3436 | } | ||
3437 | |||
3438 | /* Write must be integral number of blocks */ | ||
3439 | if (STp->block_size != 0 && (count % STp->block_size) != 0) { | ||
3440 | printk(KERN_ERR "%s:E: Write (%zd bytes) not multiple of tape block size (%d%c).\n", | ||
3441 | name, count, STp->block_size<1024? | ||
3442 | STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); | ||
3443 | retval = (-EINVAL); | ||
3444 | goto out; | ||
3445 | } | ||
3446 | |||
3447 | if (STp->first_frame_position >= STp->capacity - OSST_EOM_RESERVE) { | ||
3448 | printk(KERN_ERR "%s:E: Write truncated at EOM early warning (frame %d).\n", | ||
3449 | name, STp->first_frame_position); | ||
3450 | retval = (-ENOSPC); | ||
3451 | goto out; | ||
3452 | } | ||
3453 | |||
3454 | if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) | ||
3455 | STp->door_locked = ST_LOCKED_AUTO; | ||
3456 | |||
3457 | STps = &(STp->ps[STp->partition]); | ||
3458 | |||
3459 | if (STps->rw == ST_READING) { | ||
3460 | #if DEBUG | ||
3461 | printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name, | ||
3462 | STps->drv_file, STps->drv_block); | ||
3463 | #endif | ||
3464 | retval = osst_flush_buffer(STp, &SRpnt, 0); | ||
3465 | if (retval) | ||
3466 | goto out; | ||
3467 | STps->rw = ST_IDLE; | ||
3468 | } | ||
3469 | if (STps->rw != ST_WRITING) { | ||
3470 | /* Are we totally rewriting this tape? */ | ||
3471 | if (!STp->header_ok || | ||
3472 | (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) || | ||
3473 | (STps->drv_file == 0 && STps->drv_block == 0)) { | ||
3474 | STp->wrt_pass_cntr++; | ||
3475 | #if DEBUG | ||
3476 | printk(OSST_DEB_MSG "%s:D: Allocating next write pass counter: %d\n", | ||
3477 | name, STp->wrt_pass_cntr); | ||
3478 | #endif | ||
3479 | osst_reset_header(STp, &SRpnt); | ||
3480 | STps->drv_file = STps->drv_block = 0; | ||
3481 | } | ||
3482 | /* Do we know where we'll be writing on the tape? */ | ||
3483 | else { | ||
3484 | if ((STp->fast_open && osst_verify_position(STp, &SRpnt)) || | ||
3485 | STps->drv_file < 0 || STps->drv_block < 0) { | ||
3486 | if (STp->first_frame_position == STp->eod_frame_ppos) { /* at EOD */ | ||
3487 | STps->drv_file = STp->filemark_cnt; | ||
3488 | STps->drv_block = 0; | ||
3489 | } | ||
3490 | else { | ||
3491 | /* We have no idea where the tape is positioned - give up */ | ||
3492 | #if DEBUG | ||
3493 | printk(OSST_DEB_MSG | ||
3494 | "%s:D: Cannot write at indeterminate position.\n", name); | ||
3495 | #endif | ||
3496 | retval = (-EIO); | ||
3497 | goto out; | ||
3498 | } | ||
3499 | } | ||
3500 | if ((STps->drv_file + STps->drv_block) > 0 && STps->drv_file < STp->filemark_cnt) { | ||
3501 | STp->filemark_cnt = STps->drv_file; | ||
3502 | STp->last_mark_ppos = | ||
3503 | ntohl(STp->header_cache->dat_fm_tab.fm_tab_ent[STp->filemark_cnt-1]); | ||
3504 | printk(KERN_WARNING | ||
3505 | "%s:W: Overwriting file %d with old write pass counter %d\n", | ||
3506 | name, STps->drv_file, STp->wrt_pass_cntr); | ||
3507 | printk(KERN_WARNING | ||
3508 | "%s:W: may lead to stale data being accepted on reading back!\n", | ||
3509 | name); | ||
3510 | #if DEBUG | ||
3511 | printk(OSST_DEB_MSG | ||
3512 | "%s:D: resetting filemark count to %d and last mark ppos,lbn to %d,%d\n", | ||
3513 | name, STp->filemark_cnt, STp->last_mark_ppos, STp->last_mark_lbn); | ||
3514 | #endif | ||
3515 | } | ||
3516 | } | ||
3517 | STp->fast_open = 0; | ||
3518 | } | ||
3519 | if (!STp->header_ok) { | ||
3520 | #if DEBUG | ||
3521 | printk(OSST_DEB_MSG "%s:D: Write cannot proceed without valid headers\n", name); | ||
3522 | #endif | ||
3523 | retval = (-EIO); | ||
3524 | goto out; | ||
3525 | } | ||
3526 | |||
3527 | if ((STp->buffer)->writing) { | ||
3528 | if (SRpnt) printk(KERN_ERR "%s:A: Not supposed to have SRpnt at line %d\n", name, __LINE__); | ||
3529 | osst_write_behind_check(STp); | ||
3530 | if ((STp->buffer)->syscall_result) { | ||
3531 | #if DEBUG | ||
3532 | if (debugging) | ||
3533 | printk(OSST_DEB_MSG "%s:D: Async write error (write) %x.\n", name, | ||
3534 | (STp->buffer)->midlevel_result); | ||
3535 | #endif | ||
3536 | if ((STp->buffer)->midlevel_result == INT_MAX) | ||
3537 | STps->eof = ST_EOM_OK; | ||
3538 | else | ||
3539 | STps->eof = ST_EOM_ERROR; | ||
3540 | } | ||
3541 | } | ||
3542 | if (STps->eof == ST_EOM_OK) { | ||
3543 | retval = (-ENOSPC); | ||
3544 | goto out; | ||
3545 | } | ||
3546 | else if (STps->eof == ST_EOM_ERROR) { | ||
3547 | retval = (-EIO); | ||
3548 | goto out; | ||
3549 | } | ||
3550 | |||
3551 | /* Check the buffer readability in cases where copy_user might catch | ||
3552 | the problems after some tape movement. */ | ||
3553 | if ((copy_from_user(&i, buf, 1) != 0 || | ||
3554 | copy_from_user(&i, buf + count - 1, 1) != 0)) { | ||
3555 | retval = (-EFAULT); | ||
3556 | goto out; | ||
3557 | } | ||
3558 | |||
3559 | if (!STm->do_buffer_writes) { | ||
3560 | write_threshold = 1; | ||
3561 | } | ||
3562 | else | ||
3563 | write_threshold = (STp->buffer)->buffer_blocks * STp->block_size; | ||
3564 | if (!STm->do_async_writes) | ||
3565 | write_threshold--; | ||
3566 | |||
3567 | total = count; | ||
3568 | #if DEBUG | ||
3569 | if (debugging) | ||
3570 | printk(OSST_DEB_MSG "%s:D: Writing %d bytes to file %d block %d lblk %d fseq %d fppos %d\n", | ||
3571 | name, (int) count, STps->drv_file, STps->drv_block, | ||
3572 | STp->logical_blk_num, STp->frame_seq_number, STp->first_frame_position); | ||
3573 | #endif | ||
3574 | b_point = buf; | ||
3575 | while ((STp->buffer)->buffer_bytes + count > write_threshold) | ||
3576 | { | ||
3577 | doing_write = 1; | ||
3578 | do_count = (STp->buffer)->buffer_blocks * STp->block_size - | ||
3579 | (STp->buffer)->buffer_bytes; | ||
3580 | if (do_count > count) | ||
3581 | do_count = count; | ||
3582 | |||
3583 | i = append_to_buffer(b_point, STp->buffer, do_count); | ||
3584 | if (i) { | ||
3585 | retval = i; | ||
3586 | goto out; | ||
3587 | } | ||
3588 | |||
3589 | blks = do_count / STp->block_size; | ||
3590 | STp->logical_blk_num += blks; /* logical_blk_num is incremented as data is moved from user */ | ||
3591 | |||
3592 | i = osst_write_frame(STp, &SRpnt, 1); | ||
3593 | |||
3594 | if (i == (-ENOSPC)) { | ||
3595 | transfer = STp->buffer->writing; /* FIXME -- check this logic */ | ||
3596 | if (transfer <= do_count) { | ||
3597 | *ppos += do_count - transfer; | ||
3598 | count -= do_count - transfer; | ||
3599 | if (STps->drv_block >= 0) { | ||
3600 | STps->drv_block += (do_count - transfer) / STp->block_size; | ||
3601 | } | ||
3602 | STps->eof = ST_EOM_OK; | ||
3603 | retval = (-ENOSPC); /* EOM within current request */ | ||
3604 | #if DEBUG | ||
3605 | if (debugging) | ||
3606 | printk(OSST_DEB_MSG "%s:D: EOM with %d bytes unwritten.\n", | ||
3607 | name, (int) transfer); | ||
3608 | #endif | ||
3609 | } | ||
3610 | else { | ||
3611 | STps->eof = ST_EOM_ERROR; | ||
3612 | STps->drv_block = (-1); /* Too cautious? */ | ||
3613 | retval = (-EIO); /* EOM for old data */ | ||
3614 | #if DEBUG | ||
3615 | if (debugging) | ||
3616 | printk(OSST_DEB_MSG "%s:D: EOM with lost data.\n", name); | ||
3617 | #endif | ||
3618 | } | ||
3619 | } | ||
3620 | else | ||
3621 | retval = i; | ||
3622 | |||
3623 | if (retval < 0) { | ||
3624 | if (SRpnt != NULL) { | ||
3625 | osst_release_request(SRpnt); | ||
3626 | SRpnt = NULL; | ||
3627 | } | ||
3628 | STp->buffer->buffer_bytes = 0; | ||
3629 | STp->dirty = 0; | ||
3630 | if (count < total) | ||
3631 | retval = total - count; | ||
3632 | goto out; | ||
3633 | } | ||
3634 | |||
3635 | *ppos += do_count; | ||
3636 | b_point += do_count; | ||
3637 | count -= do_count; | ||
3638 | if (STps->drv_block >= 0) { | ||
3639 | STps->drv_block += blks; | ||
3640 | } | ||
3641 | STp->buffer->buffer_bytes = 0; | ||
3642 | STp->dirty = 0; | ||
3643 | } /* end while write threshold exceeded */ | ||
3644 | |||
3645 | if (count != 0) { | ||
3646 | STp->dirty = 1; | ||
3647 | i = append_to_buffer(b_point, STp->buffer, count); | ||
3648 | if (i) { | ||
3649 | retval = i; | ||
3650 | goto out; | ||
3651 | } | ||
3652 | blks = count / STp->block_size; | ||
3653 | STp->logical_blk_num += blks; | ||
3654 | if (STps->drv_block >= 0) { | ||
3655 | STps->drv_block += blks; | ||
3656 | } | ||
3657 | *ppos += count; | ||
3658 | count = 0; | ||
3659 | } | ||
3660 | |||
3661 | if (doing_write && (STp->buffer)->syscall_result != 0) { | ||
3662 | retval = (STp->buffer)->syscall_result; | ||
3663 | goto out; | ||
3664 | } | ||
3665 | |||
3666 | if (STm->do_async_writes && ((STp->buffer)->buffer_bytes >= STp->write_threshold)) { | ||
3667 | /* Schedule an asynchronous write */ | ||
3668 | (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / | ||
3669 | STp->block_size) * STp->block_size; | ||
3670 | STp->dirty = !((STp->buffer)->writing == | ||
3671 | (STp->buffer)->buffer_bytes); | ||
3672 | |||
3673 | i = osst_write_frame(STp, &SRpnt, 0); | ||
3674 | if (i < 0) { | ||
3675 | retval = (-EIO); | ||
3676 | goto out; | ||
3677 | } | ||
3678 | SRpnt = NULL; /* Prevent releasing this request! */ | ||
3679 | } | ||
3680 | STps->at_sm &= (total == 0); | ||
3681 | if (total > 0) | ||
3682 | STps->eof = ST_NOEOF; | ||
3683 | |||
3684 | retval = total; | ||
3685 | |||
3686 | out: | ||
3687 | if (SRpnt != NULL) osst_release_request(SRpnt); | ||
3688 | |||
3689 | mutex_unlock(&STp->lock); | ||
3690 | |||
3691 | return retval; | ||
3692 | } | ||
3693 | |||
3694 | |||
3695 | /* Read command */ | ||
3696 | static ssize_t osst_read(struct file * filp, char __user * buf, size_t count, loff_t *ppos) | ||
3697 | { | ||
3698 | ssize_t total, retval = 0; | ||
3699 | ssize_t i, transfer; | ||
3700 | int special; | ||
3701 | struct st_modedef * STm; | ||
3702 | struct st_partstat * STps; | ||
3703 | struct osst_request * SRpnt = NULL; | ||
3704 | struct osst_tape * STp = filp->private_data; | ||
3705 | char * name = tape_name(STp); | ||
3706 | |||
3707 | |||
3708 | if (mutex_lock_interruptible(&STp->lock)) | ||
3709 | return (-ERESTARTSYS); | ||
3710 | |||
3711 | /* | ||
3712 | * If we are in the middle of error recovery, don't let anyone | ||
3713 | * else try and use this device. Also, if error recovery fails, it | ||
3714 | * may try and take the device offline, in which case all further | ||
3715 | * access to the device is prohibited. | ||
3716 | */ | ||
3717 | if( !scsi_block_when_processing_errors(STp->device) ) { | ||
3718 | retval = (-ENXIO); | ||
3719 | goto out; | ||
3720 | } | ||
3721 | |||
3722 | if (STp->ready != ST_READY) { | ||
3723 | if (STp->ready == ST_NO_TAPE) | ||
3724 | retval = (-ENOMEDIUM); | ||
3725 | else | ||
3726 | retval = (-EIO); | ||
3727 | goto out; | ||
3728 | } | ||
3729 | STm = &(STp->modes[STp->current_mode]); | ||
3730 | if (!STm->defined) { | ||
3731 | retval = (-ENXIO); | ||
3732 | goto out; | ||
3733 | } | ||
3734 | #if DEBUG | ||
3735 | if (!STp->in_use) { | ||
3736 | printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); | ||
3737 | retval = (-EIO); | ||
3738 | goto out; | ||
3739 | } | ||
3740 | #endif | ||
3741 | /* Must have initialized medium */ | ||
3742 | if (!STp->header_ok) { | ||
3743 | retval = (-EIO); | ||
3744 | goto out; | ||
3745 | } | ||
3746 | |||
3747 | if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1)) | ||
3748 | STp->door_locked = ST_LOCKED_AUTO; | ||
3749 | |||
3750 | STps = &(STp->ps[STp->partition]); | ||
3751 | if (STps->rw == ST_WRITING) { | ||
3752 | retval = osst_flush_buffer(STp, &SRpnt, 0); | ||
3753 | if (retval) | ||
3754 | goto out; | ||
3755 | STps->rw = ST_IDLE; | ||
3756 | /* FIXME -- this may leave the tape without EOD and up2date headers */ | ||
3757 | } | ||
3758 | |||
3759 | if ((count % STp->block_size) != 0) { | ||
3760 | printk(KERN_WARNING | ||
3761 | "%s:W: Read (%zd bytes) not multiple of tape block size (%d%c).\n", name, count, | ||
3762 | STp->block_size<1024?STp->block_size:STp->block_size/1024, STp->block_size<1024?'b':'k'); | ||
3763 | } | ||
3764 | |||
3765 | #if DEBUG | ||
3766 | if (debugging && STps->eof != ST_NOEOF) | ||
3767 | printk(OSST_DEB_MSG "%s:D: EOF/EOM flag up (%d). Bytes %d\n", name, | ||
3768 | STps->eof, (STp->buffer)->buffer_bytes); | ||
3769 | #endif | ||
3770 | if ((STp->buffer)->buffer_bytes == 0 && | ||
3771 | STps->eof >= ST_EOD_1) { | ||
3772 | if (STps->eof < ST_EOD) { | ||
3773 | STps->eof += 1; | ||
3774 | retval = 0; | ||
3775 | goto out; | ||
3776 | } | ||
3777 | retval = (-EIO); /* EOM or Blank Check */ | ||
3778 | goto out; | ||
3779 | } | ||
3780 | |||
3781 | /* Check the buffer writability before any tape movement. Don't alter | ||
3782 | buffer data. */ | ||
3783 | if (copy_from_user(&i, buf, 1) != 0 || | ||
3784 | copy_to_user (buf, &i, 1) != 0 || | ||
3785 | copy_from_user(&i, buf + count - 1, 1) != 0 || | ||
3786 | copy_to_user (buf + count - 1, &i, 1) != 0) { | ||
3787 | retval = (-EFAULT); | ||
3788 | goto out; | ||
3789 | } | ||
3790 | |||
3791 | /* Loop until enough data in buffer or a special condition found */ | ||
3792 | for (total = 0, special = 0; total < count - STp->block_size + 1 && !special; ) { | ||
3793 | |||
3794 | /* Get new data if the buffer is empty */ | ||
3795 | if ((STp->buffer)->buffer_bytes == 0) { | ||
3796 | if (STps->eof == ST_FM_HIT) | ||
3797 | break; | ||
3798 | special = osst_get_logical_frame(STp, &SRpnt, STp->frame_seq_number, 0); | ||
3799 | if (special < 0) { /* No need to continue read */ | ||
3800 | STp->frame_in_buffer = 0; | ||
3801 | retval = special; | ||
3802 | goto out; | ||
3803 | } | ||
3804 | } | ||
3805 | |||
3806 | /* Move the data from driver buffer to user buffer */ | ||
3807 | if ((STp->buffer)->buffer_bytes > 0) { | ||
3808 | #if DEBUG | ||
3809 | if (debugging && STps->eof != ST_NOEOF) | ||
3810 | printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name, | ||
3811 | STps->eof, (STp->buffer)->buffer_bytes, (int) (count - total)); | ||
3812 | #endif | ||
3813 | /* force multiple of block size, note block_size may have been adjusted */ | ||
3814 | transfer = (((STp->buffer)->buffer_bytes < count - total ? | ||
3815 | (STp->buffer)->buffer_bytes : count - total)/ | ||
3816 | STp->block_size) * STp->block_size; | ||
3817 | |||
3818 | if (transfer == 0) { | ||
3819 | printk(KERN_WARNING | ||
3820 | "%s:W: Nothing can be transferred, requested %zd, tape block size (%d%c).\n", | ||
3821 | name, count, STp->block_size < 1024? | ||
3822 | STp->block_size:STp->block_size/1024, | ||
3823 | STp->block_size<1024?'b':'k'); | ||
3824 | break; | ||
3825 | } | ||
3826 | i = from_buffer(STp->buffer, buf, transfer); | ||
3827 | if (i) { | ||
3828 | retval = i; | ||
3829 | goto out; | ||
3830 | } | ||
3831 | STp->logical_blk_num += transfer / STp->block_size; | ||
3832 | STps->drv_block += transfer / STp->block_size; | ||
3833 | *ppos += transfer; | ||
3834 | buf += transfer; | ||
3835 | total += transfer; | ||
3836 | } | ||
3837 | |||
3838 | if ((STp->buffer)->buffer_bytes == 0) { | ||
3839 | #if DEBUG | ||
3840 | if (debugging) | ||
3841 | printk(OSST_DEB_MSG "%s:D: Finished with frame %d\n", | ||
3842 | name, STp->frame_seq_number); | ||
3843 | #endif | ||
3844 | STp->frame_in_buffer = 0; | ||
3845 | STp->frame_seq_number++; /* frame to look for next time */ | ||
3846 | } | ||
3847 | } /* for (total = 0, special = 0; total < count && !special; ) */ | ||
3848 | |||
3849 | /* Change the eof state if no data from tape or buffer */ | ||
3850 | if (total == 0) { | ||
3851 | if (STps->eof == ST_FM_HIT) { | ||
3852 | STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD_2:ST_FM; | ||
3853 | STps->drv_block = 0; | ||
3854 | if (STps->drv_file >= 0) | ||
3855 | STps->drv_file++; | ||
3856 | } | ||
3857 | else if (STps->eof == ST_EOD_1) { | ||
3858 | STps->eof = ST_EOD_2; | ||
3859 | if (STps->drv_block > 0 && STps->drv_file >= 0) | ||
3860 | STps->drv_file++; | ||
3861 | STps->drv_block = 0; | ||
3862 | } | ||
3863 | else if (STps->eof == ST_EOD_2) | ||
3864 | STps->eof = ST_EOD; | ||
3865 | } | ||
3866 | else if (STps->eof == ST_FM) | ||
3867 | STps->eof = ST_NOEOF; | ||
3868 | |||
3869 | retval = total; | ||
3870 | |||
3871 | out: | ||
3872 | if (SRpnt != NULL) osst_release_request(SRpnt); | ||
3873 | |||
3874 | mutex_unlock(&STp->lock); | ||
3875 | |||
3876 | return retval; | ||
3877 | } | ||
3878 | |||
3879 | |||
3880 | /* Set the driver options */ | ||
3881 | static void osst_log_options(struct osst_tape *STp, struct st_modedef *STm, char *name) | ||
3882 | { | ||
3883 | printk(KERN_INFO | ||
3884 | "%s:I: Mode %d options: buffer writes: %d, async writes: %d, read ahead: %d\n", | ||
3885 | name, STp->current_mode, STm->do_buffer_writes, STm->do_async_writes, | ||
3886 | STm->do_read_ahead); | ||
3887 | printk(KERN_INFO | ||
3888 | "%s:I: can bsr: %d, two FMs: %d, fast mteom: %d, auto lock: %d,\n", | ||
3889 | name, STp->can_bsr, STp->two_fm, STp->fast_mteom, STp->do_auto_lock); | ||
3890 | printk(KERN_INFO | ||
3891 | "%s:I: defs for wr: %d, no block limits: %d, partitions: %d, s2 log: %d\n", | ||
3892 | name, STm->defaults_for_writes, STp->omit_blklims, STp->can_partitions, | ||
3893 | STp->scsi2_logical); | ||
3894 | printk(KERN_INFO | ||
3895 | "%s:I: sysv: %d\n", name, STm->sysv); | ||
3896 | #if DEBUG | ||
3897 | printk(KERN_INFO | ||
3898 | "%s:D: debugging: %d\n", | ||
3899 | name, debugging); | ||
3900 | #endif | ||
3901 | } | ||
3902 | |||
3903 | |||
3904 | static int osst_set_options(struct osst_tape *STp, long options) | ||
3905 | { | ||
3906 | int value; | ||
3907 | long code; | ||
3908 | struct st_modedef * STm; | ||
3909 | char * name = tape_name(STp); | ||
3910 | |||
3911 | STm = &(STp->modes[STp->current_mode]); | ||
3912 | if (!STm->defined) { | ||
3913 | memcpy(STm, &(STp->modes[0]), sizeof(*STm)); | ||
3914 | modes_defined = 1; | ||
3915 | #if DEBUG | ||
3916 | if (debugging) | ||
3917 | printk(OSST_DEB_MSG "%s:D: Initialized mode %d definition from mode 0\n", | ||
3918 | name, STp->current_mode); | ||
3919 | #endif | ||
3920 | } | ||
3921 | |||
3922 | code = options & MT_ST_OPTIONS; | ||
3923 | if (code == MT_ST_BOOLEANS) { | ||
3924 | STm->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; | ||
3925 | STm->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; | ||
3926 | STm->defaults_for_writes = (options & MT_ST_DEF_WRITES) != 0; | ||
3927 | STm->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; | ||
3928 | STp->two_fm = (options & MT_ST_TWO_FM) != 0; | ||
3929 | STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0; | ||
3930 | STp->do_auto_lock = (options & MT_ST_AUTO_LOCK) != 0; | ||
3931 | STp->can_bsr = (options & MT_ST_CAN_BSR) != 0; | ||
3932 | STp->omit_blklims = (options & MT_ST_NO_BLKLIMS) != 0; | ||
3933 | if ((STp->device)->scsi_level >= SCSI_2) | ||
3934 | STp->can_partitions = (options & MT_ST_CAN_PARTITIONS) != 0; | ||
3935 | STp->scsi2_logical = (options & MT_ST_SCSI2LOGICAL) != 0; | ||
3936 | STm->sysv = (options & MT_ST_SYSV) != 0; | ||
3937 | #if DEBUG | ||
3938 | debugging = (options & MT_ST_DEBUGGING) != 0; | ||
3939 | #endif | ||
3940 | osst_log_options(STp, STm, name); | ||
3941 | } | ||
3942 | else if (code == MT_ST_SETBOOLEANS || code == MT_ST_CLEARBOOLEANS) { | ||
3943 | value = (code == MT_ST_SETBOOLEANS); | ||
3944 | if ((options & MT_ST_BUFFER_WRITES) != 0) | ||
3945 | STm->do_buffer_writes = value; | ||
3946 | if ((options & MT_ST_ASYNC_WRITES) != 0) | ||
3947 | STm->do_async_writes = value; | ||
3948 | if ((options & MT_ST_DEF_WRITES) != 0) | ||
3949 | STm->defaults_for_writes = value; | ||
3950 | if ((options & MT_ST_READ_AHEAD) != 0) | ||
3951 | STm->do_read_ahead = value; | ||
3952 | if ((options & MT_ST_TWO_FM) != 0) | ||
3953 | STp->two_fm = value; | ||
3954 | if ((options & MT_ST_FAST_MTEOM) != 0) | ||
3955 | STp->fast_mteom = value; | ||
3956 | if ((options & MT_ST_AUTO_LOCK) != 0) | ||
3957 | STp->do_auto_lock = value; | ||
3958 | if ((options & MT_ST_CAN_BSR) != 0) | ||
3959 | STp->can_bsr = value; | ||
3960 | if ((options & MT_ST_NO_BLKLIMS) != 0) | ||
3961 | STp->omit_blklims = value; | ||
3962 | if ((STp->device)->scsi_level >= SCSI_2 && | ||
3963 | (options & MT_ST_CAN_PARTITIONS) != 0) | ||
3964 | STp->can_partitions = value; | ||
3965 | if ((options & MT_ST_SCSI2LOGICAL) != 0) | ||
3966 | STp->scsi2_logical = value; | ||
3967 | if ((options & MT_ST_SYSV) != 0) | ||
3968 | STm->sysv = value; | ||
3969 | #if DEBUG | ||
3970 | if ((options & MT_ST_DEBUGGING) != 0) | ||
3971 | debugging = value; | ||
3972 | #endif | ||
3973 | osst_log_options(STp, STm, name); | ||
3974 | } | ||
3975 | else if (code == MT_ST_WRITE_THRESHOLD) { | ||
3976 | value = (options & ~MT_ST_OPTIONS) * ST_KILOBYTE; | ||
3977 | if (value < 1 || value > osst_buffer_size) { | ||
3978 | printk(KERN_WARNING "%s:W: Write threshold %d too small or too large.\n", | ||
3979 | name, value); | ||
3980 | return (-EIO); | ||
3981 | } | ||
3982 | STp->write_threshold = value; | ||
3983 | printk(KERN_INFO "%s:I: Write threshold set to %d bytes.\n", | ||
3984 | name, value); | ||
3985 | } | ||
3986 | else if (code == MT_ST_DEF_BLKSIZE) { | ||
3987 | value = (options & ~MT_ST_OPTIONS); | ||
3988 | if (value == ~MT_ST_OPTIONS) { | ||
3989 | STm->default_blksize = (-1); | ||
3990 | printk(KERN_INFO "%s:I: Default block size disabled.\n", name); | ||
3991 | } | ||
3992 | else { | ||
3993 | if (value < 512 || value > OS_DATA_SIZE || OS_DATA_SIZE % value) { | ||
3994 | printk(KERN_WARNING "%s:W: Default block size cannot be set to %d.\n", | ||
3995 | name, value); | ||
3996 | return (-EINVAL); | ||
3997 | } | ||
3998 | STm->default_blksize = value; | ||
3999 | printk(KERN_INFO "%s:I: Default block size set to %d bytes.\n", | ||
4000 | name, STm->default_blksize); | ||
4001 | } | ||
4002 | } | ||
4003 | else if (code == MT_ST_TIMEOUTS) { | ||
4004 | value = (options & ~MT_ST_OPTIONS); | ||
4005 | if ((value & MT_ST_SET_LONG_TIMEOUT) != 0) { | ||
4006 | STp->long_timeout = (value & ~MT_ST_SET_LONG_TIMEOUT) * HZ; | ||
4007 | printk(KERN_INFO "%s:I: Long timeout set to %d seconds.\n", name, | ||
4008 | (value & ~MT_ST_SET_LONG_TIMEOUT)); | ||
4009 | } | ||
4010 | else { | ||
4011 | STp->timeout = value * HZ; | ||
4012 | printk(KERN_INFO "%s:I: Normal timeout set to %d seconds.\n", name, value); | ||
4013 | } | ||
4014 | } | ||
4015 | else if (code == MT_ST_DEF_OPTIONS) { | ||
4016 | code = (options & ~MT_ST_CLEAR_DEFAULT); | ||
4017 | value = (options & MT_ST_CLEAR_DEFAULT); | ||
4018 | if (code == MT_ST_DEF_DENSITY) { | ||
4019 | if (value == MT_ST_CLEAR_DEFAULT) { | ||
4020 | STm->default_density = (-1); | ||
4021 | printk(KERN_INFO "%s:I: Density default disabled.\n", name); | ||
4022 | } | ||
4023 | else { | ||
4024 | STm->default_density = value & 0xff; | ||
4025 | printk(KERN_INFO "%s:I: Density default set to %x\n", | ||
4026 | name, STm->default_density); | ||
4027 | } | ||
4028 | } | ||
4029 | else if (code == MT_ST_DEF_DRVBUFFER) { | ||
4030 | if (value == MT_ST_CLEAR_DEFAULT) { | ||
4031 | STp->default_drvbuffer = 0xff; | ||
4032 | printk(KERN_INFO "%s:I: Drive buffer default disabled.\n", name); | ||
4033 | } | ||
4034 | else { | ||
4035 | STp->default_drvbuffer = value & 7; | ||
4036 | printk(KERN_INFO "%s:I: Drive buffer default set to %x\n", | ||
4037 | name, STp->default_drvbuffer); | ||
4038 | } | ||
4039 | } | ||
4040 | else if (code == MT_ST_DEF_COMPRESSION) { | ||
4041 | if (value == MT_ST_CLEAR_DEFAULT) { | ||
4042 | STm->default_compression = ST_DONT_TOUCH; | ||
4043 | printk(KERN_INFO "%s:I: Compression default disabled.\n", name); | ||
4044 | } | ||
4045 | else { | ||
4046 | STm->default_compression = (value & 1 ? ST_YES : ST_NO); | ||
4047 | printk(KERN_INFO "%s:I: Compression default set to %x\n", | ||
4048 | name, (value & 1)); | ||
4049 | } | ||
4050 | } | ||
4051 | } | ||
4052 | else | ||
4053 | return (-EIO); | ||
4054 | |||
4055 | return 0; | ||
4056 | } | ||
4057 | |||
4058 | |||
4059 | /* Internal ioctl function */ | ||
4060 | static int osst_int_ioctl(struct osst_tape * STp, struct osst_request ** aSRpnt, | ||
4061 | unsigned int cmd_in, unsigned long arg) | ||
4062 | { | ||
4063 | int timeout; | ||
4064 | long ltmp; | ||
4065 | int i, ioctl_result; | ||
4066 | int chg_eof = 1; | ||
4067 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
4068 | struct osst_request * SRpnt = * aSRpnt; | ||
4069 | struct st_partstat * STps; | ||
4070 | int fileno, blkno, at_sm, frame_seq_numbr, logical_blk_num; | ||
4071 | int datalen = 0, direction = DMA_NONE; | ||
4072 | char * name = tape_name(STp); | ||
4073 | |||
4074 | if (STp->ready != ST_READY && cmd_in != MTLOAD) { | ||
4075 | if (STp->ready == ST_NO_TAPE) | ||
4076 | return (-ENOMEDIUM); | ||
4077 | else | ||
4078 | return (-EIO); | ||
4079 | } | ||
4080 | timeout = STp->long_timeout; | ||
4081 | STps = &(STp->ps[STp->partition]); | ||
4082 | fileno = STps->drv_file; | ||
4083 | blkno = STps->drv_block; | ||
4084 | at_sm = STps->at_sm; | ||
4085 | frame_seq_numbr = STp->frame_seq_number; | ||
4086 | logical_blk_num = STp->logical_blk_num; | ||
4087 | |||
4088 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
4089 | switch (cmd_in) { | ||
4090 | case MTFSFM: | ||
4091 | chg_eof = 0; /* Changed from the FSF after this */ | ||
4092 | /* fall through */ | ||
4093 | case MTFSF: | ||
4094 | if (STp->raw) | ||
4095 | return (-EIO); | ||
4096 | if (STp->linux_media) | ||
4097 | ioctl_result = osst_space_over_filemarks_forward_fast(STp, &SRpnt, cmd_in, arg); | ||
4098 | else | ||
4099 | ioctl_result = osst_space_over_filemarks_forward_slow(STp, &SRpnt, cmd_in, arg); | ||
4100 | if (fileno >= 0) | ||
4101 | fileno += arg; | ||
4102 | blkno = 0; | ||
4103 | at_sm &= (arg == 0); | ||
4104 | goto os_bypass; | ||
4105 | |||
4106 | case MTBSF: | ||
4107 | chg_eof = 0; /* Changed from the FSF after this */ | ||
4108 | /* fall through */ | ||
4109 | case MTBSFM: | ||
4110 | if (STp->raw) | ||
4111 | return (-EIO); | ||
4112 | ioctl_result = osst_space_over_filemarks_backward(STp, &SRpnt, cmd_in, arg); | ||
4113 | if (fileno >= 0) | ||
4114 | fileno -= arg; | ||
4115 | blkno = (-1); /* We can't know the block number */ | ||
4116 | at_sm &= (arg == 0); | ||
4117 | goto os_bypass; | ||
4118 | |||
4119 | case MTFSR: | ||
4120 | case MTBSR: | ||
4121 | #if DEBUG | ||
4122 | if (debugging) | ||
4123 | printk(OSST_DEB_MSG "%s:D: Skipping %lu blocks %s from logical block %d\n", | ||
4124 | name, arg, cmd_in==MTFSR?"forward":"backward", logical_blk_num); | ||
4125 | #endif | ||
4126 | if (cmd_in == MTFSR) { | ||
4127 | logical_blk_num += arg; | ||
4128 | if (blkno >= 0) blkno += arg; | ||
4129 | } | ||
4130 | else { | ||
4131 | logical_blk_num -= arg; | ||
4132 | if (blkno >= 0) blkno -= arg; | ||
4133 | } | ||
4134 | ioctl_result = osst_seek_logical_blk(STp, &SRpnt, logical_blk_num); | ||
4135 | fileno = STps->drv_file; | ||
4136 | blkno = STps->drv_block; | ||
4137 | at_sm &= (arg == 0); | ||
4138 | goto os_bypass; | ||
4139 | |||
4140 | case MTFSS: | ||
4141 | cmd[0] = SPACE; | ||
4142 | cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ | ||
4143 | cmd[2] = (arg >> 16); | ||
4144 | cmd[3] = (arg >> 8); | ||
4145 | cmd[4] = arg; | ||
4146 | #if DEBUG | ||
4147 | if (debugging) | ||
4148 | printk(OSST_DEB_MSG "%s:D: Spacing tape forward %d setmarks.\n", name, | ||
4149 | cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); | ||
4150 | #endif | ||
4151 | if (arg != 0) { | ||
4152 | blkno = fileno = (-1); | ||
4153 | at_sm = 1; | ||
4154 | } | ||
4155 | break; | ||
4156 | case MTBSS: | ||
4157 | cmd[0] = SPACE; | ||
4158 | cmd[1] = 0x04; /* Space Setmarks */ /* FIXME -- OS can't do this? */ | ||
4159 | ltmp = (-arg); | ||
4160 | cmd[2] = (ltmp >> 16); | ||
4161 | cmd[3] = (ltmp >> 8); | ||
4162 | cmd[4] = ltmp; | ||
4163 | #if DEBUG | ||
4164 | if (debugging) { | ||
4165 | if (cmd[2] & 0x80) | ||
4166 | ltmp = 0xff000000; | ||
4167 | ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; | ||
4168 | printk(OSST_DEB_MSG "%s:D: Spacing tape backward %ld setmarks.\n", | ||
4169 | name, (-ltmp)); | ||
4170 | } | ||
4171 | #endif | ||
4172 | if (arg != 0) { | ||
4173 | blkno = fileno = (-1); | ||
4174 | at_sm = 1; | ||
4175 | } | ||
4176 | break; | ||
4177 | case MTWEOF: | ||
4178 | if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { | ||
4179 | STp->write_type = OS_WRITE_DATA; | ||
4180 | ioctl_result = osst_flush_write_buffer(STp, &SRpnt); | ||
4181 | } else | ||
4182 | ioctl_result = 0; | ||
4183 | #if DEBUG | ||
4184 | if (debugging) | ||
4185 | printk(OSST_DEB_MSG "%s:D: Writing %ld filemark(s).\n", name, arg); | ||
4186 | #endif | ||
4187 | for (i=0; i<arg; i++) | ||
4188 | ioctl_result |= osst_write_filemark(STp, &SRpnt); | ||
4189 | if (fileno >= 0) fileno += arg; | ||
4190 | if (blkno >= 0) blkno = 0; | ||
4191 | goto os_bypass; | ||
4192 | |||
4193 | case MTWSM: | ||
4194 | if (STp->write_prot) | ||
4195 | return (-EACCES); | ||
4196 | if (!STp->raw) | ||
4197 | return 0; | ||
4198 | cmd[0] = WRITE_FILEMARKS; /* FIXME -- need OS version */ | ||
4199 | if (cmd_in == MTWSM) | ||
4200 | cmd[1] = 2; | ||
4201 | cmd[2] = (arg >> 16); | ||
4202 | cmd[3] = (arg >> 8); | ||
4203 | cmd[4] = arg; | ||
4204 | timeout = STp->timeout; | ||
4205 | #if DEBUG | ||
4206 | if (debugging) | ||
4207 | printk(OSST_DEB_MSG "%s:D: Writing %d setmark(s).\n", name, | ||
4208 | cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); | ||
4209 | #endif | ||
4210 | if (fileno >= 0) | ||
4211 | fileno += arg; | ||
4212 | blkno = 0; | ||
4213 | at_sm = (cmd_in == MTWSM); | ||
4214 | break; | ||
4215 | case MTOFFL: | ||
4216 | case MTLOAD: | ||
4217 | case MTUNLOAD: | ||
4218 | case MTRETEN: | ||
4219 | cmd[0] = START_STOP; | ||
4220 | cmd[1] = 1; /* Don't wait for completion */ | ||
4221 | if (cmd_in == MTLOAD) { | ||
4222 | if (STp->ready == ST_NO_TAPE) | ||
4223 | cmd[4] = 4; /* open tray */ | ||
4224 | else | ||
4225 | cmd[4] = 1; /* load */ | ||
4226 | } | ||
4227 | if (cmd_in == MTRETEN) | ||
4228 | cmd[4] = 3; /* retension then mount */ | ||
4229 | if (cmd_in == MTOFFL) | ||
4230 | cmd[4] = 4; /* rewind then eject */ | ||
4231 | timeout = STp->timeout; | ||
4232 | #if DEBUG | ||
4233 | if (debugging) { | ||
4234 | switch (cmd_in) { | ||
4235 | case MTUNLOAD: | ||
4236 | printk(OSST_DEB_MSG "%s:D: Unloading tape.\n", name); | ||
4237 | break; | ||
4238 | case MTLOAD: | ||
4239 | printk(OSST_DEB_MSG "%s:D: Loading tape.\n", name); | ||
4240 | break; | ||
4241 | case MTRETEN: | ||
4242 | printk(OSST_DEB_MSG "%s:D: Retensioning tape.\n", name); | ||
4243 | break; | ||
4244 | case MTOFFL: | ||
4245 | printk(OSST_DEB_MSG "%s:D: Ejecting tape.\n", name); | ||
4246 | break; | ||
4247 | } | ||
4248 | } | ||
4249 | #endif | ||
4250 | fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; | ||
4251 | break; | ||
4252 | case MTNOP: | ||
4253 | #if DEBUG | ||
4254 | if (debugging) | ||
4255 | printk(OSST_DEB_MSG "%s:D: No-op on tape.\n", name); | ||
4256 | #endif | ||
4257 | return 0; /* Should do something ? */ | ||
4258 | break; | ||
4259 | case MTEOM: | ||
4260 | #if DEBUG | ||
4261 | if (debugging) | ||
4262 | printk(OSST_DEB_MSG "%s:D: Spacing to end of recorded medium.\n", name); | ||
4263 | #endif | ||
4264 | if ((osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) || | ||
4265 | (osst_get_logical_frame(STp, &SRpnt, -1, 0) < 0)) { | ||
4266 | ioctl_result = -EIO; | ||
4267 | goto os_bypass; | ||
4268 | } | ||
4269 | if (STp->buffer->aux->frame_type != OS_FRAME_TYPE_EOD) { | ||
4270 | #if DEBUG | ||
4271 | printk(OSST_DEB_MSG "%s:D: No EOD frame found where expected.\n", name); | ||
4272 | #endif | ||
4273 | ioctl_result = -EIO; | ||
4274 | goto os_bypass; | ||
4275 | } | ||
4276 | ioctl_result = osst_set_frame_position(STp, &SRpnt, STp->eod_frame_ppos, 0); | ||
4277 | fileno = STp->filemark_cnt; | ||
4278 | blkno = at_sm = 0; | ||
4279 | goto os_bypass; | ||
4280 | |||
4281 | case MTERASE: | ||
4282 | if (STp->write_prot) | ||
4283 | return (-EACCES); | ||
4284 | ioctl_result = osst_reset_header(STp, &SRpnt); | ||
4285 | i = osst_write_eod(STp, &SRpnt); | ||
4286 | if (i < ioctl_result) ioctl_result = i; | ||
4287 | i = osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos); | ||
4288 | if (i < ioctl_result) ioctl_result = i; | ||
4289 | fileno = blkno = at_sm = 0 ; | ||
4290 | goto os_bypass; | ||
4291 | |||
4292 | case MTREW: | ||
4293 | cmd[0] = REZERO_UNIT; /* rewind */ | ||
4294 | cmd[1] = 1; | ||
4295 | #if DEBUG | ||
4296 | if (debugging) | ||
4297 | printk(OSST_DEB_MSG "%s:D: Rewinding tape, Immed=%d.\n", name, cmd[1]); | ||
4298 | #endif | ||
4299 | fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; | ||
4300 | break; | ||
4301 | |||
4302 | case MTSETBLK: /* Set block length */ | ||
4303 | if ((STps->drv_block == 0 ) && | ||
4304 | !STp->dirty && | ||
4305 | ((STp->buffer)->buffer_bytes == 0) && | ||
4306 | ((arg & MT_ST_BLKSIZE_MASK) >= 512 ) && | ||
4307 | ((arg & MT_ST_BLKSIZE_MASK) <= OS_DATA_SIZE) && | ||
4308 | !(OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK)) ) { | ||
4309 | /* | ||
4310 | * Only allowed to change the block size if you opened the | ||
4311 | * device at the beginning of a file before writing anything. | ||
4312 | * Note, that when reading, changing block_size is futile, | ||
4313 | * as the size used when writing overrides it. | ||
4314 | */ | ||
4315 | STp->block_size = (arg & MT_ST_BLKSIZE_MASK); | ||
4316 | printk(KERN_INFO "%s:I: Block size set to %d bytes.\n", | ||
4317 | name, STp->block_size); | ||
4318 | return 0; | ||
4319 | } | ||
4320 | /* fall through */ | ||
4321 | case MTSETDENSITY: /* Set tape density */ | ||
4322 | case MTSETDRVBUFFER: /* Set drive buffering */ | ||
4323 | case SET_DENS_AND_BLK: /* Set density and block size */ | ||
4324 | chg_eof = 0; | ||
4325 | if (STp->dirty || (STp->buffer)->buffer_bytes != 0) | ||
4326 | return (-EIO); /* Not allowed if data in buffer */ | ||
4327 | if ((cmd_in == MTSETBLK || cmd_in == SET_DENS_AND_BLK) && | ||
4328 | (arg & MT_ST_BLKSIZE_MASK) != 0 && | ||
4329 | (arg & MT_ST_BLKSIZE_MASK) != STp->block_size ) { | ||
4330 | printk(KERN_WARNING "%s:W: Illegal to set block size to %d%s.\n", | ||
4331 | name, (int)(arg & MT_ST_BLKSIZE_MASK), | ||
4332 | (OS_DATA_SIZE % (arg & MT_ST_BLKSIZE_MASK))?"":" now"); | ||
4333 | return (-EINVAL); | ||
4334 | } | ||
4335 | return 0; /* FIXME silently ignore if block size didn't change */ | ||
4336 | |||
4337 | default: | ||
4338 | return (-ENOSYS); | ||
4339 | } | ||
4340 | |||
4341 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, datalen, direction, timeout, MAX_RETRIES, 1); | ||
4342 | |||
4343 | ioctl_result = (STp->buffer)->syscall_result; | ||
4344 | |||
4345 | if (!SRpnt) { | ||
4346 | #if DEBUG | ||
4347 | printk(OSST_DEB_MSG "%s:D: Couldn't exec scsi cmd for IOCTL\n", name); | ||
4348 | #endif | ||
4349 | return ioctl_result; | ||
4350 | } | ||
4351 | |||
4352 | if (!ioctl_result) { /* SCSI command successful */ | ||
4353 | STp->frame_seq_number = frame_seq_numbr; | ||
4354 | STp->logical_blk_num = logical_blk_num; | ||
4355 | } | ||
4356 | |||
4357 | os_bypass: | ||
4358 | #if DEBUG | ||
4359 | if (debugging) | ||
4360 | printk(OSST_DEB_MSG "%s:D: IOCTL (%d) Result=%d\n", name, cmd_in, ioctl_result); | ||
4361 | #endif | ||
4362 | |||
4363 | if (!ioctl_result) { /* success */ | ||
4364 | |||
4365 | if (cmd_in == MTFSFM) { | ||
4366 | fileno--; | ||
4367 | blkno--; | ||
4368 | } | ||
4369 | if (cmd_in == MTBSFM) { | ||
4370 | fileno++; | ||
4371 | blkno++; | ||
4372 | } | ||
4373 | STps->drv_block = blkno; | ||
4374 | STps->drv_file = fileno; | ||
4375 | STps->at_sm = at_sm; | ||
4376 | |||
4377 | if (cmd_in == MTEOM) | ||
4378 | STps->eof = ST_EOD; | ||
4379 | else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT) { | ||
4380 | ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num-1); | ||
4381 | STps->drv_block++; | ||
4382 | STp->logical_blk_num++; | ||
4383 | STp->frame_seq_number++; | ||
4384 | STp->frame_in_buffer = 0; | ||
4385 | STp->buffer->read_pointer = 0; | ||
4386 | } | ||
4387 | else if (cmd_in == MTFSF) | ||
4388 | STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; | ||
4389 | else if (chg_eof) | ||
4390 | STps->eof = ST_NOEOF; | ||
4391 | |||
4392 | if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) | ||
4393 | STp->rew_at_close = 0; | ||
4394 | else if (cmd_in == MTLOAD) { | ||
4395 | for (i=0; i < ST_NBR_PARTITIONS; i++) { | ||
4396 | STp->ps[i].rw = ST_IDLE; | ||
4397 | STp->ps[i].last_block_valid = 0;/* FIXME - where else is this field maintained? */ | ||
4398 | } | ||
4399 | STp->partition = 0; | ||
4400 | } | ||
4401 | |||
4402 | if (cmd_in == MTREW) { | ||
4403 | ioctl_result = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); | ||
4404 | if (ioctl_result > 0) | ||
4405 | ioctl_result = 0; | ||
4406 | } | ||
4407 | |||
4408 | } else if (cmd_in == MTBSF || cmd_in == MTBSFM ) { | ||
4409 | if (osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos) < 0) | ||
4410 | STps->drv_file = STps->drv_block = -1; | ||
4411 | else | ||
4412 | STps->drv_file = STps->drv_block = 0; | ||
4413 | STps->eof = ST_NOEOF; | ||
4414 | } else if (cmd_in == MTFSF || cmd_in == MTFSFM) { | ||
4415 | if (osst_position_tape_and_confirm(STp, &SRpnt, STp->eod_frame_ppos) < 0) | ||
4416 | STps->drv_file = STps->drv_block = -1; | ||
4417 | else { | ||
4418 | STps->drv_file = STp->filemark_cnt; | ||
4419 | STps->drv_block = 0; | ||
4420 | } | ||
4421 | STps->eof = ST_EOD; | ||
4422 | } else if (cmd_in == MTBSR || cmd_in == MTFSR || cmd_in == MTWEOF || cmd_in == MTEOM) { | ||
4423 | STps->drv_file = STps->drv_block = (-1); | ||
4424 | STps->eof = ST_NOEOF; | ||
4425 | STp->header_ok = 0; | ||
4426 | } else if (cmd_in == MTERASE) { | ||
4427 | STp->header_ok = 0; | ||
4428 | } else if (SRpnt) { /* SCSI command was not completely successful. */ | ||
4429 | if (SRpnt->sense[2] & 0x40) { | ||
4430 | STps->eof = ST_EOM_OK; | ||
4431 | STps->drv_block = 0; | ||
4432 | } | ||
4433 | if (chg_eof) | ||
4434 | STps->eof = ST_NOEOF; | ||
4435 | |||
4436 | if ((SRpnt->sense[2] & 0x0f) == BLANK_CHECK) | ||
4437 | STps->eof = ST_EOD; | ||
4438 | |||
4439 | if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) | ||
4440 | ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE); | ||
4441 | } | ||
4442 | *aSRpnt = SRpnt; | ||
4443 | |||
4444 | return ioctl_result; | ||
4445 | } | ||
4446 | |||
4447 | |||
4448 | /* Open the device */ | ||
4449 | static int __os_scsi_tape_open(struct inode * inode, struct file * filp) | ||
4450 | { | ||
4451 | unsigned short flags; | ||
4452 | int i, b_size, new_session = 0, retval = 0; | ||
4453 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
4454 | struct osst_request * SRpnt = NULL; | ||
4455 | struct osst_tape * STp; | ||
4456 | struct st_modedef * STm; | ||
4457 | struct st_partstat * STps; | ||
4458 | char * name; | ||
4459 | int dev = TAPE_NR(inode); | ||
4460 | int mode = TAPE_MODE(inode); | ||
4461 | |||
4462 | /* | ||
4463 | * We really want to do nonseekable_open(inode, filp); here, but some | ||
4464 | * versions of tar incorrectly call lseek on tapes and bail out if that | ||
4465 | * fails. So we disallow pread() and pwrite(), but permit lseeks. | ||
4466 | */ | ||
4467 | filp->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE); | ||
4468 | |||
4469 | write_lock(&os_scsi_tapes_lock); | ||
4470 | if (dev >= osst_max_dev || os_scsi_tapes == NULL || | ||
4471 | (STp = os_scsi_tapes[dev]) == NULL || !STp->device) { | ||
4472 | write_unlock(&os_scsi_tapes_lock); | ||
4473 | return (-ENXIO); | ||
4474 | } | ||
4475 | |||
4476 | name = tape_name(STp); | ||
4477 | |||
4478 | if (STp->in_use) { | ||
4479 | write_unlock(&os_scsi_tapes_lock); | ||
4480 | #if DEBUG | ||
4481 | printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name); | ||
4482 | #endif | ||
4483 | return (-EBUSY); | ||
4484 | } | ||
4485 | if (scsi_device_get(STp->device)) { | ||
4486 | write_unlock(&os_scsi_tapes_lock); | ||
4487 | #if DEBUG | ||
4488 | printk(OSST_DEB_MSG "%s:D: Failed scsi_device_get.\n", name); | ||
4489 | #endif | ||
4490 | return (-ENXIO); | ||
4491 | } | ||
4492 | filp->private_data = STp; | ||
4493 | STp->in_use = 1; | ||
4494 | write_unlock(&os_scsi_tapes_lock); | ||
4495 | STp->rew_at_close = TAPE_REWIND(inode); | ||
4496 | |||
4497 | if( !scsi_block_when_processing_errors(STp->device) ) { | ||
4498 | return -ENXIO; | ||
4499 | } | ||
4500 | |||
4501 | if (mode != STp->current_mode) { | ||
4502 | #if DEBUG | ||
4503 | if (debugging) | ||
4504 | printk(OSST_DEB_MSG "%s:D: Mode change from %d to %d.\n", | ||
4505 | name, STp->current_mode, mode); | ||
4506 | #endif | ||
4507 | new_session = 1; | ||
4508 | STp->current_mode = mode; | ||
4509 | } | ||
4510 | STm = &(STp->modes[STp->current_mode]); | ||
4511 | |||
4512 | flags = filp->f_flags; | ||
4513 | STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); | ||
4514 | |||
4515 | STp->raw = TAPE_IS_RAW(inode); | ||
4516 | if (STp->raw) | ||
4517 | STp->header_ok = 0; | ||
4518 | |||
4519 | /* Allocate data segments for this device's tape buffer */ | ||
4520 | if (!enlarge_buffer(STp->buffer, STp->restr_dma)) { | ||
4521 | printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name); | ||
4522 | retval = (-EOVERFLOW); | ||
4523 | goto err_out; | ||
4524 | } | ||
4525 | if (STp->buffer->buffer_size >= OS_FRAME_SIZE) { | ||
4526 | for (i = 0, b_size = 0; | ||
4527 | (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE); | ||
4528 | b_size += STp->buffer->sg[i++].length); | ||
4529 | STp->buffer->aux = (os_aux_t *) (page_address(sg_page(&STp->buffer->sg[i])) + OS_DATA_SIZE - b_size); | ||
4530 | #if DEBUG | ||
4531 | printk(OSST_DEB_MSG "%s:D: b_data points to %p in segment 0 at %p\n", name, | ||
4532 | STp->buffer->b_data, page_address(STp->buffer->sg[0].page)); | ||
4533 | printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name, | ||
4534 | STp->buffer->aux, i, page_address(STp->buffer->sg[i].page)); | ||
4535 | #endif | ||
4536 | } else { | ||
4537 | STp->buffer->aux = NULL; /* this had better never happen! */ | ||
4538 | printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE); | ||
4539 | retval = (-EIO); | ||
4540 | goto err_out; | ||
4541 | } | ||
4542 | STp->buffer->writing = 0; | ||
4543 | STp->buffer->syscall_result = 0; | ||
4544 | STp->dirty = 0; | ||
4545 | for (i=0; i < ST_NBR_PARTITIONS; i++) { | ||
4546 | STps = &(STp->ps[i]); | ||
4547 | STps->rw = ST_IDLE; | ||
4548 | } | ||
4549 | STp->ready = ST_READY; | ||
4550 | #if DEBUG | ||
4551 | STp->nbr_waits = STp->nbr_finished = 0; | ||
4552 | #endif | ||
4553 | |||
4554 | memset (cmd, 0, MAX_COMMAND_SIZE); | ||
4555 | cmd[0] = TEST_UNIT_READY; | ||
4556 | |||
4557 | SRpnt = osst_do_scsi(NULL, STp, cmd, 0, DMA_NONE, STp->timeout, MAX_RETRIES, 1); | ||
4558 | if (!SRpnt) { | ||
4559 | retval = (STp->buffer)->syscall_result; /* FIXME - valid? */ | ||
4560 | goto err_out; | ||
4561 | } | ||
4562 | if ((SRpnt->sense[0] & 0x70) == 0x70 && | ||
4563 | (SRpnt->sense[2] & 0x0f) == NOT_READY && | ||
4564 | SRpnt->sense[12] == 4 ) { | ||
4565 | #if DEBUG | ||
4566 | printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sense[13]); | ||
4567 | #endif | ||
4568 | if (filp->f_flags & O_NONBLOCK) { | ||
4569 | retval = -EAGAIN; | ||
4570 | goto err_out; | ||
4571 | } | ||
4572 | if (SRpnt->sense[13] == 2) { /* initialize command required (LOAD) */ | ||
4573 | memset (cmd, 0, MAX_COMMAND_SIZE); | ||
4574 | cmd[0] = START_STOP; | ||
4575 | cmd[1] = 1; | ||
4576 | cmd[4] = 1; | ||
4577 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, | ||
4578 | STp->timeout, MAX_RETRIES, 1); | ||
4579 | } | ||
4580 | osst_wait_ready(STp, &SRpnt, (SRpnt->sense[13]==1?15:3) * 60, 0); | ||
4581 | } | ||
4582 | if ((SRpnt->sense[0] & 0x70) == 0x70 && | ||
4583 | (SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ | ||
4584 | #if DEBUG | ||
4585 | printk(OSST_DEB_MSG "%s:D: Unit wants attention\n", name); | ||
4586 | #endif | ||
4587 | STp->header_ok = 0; | ||
4588 | |||
4589 | for (i=0; i < 10; i++) { | ||
4590 | |||
4591 | memset (cmd, 0, MAX_COMMAND_SIZE); | ||
4592 | cmd[0] = TEST_UNIT_READY; | ||
4593 | |||
4594 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, | ||
4595 | STp->timeout, MAX_RETRIES, 1); | ||
4596 | if ((SRpnt->sense[0] & 0x70) != 0x70 || | ||
4597 | (SRpnt->sense[2] & 0x0f) != UNIT_ATTENTION) | ||
4598 | break; | ||
4599 | } | ||
4600 | |||
4601 | STp->pos_unknown = 0; | ||
4602 | STp->partition = STp->new_partition = 0; | ||
4603 | if (STp->can_partitions) | ||
4604 | STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ | ||
4605 | for (i=0; i < ST_NBR_PARTITIONS; i++) { | ||
4606 | STps = &(STp->ps[i]); | ||
4607 | STps->rw = ST_IDLE; /* FIXME - seems to be redundant... */ | ||
4608 | STps->eof = ST_NOEOF; | ||
4609 | STps->at_sm = 0; | ||
4610 | STps->last_block_valid = 0; | ||
4611 | STps->drv_block = 0; | ||
4612 | STps->drv_file = 0 ; | ||
4613 | } | ||
4614 | new_session = 1; | ||
4615 | STp->recover_count = 0; | ||
4616 | STp->abort_count = 0; | ||
4617 | } | ||
4618 | /* | ||
4619 | * if we have valid headers from before, and the drive/tape seem untouched, | ||
4620 | * open without reconfiguring and re-reading the headers | ||
4621 | */ | ||
4622 | if (!STp->buffer->syscall_result && STp->header_ok && | ||
4623 | !SRpnt->result && SRpnt->sense[0] == 0) { | ||
4624 | |||
4625 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
4626 | cmd[0] = MODE_SENSE; | ||
4627 | cmd[1] = 8; | ||
4628 | cmd[2] = VENDOR_IDENT_PAGE; | ||
4629 | cmd[4] = VENDOR_IDENT_PAGE_LENGTH + MODE_HEADER_LENGTH; | ||
4630 | |||
4631 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_FROM_DEVICE, STp->timeout, 0, 1); | ||
4632 | |||
4633 | if (STp->buffer->syscall_result || | ||
4634 | STp->buffer->b_data[MODE_HEADER_LENGTH + 2] != 'L' || | ||
4635 | STp->buffer->b_data[MODE_HEADER_LENGTH + 3] != 'I' || | ||
4636 | STp->buffer->b_data[MODE_HEADER_LENGTH + 4] != 'N' || | ||
4637 | STp->buffer->b_data[MODE_HEADER_LENGTH + 5] != '4' ) { | ||
4638 | #if DEBUG | ||
4639 | printk(OSST_DEB_MSG "%s:D: Signature was changed to %c%c%c%c\n", name, | ||
4640 | STp->buffer->b_data[MODE_HEADER_LENGTH + 2], | ||
4641 | STp->buffer->b_data[MODE_HEADER_LENGTH + 3], | ||
4642 | STp->buffer->b_data[MODE_HEADER_LENGTH + 4], | ||
4643 | STp->buffer->b_data[MODE_HEADER_LENGTH + 5]); | ||
4644 | #endif | ||
4645 | STp->header_ok = 0; | ||
4646 | } | ||
4647 | i = STp->first_frame_position; | ||
4648 | if (STp->header_ok && i == osst_get_frame_position(STp, &SRpnt)) { | ||
4649 | if (STp->door_locked == ST_UNLOCKED) { | ||
4650 | if (do_door_lock(STp, 1)) | ||
4651 | printk(KERN_INFO "%s:I: Can't lock drive door\n", name); | ||
4652 | else | ||
4653 | STp->door_locked = ST_LOCKED_AUTO; | ||
4654 | } | ||
4655 | if (!STp->frame_in_buffer) { | ||
4656 | STp->block_size = (STm->default_blksize > 0) ? | ||
4657 | STm->default_blksize : OS_DATA_SIZE; | ||
4658 | STp->buffer->buffer_bytes = STp->buffer->read_pointer = 0; | ||
4659 | } | ||
4660 | STp->buffer->buffer_blocks = OS_DATA_SIZE / STp->block_size; | ||
4661 | STp->fast_open = 1; | ||
4662 | osst_release_request(SRpnt); | ||
4663 | return 0; | ||
4664 | } | ||
4665 | #if DEBUG | ||
4666 | if (i != STp->first_frame_position) | ||
4667 | printk(OSST_DEB_MSG "%s:D: Tape position changed from %d to %d\n", | ||
4668 | name, i, STp->first_frame_position); | ||
4669 | #endif | ||
4670 | STp->header_ok = 0; | ||
4671 | } | ||
4672 | STp->fast_open = 0; | ||
4673 | |||
4674 | if ((STp->buffer)->syscall_result != 0 && /* in all error conditions except no medium */ | ||
4675 | (SRpnt->sense[2] != 2 || SRpnt->sense[12] != 0x3A) ) { | ||
4676 | |||
4677 | memset(cmd, 0, MAX_COMMAND_SIZE); | ||
4678 | cmd[0] = MODE_SELECT; | ||
4679 | cmd[1] = 0x10; | ||
4680 | cmd[4] = 4 + MODE_HEADER_LENGTH; | ||
4681 | |||
4682 | (STp->buffer)->b_data[0] = cmd[4] - 1; | ||
4683 | (STp->buffer)->b_data[1] = 0; /* Medium Type - ignoring */ | ||
4684 | (STp->buffer)->b_data[2] = 0; /* Reserved */ | ||
4685 | (STp->buffer)->b_data[3] = 0; /* Block Descriptor Length */ | ||
4686 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 0] = 0x3f; | ||
4687 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 1] = 1; | ||
4688 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 2] = 2; | ||
4689 | (STp->buffer)->b_data[MODE_HEADER_LENGTH + 3] = 3; | ||
4690 | |||
4691 | #if DEBUG | ||
4692 | printk(OSST_DEB_MSG "%s:D: Applying soft reset\n", name); | ||
4693 | #endif | ||
4694 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, cmd[4], DMA_TO_DEVICE, STp->timeout, 0, 1); | ||
4695 | |||
4696 | STp->header_ok = 0; | ||
4697 | |||
4698 | for (i=0; i < 10; i++) { | ||
4699 | |||
4700 | memset (cmd, 0, MAX_COMMAND_SIZE); | ||
4701 | cmd[0] = TEST_UNIT_READY; | ||
4702 | |||
4703 | SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, DMA_NONE, | ||
4704 | STp->timeout, MAX_RETRIES, 1); | ||
4705 | if ((SRpnt->sense[0] & 0x70) != 0x70 || | ||
4706 | (SRpnt->sense[2] & 0x0f) == NOT_READY) | ||
4707 | break; | ||
4708 | |||
4709 | if ((SRpnt->sense[2] & 0x0f) == UNIT_ATTENTION) { | ||
4710 | int j; | ||
4711 | |||
4712 | STp->pos_unknown = 0; | ||
4713 | STp->partition = STp->new_partition = 0; | ||
4714 | if (STp->can_partitions) | ||
4715 | STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ | ||
4716 | for (j = 0; j < ST_NBR_PARTITIONS; j++) { | ||
4717 | STps = &(STp->ps[j]); | ||
4718 | STps->rw = ST_IDLE; | ||
4719 | STps->eof = ST_NOEOF; | ||
4720 | STps->at_sm = 0; | ||
4721 | STps->last_block_valid = 0; | ||
4722 | STps->drv_block = 0; | ||
4723 | STps->drv_file = 0 ; | ||
4724 | } | ||
4725 | new_session = 1; | ||
4726 | } | ||
4727 | } | ||
4728 | } | ||
4729 | |||
4730 | if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */ | ||
4731 | printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name); | ||
4732 | |||
4733 | if ((STp->buffer)->syscall_result != 0) { | ||
4734 | if ((STp->device)->scsi_level >= SCSI_2 && | ||
4735 | (SRpnt->sense[0] & 0x70) == 0x70 && | ||
4736 | (SRpnt->sense[2] & 0x0f) == NOT_READY && | ||
4737 | SRpnt->sense[12] == 0x3a) { /* Check ASC */ | ||
4738 | STp->ready = ST_NO_TAPE; | ||
4739 | } else | ||
4740 | STp->ready = ST_NOT_READY; | ||
4741 | osst_release_request(SRpnt); | ||
4742 | SRpnt = NULL; | ||
4743 | STp->density = 0; /* Clear the erroneous "residue" */ | ||
4744 | STp->write_prot = 0; | ||
4745 | STp->block_size = 0; | ||
4746 | STp->ps[0].drv_file = STp->ps[0].drv_block = (-1); | ||
4747 | STp->partition = STp->new_partition = 0; | ||
4748 | STp->door_locked = ST_UNLOCKED; | ||
4749 | return 0; | ||
4750 | } | ||
4751 | |||
4752 | osst_configure_onstream(STp, &SRpnt); | ||
4753 | |||
4754 | STp->block_size = STp->raw ? OS_FRAME_SIZE : ( | ||
4755 | (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); | ||
4756 | STp->buffer->buffer_blocks = STp->raw ? 1 : OS_DATA_SIZE / STp->block_size; | ||
4757 | STp->buffer->buffer_bytes = | ||
4758 | STp->buffer->read_pointer = | ||
4759 | STp->frame_in_buffer = 0; | ||
4760 | |||
4761 | #if DEBUG | ||
4762 | if (debugging) | ||
4763 | printk(OSST_DEB_MSG "%s:D: Block size: %d, frame size: %d, buffer size: %d (%d blocks).\n", | ||
4764 | name, STp->block_size, OS_FRAME_SIZE, (STp->buffer)->buffer_size, | ||
4765 | (STp->buffer)->buffer_blocks); | ||
4766 | #endif | ||
4767 | |||
4768 | if (STp->drv_write_prot) { | ||
4769 | STp->write_prot = 1; | ||
4770 | #if DEBUG | ||
4771 | if (debugging) | ||
4772 | printk(OSST_DEB_MSG "%s:D: Write protected\n", name); | ||
4773 | #endif | ||
4774 | if ((flags & O_ACCMODE) == O_WRONLY || (flags & O_ACCMODE) == O_RDWR) { | ||
4775 | retval = (-EROFS); | ||
4776 | goto err_out; | ||
4777 | } | ||
4778 | } | ||
4779 | |||
4780 | if (new_session) { /* Change the drive parameters for the new mode */ | ||
4781 | #if DEBUG | ||
4782 | if (debugging) | ||
4783 | printk(OSST_DEB_MSG "%s:D: New Session\n", name); | ||
4784 | #endif | ||
4785 | STp->density_changed = STp->blksize_changed = 0; | ||
4786 | STp->compression_changed = 0; | ||
4787 | } | ||
4788 | |||
4789 | /* | ||
4790 | * properly position the tape and check the ADR headers | ||
4791 | */ | ||
4792 | if (STp->door_locked == ST_UNLOCKED) { | ||
4793 | if (do_door_lock(STp, 1)) | ||
4794 | printk(KERN_INFO "%s:I: Can't lock drive door\n", name); | ||
4795 | else | ||
4796 | STp->door_locked = ST_LOCKED_AUTO; | ||
4797 | } | ||
4798 | |||
4799 | osst_analyze_headers(STp, &SRpnt); | ||
4800 | |||
4801 | osst_release_request(SRpnt); | ||
4802 | SRpnt = NULL; | ||
4803 | |||
4804 | return 0; | ||
4805 | |||
4806 | err_out: | ||
4807 | if (SRpnt != NULL) | ||
4808 | osst_release_request(SRpnt); | ||
4809 | normalize_buffer(STp->buffer); | ||
4810 | STp->header_ok = 0; | ||
4811 | STp->in_use = 0; | ||
4812 | scsi_device_put(STp->device); | ||
4813 | |||
4814 | return retval; | ||
4815 | } | ||
4816 | |||
4817 | /* BKL pushdown: spaghetti avoidance wrapper */ | ||
4818 | static int os_scsi_tape_open(struct inode * inode, struct file * filp) | ||
4819 | { | ||
4820 | int ret; | ||
4821 | |||
4822 | mutex_lock(&osst_int_mutex); | ||
4823 | ret = __os_scsi_tape_open(inode, filp); | ||
4824 | mutex_unlock(&osst_int_mutex); | ||
4825 | return ret; | ||
4826 | } | ||
4827 | |||
4828 | |||
4829 | |||
4830 | /* Flush the tape buffer before close */ | ||
4831 | static int os_scsi_tape_flush(struct file * filp, fl_owner_t id) | ||
4832 | { | ||
4833 | int result = 0, result2; | ||
4834 | struct osst_tape * STp = filp->private_data; | ||
4835 | struct st_modedef * STm = &(STp->modes[STp->current_mode]); | ||
4836 | struct st_partstat * STps = &(STp->ps[STp->partition]); | ||
4837 | struct osst_request * SRpnt = NULL; | ||
4838 | char * name = tape_name(STp); | ||
4839 | |||
4840 | if (file_count(filp) > 1) | ||
4841 | return 0; | ||
4842 | |||
4843 | if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) { | ||
4844 | STp->write_type = OS_WRITE_DATA; | ||
4845 | result = osst_flush_write_buffer(STp, &SRpnt); | ||
4846 | if (result != 0 && result != (-ENOSPC)) | ||
4847 | goto out; | ||
4848 | } | ||
4849 | if ( STps->rw >= ST_WRITING && !STp->pos_unknown) { | ||
4850 | |||
4851 | #if DEBUG | ||
4852 | if (debugging) { | ||
4853 | printk(OSST_DEB_MSG "%s:D: File length %ld bytes.\n", | ||
4854 | name, (long)(filp->f_pos)); | ||
4855 | printk(OSST_DEB_MSG "%s:D: Async write waits %d, finished %d.\n", | ||
4856 | name, STp->nbr_waits, STp->nbr_finished); | ||
4857 | } | ||
4858 | #endif | ||
4859 | result = osst_write_trailer(STp, &SRpnt, !(STp->rew_at_close)); | ||
4860 | #if DEBUG | ||
4861 | if (debugging) | ||
4862 | printk(OSST_DEB_MSG "%s:D: Buffer flushed, %d EOF(s) written\n", | ||
4863 | name, 1+STp->two_fm); | ||
4864 | #endif | ||
4865 | } | ||
4866 | else if (!STp->rew_at_close) { | ||
4867 | STps = &(STp->ps[STp->partition]); | ||
4868 | if (!STm->sysv || STps->rw != ST_READING) { | ||
4869 | if (STp->can_bsr) | ||
4870 | result = osst_flush_buffer(STp, &SRpnt, 0); /* this is the default path */ | ||
4871 | else if (STps->eof == ST_FM_HIT) { | ||
4872 | result = cross_eof(STp, &SRpnt, 0); | ||
4873 | if (result) { | ||
4874 | if (STps->drv_file >= 0) | ||
4875 | STps->drv_file++; | ||
4876 | STps->drv_block = 0; | ||
4877 | STps->eof = ST_FM; | ||
4878 | } | ||
4879 | else | ||
4880 | STps->eof = ST_NOEOF; | ||
4881 | } | ||
4882 | } | ||
4883 | else if ((STps->eof == ST_NOEOF && | ||
4884 | !(result = cross_eof(STp, &SRpnt, 1))) || | ||
4885 | STps->eof == ST_FM_HIT) { | ||
4886 | if (STps->drv_file >= 0) | ||
4887 | STps->drv_file++; | ||
4888 | STps->drv_block = 0; | ||
4889 | STps->eof = ST_FM; | ||
4890 | } | ||
4891 | } | ||
4892 | |||
4893 | out: | ||
4894 | if (STp->rew_at_close) { | ||
4895 | result2 = osst_position_tape_and_confirm(STp, &SRpnt, STp->first_data_ppos); | ||
4896 | STps->drv_file = STps->drv_block = STp->frame_seq_number = STp->logical_blk_num = 0; | ||
4897 | if (result == 0 && result2 < 0) | ||
4898 | result = result2; | ||
4899 | } | ||
4900 | if (SRpnt) osst_release_request(SRpnt); | ||
4901 | |||
4902 | if (STp->abort_count || STp->recover_count) { | ||
4903 | printk(KERN_INFO "%s:I:", name); | ||
4904 | if (STp->abort_count) | ||
4905 | printk(" %d unrecovered errors", STp->abort_count); | ||
4906 | if (STp->recover_count) | ||
4907 | printk(" %d recovered errors", STp->recover_count); | ||
4908 | if (STp->write_count) | ||
4909 | printk(" in %d frames written", STp->write_count); | ||
4910 | if (STp->read_count) | ||
4911 | printk(" in %d frames read", STp->read_count); | ||
4912 | printk("\n"); | ||
4913 | STp->recover_count = 0; | ||
4914 | STp->abort_count = 0; | ||
4915 | } | ||
4916 | STp->write_count = 0; | ||
4917 | STp->read_count = 0; | ||
4918 | |||
4919 | return result; | ||
4920 | } | ||
4921 | |||
4922 | |||
4923 | /* Close the device and release it */ | ||
4924 | static int os_scsi_tape_close(struct inode * inode, struct file * filp) | ||
4925 | { | ||
4926 | int result = 0; | ||
4927 | struct osst_tape * STp = filp->private_data; | ||
4928 | |||
4929 | if (STp->door_locked == ST_LOCKED_AUTO) | ||
4930 | do_door_lock(STp, 0); | ||
4931 | |||
4932 | if (STp->raw) | ||
4933 | STp->header_ok = 0; | ||
4934 | |||
4935 | normalize_buffer(STp->buffer); | ||
4936 | write_lock(&os_scsi_tapes_lock); | ||
4937 | STp->in_use = 0; | ||
4938 | write_unlock(&os_scsi_tapes_lock); | ||
4939 | |||
4940 | scsi_device_put(STp->device); | ||
4941 | |||
4942 | return result; | ||
4943 | } | ||
4944 | |||
4945 | |||
4946 | /* The ioctl command */ | ||
4947 | static long osst_ioctl(struct file * file, | ||
4948 | unsigned int cmd_in, unsigned long arg) | ||
4949 | { | ||
4950 | int i, cmd_nr, cmd_type, blk, retval = 0; | ||
4951 | struct st_modedef * STm; | ||
4952 | struct st_partstat * STps; | ||
4953 | struct osst_request * SRpnt = NULL; | ||
4954 | struct osst_tape * STp = file->private_data; | ||
4955 | char * name = tape_name(STp); | ||
4956 | void __user * p = (void __user *)arg; | ||
4957 | |||
4958 | mutex_lock(&osst_int_mutex); | ||
4959 | if (mutex_lock_interruptible(&STp->lock)) { | ||
4960 | mutex_unlock(&osst_int_mutex); | ||
4961 | return -ERESTARTSYS; | ||
4962 | } | ||
4963 | |||
4964 | #if DEBUG | ||
4965 | if (debugging && !STp->in_use) { | ||
4966 | printk(OSST_DEB_MSG "%s:D: Incorrect device.\n", name); | ||
4967 | retval = (-EIO); | ||
4968 | goto out; | ||
4969 | } | ||
4970 | #endif | ||
4971 | STm = &(STp->modes[STp->current_mode]); | ||
4972 | STps = &(STp->ps[STp->partition]); | ||
4973 | |||
4974 | /* | ||
4975 | * If we are in the middle of error recovery, don't let anyone | ||
4976 | * else try and use this device. Also, if error recovery fails, it | ||
4977 | * may try and take the device offline, in which case all further | ||
4978 | * access to the device is prohibited. | ||
4979 | */ | ||
4980 | retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in, | ||
4981 | file->f_flags & O_NDELAY); | ||
4982 | if (retval) | ||
4983 | goto out; | ||
4984 | |||
4985 | cmd_type = _IOC_TYPE(cmd_in); | ||
4986 | cmd_nr = _IOC_NR(cmd_in); | ||
4987 | #if DEBUG | ||
4988 | printk(OSST_DEB_MSG "%s:D: Ioctl %d,%d in %s mode\n", name, | ||
4989 | cmd_type, cmd_nr, STp->raw?"raw":"normal"); | ||
4990 | #endif | ||
4991 | if (cmd_type == _IOC_TYPE(MTIOCTOP) && cmd_nr == _IOC_NR(MTIOCTOP)) { | ||
4992 | struct mtop mtc; | ||
4993 | int auto_weof = 0; | ||
4994 | |||
4995 | if (_IOC_SIZE(cmd_in) != sizeof(mtc)) { | ||
4996 | retval = (-EINVAL); | ||
4997 | goto out; | ||
4998 | } | ||
4999 | |||
5000 | i = copy_from_user((char *) &mtc, p, sizeof(struct mtop)); | ||
5001 | if (i) { | ||
5002 | retval = (-EFAULT); | ||
5003 | goto out; | ||
5004 | } | ||
5005 | |||
5006 | if (mtc.mt_op == MTSETDRVBUFFER && !capable(CAP_SYS_ADMIN)) { | ||
5007 | printk(KERN_WARNING "%s:W: MTSETDRVBUFFER only allowed for root.\n", name); | ||
5008 | retval = (-EPERM); | ||
5009 | goto out; | ||
5010 | } | ||
5011 | |||
5012 | if (!STm->defined && (mtc.mt_op != MTSETDRVBUFFER && (mtc.mt_count & MT_ST_OPTIONS) == 0)) { | ||
5013 | retval = (-ENXIO); | ||
5014 | goto out; | ||
5015 | } | ||
5016 | |||
5017 | if (!STp->pos_unknown) { | ||
5018 | |||
5019 | if (STps->eof == ST_FM_HIT) { | ||
5020 | if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { | ||
5021 | mtc.mt_count -= 1; | ||
5022 | if (STps->drv_file >= 0) | ||
5023 | STps->drv_file += 1; | ||
5024 | } | ||
5025 | else if (mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM) { | ||
5026 | mtc.mt_count += 1; | ||
5027 | if (STps->drv_file >= 0) | ||
5028 | STps->drv_file += 1; | ||
5029 | } | ||
5030 | } | ||
5031 | |||
5032 | if (mtc.mt_op == MTSEEK) { | ||
5033 | /* Old position must be restored if partition will be changed */ | ||
5034 | i = !STp->can_partitions || (STp->new_partition != STp->partition); | ||
5035 | } | ||
5036 | else { | ||
5037 | i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || | ||
5038 | mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM || | ||
5039 | mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD || | ||
5040 | mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM || | ||
5041 | mtc.mt_op == MTBSF || mtc.mt_op == MTBSFM || | ||
5042 | mtc.mt_op == MTCOMPRESSION; | ||
5043 | } | ||
5044 | i = osst_flush_buffer(STp, &SRpnt, i); | ||
5045 | if (i < 0) { | ||
5046 | retval = i; | ||
5047 | goto out; | ||
5048 | } | ||
5049 | } | ||
5050 | else { | ||
5051 | /* | ||
5052 | * If there was a bus reset, block further access | ||
5053 | * to this device. If the user wants to rewind the tape, | ||
5054 | * then reset the flag and allow access again. | ||
5055 | */ | ||
5056 | if(mtc.mt_op != MTREW && | ||
5057 | mtc.mt_op != MTOFFL && | ||
5058 | mtc.mt_op != MTRETEN && | ||
5059 | mtc.mt_op != MTERASE && | ||
5060 | mtc.mt_op != MTSEEK && | ||
5061 | mtc.mt_op != MTEOM) { | ||
5062 | retval = (-EIO); | ||
5063 | goto out; | ||
5064 | } | ||
5065 | reset_state(STp); | ||
5066 | /* remove this when the midlevel properly clears was_reset */ | ||
5067 | STp->device->was_reset = 0; | ||
5068 | } | ||
5069 | |||
5070 | if (mtc.mt_op != MTCOMPRESSION && mtc.mt_op != MTLOCK && | ||
5071 | mtc.mt_op != MTNOP && mtc.mt_op != MTSETBLK && | ||
5072 | mtc.mt_op != MTSETDENSITY && mtc.mt_op != MTSETDRVBUFFER && | ||
5073 | mtc.mt_op != MTMKPART && mtc.mt_op != MTSETPART && | ||
5074 | mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM ) { | ||
5075 | |||
5076 | /* | ||
5077 | * The user tells us to move to another position on the tape. | ||
5078 | * If we were appending to the tape content, that would leave | ||
5079 | * the tape without proper end, in that case write EOD and | ||
5080 | * update the header to reflect its position. | ||
5081 | */ | ||
5082 | #if DEBUG | ||
5083 | printk(KERN_WARNING "%s:D: auto_weod %s at ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", name, | ||
5084 | STps->rw >= ST_WRITING ? "write" : STps->rw == ST_READING ? "read" : "idle", | ||
5085 | STp->first_frame_position, STp->eod_frame_ppos, STp->frame_seq_number, | ||
5086 | STp->logical_blk_num, STps->drv_file, STps->drv_block ); | ||
5087 | #endif | ||
5088 | if (STps->rw >= ST_WRITING && STp->first_frame_position >= STp->eod_frame_ppos) { | ||
5089 | auto_weof = ((STp->write_type != OS_WRITE_NEW_MARK) && | ||
5090 | !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); | ||
5091 | i = osst_write_trailer(STp, &SRpnt, | ||
5092 | !(mtc.mt_op == MTREW || mtc.mt_op == MTOFFL)); | ||
5093 | #if DEBUG | ||
5094 | printk(KERN_WARNING "%s:D: post trailer xeof=%d,ffp=%d,efp=%d,fsn=%d,lbn=%d,fn=%d,bn=%d\n", | ||
5095 | name, auto_weof, STp->first_frame_position, STp->eod_frame_ppos, | ||
5096 | STp->frame_seq_number, STp->logical_blk_num, STps->drv_file, STps->drv_block ); | ||
5097 | #endif | ||
5098 | if (i < 0) { | ||
5099 | retval = i; | ||
5100 | goto out; | ||
5101 | } | ||
5102 | } | ||
5103 | STps->rw = ST_IDLE; | ||
5104 | } | ||
5105 | |||
5106 | if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) | ||
5107 | do_door_lock(STp, 0); /* Ignore result! */ | ||
5108 | |||
5109 | if (mtc.mt_op == MTSETDRVBUFFER && | ||
5110 | (mtc.mt_count & MT_ST_OPTIONS) != 0) { | ||
5111 | retval = osst_set_options(STp, mtc.mt_count); | ||
5112 | goto out; | ||
5113 | } | ||
5114 | |||
5115 | if (mtc.mt_op == MTSETPART) { | ||
5116 | if (mtc.mt_count >= STp->nbr_partitions) | ||
5117 | retval = -EINVAL; | ||
5118 | else { | ||
5119 | STp->new_partition = mtc.mt_count; | ||
5120 | retval = 0; | ||
5121 | } | ||
5122 | goto out; | ||
5123 | } | ||
5124 | |||
5125 | if (mtc.mt_op == MTMKPART) { | ||
5126 | if (!STp->can_partitions) { | ||
5127 | retval = (-EINVAL); | ||
5128 | goto out; | ||
5129 | } | ||
5130 | if ((i = osst_int_ioctl(STp, &SRpnt, MTREW, 0)) < 0 /*|| | ||
5131 | (i = partition_tape(inode, mtc.mt_count)) < 0*/) { | ||
5132 | retval = i; | ||
5133 | goto out; | ||
5134 | } | ||
5135 | for (i=0; i < ST_NBR_PARTITIONS; i++) { | ||
5136 | STp->ps[i].rw = ST_IDLE; | ||
5137 | STp->ps[i].at_sm = 0; | ||
5138 | STp->ps[i].last_block_valid = 0; | ||
5139 | } | ||
5140 | STp->partition = STp->new_partition = 0; | ||
5141 | STp->nbr_partitions = 1; /* Bad guess ?-) */ | ||
5142 | STps->drv_block = STps->drv_file = 0; | ||
5143 | retval = 0; | ||
5144 | goto out; | ||
5145 | } | ||
5146 | |||
5147 | if (mtc.mt_op == MTSEEK) { | ||
5148 | if (STp->raw) | ||
5149 | i = osst_set_frame_position(STp, &SRpnt, mtc.mt_count, 0); | ||
5150 | else | ||
5151 | i = osst_seek_sector(STp, &SRpnt, mtc.mt_count); | ||
5152 | if (!STp->can_partitions) | ||
5153 | STp->ps[0].rw = ST_IDLE; | ||
5154 | retval = i; | ||
5155 | goto out; | ||
5156 | } | ||
5157 | |||
5158 | if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) { | ||
5159 | retval = do_door_lock(STp, (mtc.mt_op == MTLOCK)); | ||
5160 | goto out; | ||
5161 | } | ||
5162 | |||
5163 | if (auto_weof) | ||
5164 | cross_eof(STp, &SRpnt, 0); | ||
5165 | |||
5166 | if (mtc.mt_op == MTCOMPRESSION) | ||
5167 | retval = -EINVAL; /* OnStream drives don't have compression hardware */ | ||
5168 | else | ||
5169 | /* MTBSF MTBSFM MTBSR MTBSS MTEOM MTERASE MTFSF MTFSFB MTFSR MTFSS | ||
5170 | * MTLOAD MTOFFL MTRESET MTRETEN MTREW MTUNLOAD MTWEOF MTWSM */ | ||
5171 | retval = osst_int_ioctl(STp, &SRpnt, mtc.mt_op, mtc.mt_count); | ||
5172 | goto out; | ||
5173 | } | ||
5174 | |||
5175 | if (!STm->defined) { | ||
5176 | retval = (-ENXIO); | ||
5177 | goto out; | ||
5178 | } | ||
5179 | |||
5180 | if ((i = osst_flush_buffer(STp, &SRpnt, 0)) < 0) { | ||
5181 | retval = i; | ||
5182 | goto out; | ||
5183 | } | ||
5184 | |||
5185 | if (cmd_type == _IOC_TYPE(MTIOCGET) && cmd_nr == _IOC_NR(MTIOCGET)) { | ||
5186 | struct mtget mt_status; | ||
5187 | |||
5188 | if (_IOC_SIZE(cmd_in) != sizeof(struct mtget)) { | ||
5189 | retval = (-EINVAL); | ||
5190 | goto out; | ||
5191 | } | ||
5192 | |||
5193 | mt_status.mt_type = MT_ISONSTREAM_SC; | ||
5194 | mt_status.mt_erreg = STp->recover_erreg << MT_ST_SOFTERR_SHIFT; | ||
5195 | mt_status.mt_dsreg = | ||
5196 | ((STp->block_size << MT_ST_BLKSIZE_SHIFT) & MT_ST_BLKSIZE_MASK) | | ||
5197 | ((STp->density << MT_ST_DENSITY_SHIFT) & MT_ST_DENSITY_MASK); | ||
5198 | mt_status.mt_blkno = STps->drv_block; | ||
5199 | mt_status.mt_fileno = STps->drv_file; | ||
5200 | if (STp->block_size != 0) { | ||
5201 | if (STps->rw == ST_WRITING) | ||
5202 | mt_status.mt_blkno += (STp->buffer)->buffer_bytes / STp->block_size; | ||
5203 | else if (STps->rw == ST_READING) | ||
5204 | mt_status.mt_blkno -= ((STp->buffer)->buffer_bytes + | ||
5205 | STp->block_size - 1) / STp->block_size; | ||
5206 | } | ||
5207 | |||
5208 | mt_status.mt_gstat = 0; | ||
5209 | if (STp->drv_write_prot) | ||
5210 | mt_status.mt_gstat |= GMT_WR_PROT(0xffffffff); | ||
5211 | if (mt_status.mt_blkno == 0) { | ||
5212 | if (mt_status.mt_fileno == 0) | ||
5213 | mt_status.mt_gstat |= GMT_BOT(0xffffffff); | ||
5214 | else | ||
5215 | mt_status.mt_gstat |= GMT_EOF(0xffffffff); | ||
5216 | } | ||
5217 | mt_status.mt_resid = STp->partition; | ||
5218 | if (STps->eof == ST_EOM_OK || STps->eof == ST_EOM_ERROR) | ||
5219 | mt_status.mt_gstat |= GMT_EOT(0xffffffff); | ||
5220 | else if (STps->eof >= ST_EOM_OK) | ||
5221 | mt_status.mt_gstat |= GMT_EOD(0xffffffff); | ||
5222 | if (STp->density == 1) | ||
5223 | mt_status.mt_gstat |= GMT_D_800(0xffffffff); | ||
5224 | else if (STp->density == 2) | ||
5225 | mt_status.mt_gstat |= GMT_D_1600(0xffffffff); | ||
5226 | else if (STp->density == 3) | ||
5227 | mt_status.mt_gstat |= GMT_D_6250(0xffffffff); | ||
5228 | if (STp->ready == ST_READY) | ||
5229 | mt_status.mt_gstat |= GMT_ONLINE(0xffffffff); | ||
5230 | if (STp->ready == ST_NO_TAPE) | ||
5231 | mt_status.mt_gstat |= GMT_DR_OPEN(0xffffffff); | ||
5232 | if (STps->at_sm) | ||
5233 | mt_status.mt_gstat |= GMT_SM(0xffffffff); | ||
5234 | if (STm->do_async_writes || (STm->do_buffer_writes && STp->block_size != 0) || | ||
5235 | STp->drv_buffer != 0) | ||
5236 | mt_status.mt_gstat |= GMT_IM_REP_EN(0xffffffff); | ||
5237 | |||
5238 | i = copy_to_user(p, &mt_status, sizeof(struct mtget)); | ||
5239 | if (i) { | ||
5240 | retval = (-EFAULT); | ||
5241 | goto out; | ||
5242 | } | ||
5243 | |||
5244 | STp->recover_erreg = 0; /* Clear after read */ | ||
5245 | retval = 0; | ||
5246 | goto out; | ||
5247 | } /* End of MTIOCGET */ | ||
5248 | |||
5249 | if (cmd_type == _IOC_TYPE(MTIOCPOS) && cmd_nr == _IOC_NR(MTIOCPOS)) { | ||
5250 | struct mtpos mt_pos; | ||
5251 | |||
5252 | if (_IOC_SIZE(cmd_in) != sizeof(struct mtpos)) { | ||
5253 | retval = (-EINVAL); | ||
5254 | goto out; | ||
5255 | } | ||
5256 | if (STp->raw) | ||
5257 | blk = osst_get_frame_position(STp, &SRpnt); | ||
5258 | else | ||
5259 | blk = osst_get_sector(STp, &SRpnt); | ||
5260 | if (blk < 0) { | ||
5261 | retval = blk; | ||
5262 | goto out; | ||
5263 | } | ||
5264 | mt_pos.mt_blkno = blk; | ||
5265 | i = copy_to_user(p, &mt_pos, sizeof(struct mtpos)); | ||
5266 | if (i) | ||
5267 | retval = -EFAULT; | ||
5268 | goto out; | ||
5269 | } | ||
5270 | if (SRpnt) osst_release_request(SRpnt); | ||
5271 | |||
5272 | mutex_unlock(&STp->lock); | ||
5273 | |||
5274 | retval = scsi_ioctl(STp->device, cmd_in, p); | ||
5275 | mutex_unlock(&osst_int_mutex); | ||
5276 | return retval; | ||
5277 | |||
5278 | out: | ||
5279 | if (SRpnt) osst_release_request(SRpnt); | ||
5280 | |||
5281 | mutex_unlock(&STp->lock); | ||
5282 | mutex_unlock(&osst_int_mutex); | ||
5283 | |||
5284 | return retval; | ||
5285 | } | ||
5286 | |||
5287 | #ifdef CONFIG_COMPAT | ||
5288 | static long osst_compat_ioctl(struct file * file, unsigned int cmd_in, unsigned long arg) | ||
5289 | { | ||
5290 | struct osst_tape *STp = file->private_data; | ||
5291 | struct scsi_device *sdev = STp->device; | ||
5292 | int ret = -ENOIOCTLCMD; | ||
5293 | if (sdev->host->hostt->compat_ioctl) { | ||
5294 | |||
5295 | ret = sdev->host->hostt->compat_ioctl(sdev, cmd_in, (void __user *)arg); | ||
5296 | |||
5297 | } | ||
5298 | return ret; | ||
5299 | } | ||
5300 | #endif | ||
5301 | |||
5302 | |||
5303 | |||
5304 | /* Memory handling routines */ | ||
5305 | |||
5306 | /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */ | ||
5307 | static struct osst_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg ) | ||
5308 | { | ||
5309 | int i; | ||
5310 | gfp_t priority; | ||
5311 | struct osst_buffer *tb; | ||
5312 | |||
5313 | if (from_initialization) | ||
5314 | priority = GFP_ATOMIC; | ||
5315 | else | ||
5316 | priority = GFP_KERNEL; | ||
5317 | |||
5318 | i = sizeof(struct osst_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); | ||
5319 | tb = kzalloc(i, priority); | ||
5320 | if (!tb) { | ||
5321 | printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n"); | ||
5322 | return NULL; | ||
5323 | } | ||
5324 | |||
5325 | tb->sg_segs = tb->orig_sg_segs = 0; | ||
5326 | tb->use_sg = max_sg; | ||
5327 | tb->in_use = 1; | ||
5328 | tb->dma = need_dma; | ||
5329 | tb->buffer_size = 0; | ||
5330 | #if DEBUG | ||
5331 | if (debugging) | ||
5332 | printk(OSST_DEB_MSG | ||
5333 | "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n", | ||
5334 | i, max_sg, need_dma); | ||
5335 | #endif | ||
5336 | return tb; | ||
5337 | } | ||
5338 | |||
5339 | /* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */ | ||
5340 | static int enlarge_buffer(struct osst_buffer *STbuffer, int need_dma) | ||
5341 | { | ||
5342 | int segs, nbr, max_segs, b_size, order, got; | ||
5343 | gfp_t priority; | ||
5344 | |||
5345 | if (STbuffer->buffer_size >= OS_FRAME_SIZE) | ||
5346 | return 1; | ||
5347 | |||
5348 | if (STbuffer->sg_segs) { | ||
5349 | printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n"); | ||
5350 | normalize_buffer(STbuffer); | ||
5351 | } | ||
5352 | /* See how many segments we can use -- need at least two */ | ||
5353 | nbr = max_segs = STbuffer->use_sg; | ||
5354 | if (nbr <= 2) | ||
5355 | return 0; | ||
5356 | |||
5357 | priority = GFP_KERNEL /* | __GFP_NOWARN */; | ||
5358 | if (need_dma) | ||
5359 | priority |= GFP_DMA; | ||
5360 | |||
5361 | /* Try to allocate the first segment up to OS_DATA_SIZE and the others | ||
5362 | big enough to reach the goal (code assumes no segments in place) */ | ||
5363 | for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) { | ||
5364 | struct page *page = alloc_pages(priority, order); | ||
5365 | |||
5366 | STbuffer->sg[0].offset = 0; | ||
5367 | if (page != NULL) { | ||
5368 | sg_set_page(&STbuffer->sg[0], page, b_size, 0); | ||
5369 | STbuffer->b_data = page_address(page); | ||
5370 | break; | ||
5371 | } | ||
5372 | } | ||
5373 | if (sg_page(&STbuffer->sg[0]) == NULL) { | ||
5374 | printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n"); | ||
5375 | return 0; | ||
5376 | } | ||
5377 | /* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */ | ||
5378 | for (segs=STbuffer->sg_segs=1, got=b_size; | ||
5379 | segs < max_segs && got < OS_FRAME_SIZE; ) { | ||
5380 | struct page *page = alloc_pages(priority, (OS_FRAME_SIZE - got <= PAGE_SIZE) ? 0 : order); | ||
5381 | STbuffer->sg[segs].offset = 0; | ||
5382 | if (page == NULL) { | ||
5383 | printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", | ||
5384 | OS_FRAME_SIZE); | ||
5385 | #if DEBUG | ||
5386 | STbuffer->buffer_size = got; | ||
5387 | #endif | ||
5388 | normalize_buffer(STbuffer); | ||
5389 | return 0; | ||
5390 | } | ||
5391 | sg_set_page(&STbuffer->sg[segs], page, (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size, 0); | ||
5392 | got += STbuffer->sg[segs].length; | ||
5393 | STbuffer->buffer_size = got; | ||
5394 | STbuffer->sg_segs = ++segs; | ||
5395 | } | ||
5396 | #if DEBUG | ||
5397 | if (debugging) { | ||
5398 | printk(OSST_DEB_MSG | ||
5399 | "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n", | ||
5400 | got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data); | ||
5401 | printk(OSST_DEB_MSG | ||
5402 | "osst :D: segment sizes: first %d at %p, last %d bytes at %p.\n", | ||
5403 | STbuffer->sg[0].length, page_address(STbuffer->sg[0].page), | ||
5404 | STbuffer->sg[segs-1].length, page_address(STbuffer->sg[segs-1].page)); | ||
5405 | } | ||
5406 | #endif | ||
5407 | |||
5408 | return 1; | ||
5409 | } | ||
5410 | |||
5411 | |||
5412 | /* Release the segments */ | ||
5413 | static void normalize_buffer(struct osst_buffer *STbuffer) | ||
5414 | { | ||
5415 | int i, order, b_size; | ||
5416 | |||
5417 | for (i=0; i < STbuffer->sg_segs; i++) { | ||
5418 | |||
5419 | for (b_size = PAGE_SIZE, order = 0; | ||
5420 | b_size < STbuffer->sg[i].length; | ||
5421 | b_size *= 2, order++); | ||
5422 | |||
5423 | __free_pages(sg_page(&STbuffer->sg[i]), order); | ||
5424 | STbuffer->buffer_size -= STbuffer->sg[i].length; | ||
5425 | } | ||
5426 | #if DEBUG | ||
5427 | if (debugging && STbuffer->orig_sg_segs < STbuffer->sg_segs) | ||
5428 | printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n", | ||
5429 | STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); | ||
5430 | #endif | ||
5431 | STbuffer->sg_segs = STbuffer->orig_sg_segs = 0; | ||
5432 | } | ||
5433 | |||
5434 | |||
5435 | /* Move data from the user buffer to the tape buffer. Returns zero (success) or | ||
5436 | negative error code. */ | ||
5437 | static int append_to_buffer(const char __user *ubp, struct osst_buffer *st_bp, int do_count) | ||
5438 | { | ||
5439 | int i, cnt, res, offset; | ||
5440 | |||
5441 | for (i=0, offset=st_bp->buffer_bytes; | ||
5442 | i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) | ||
5443 | offset -= st_bp->sg[i].length; | ||
5444 | if (i == st_bp->sg_segs) { /* Should never happen */ | ||
5445 | printk(KERN_WARNING "osst :A: Append_to_buffer offset overflow.\n"); | ||
5446 | return (-EIO); | ||
5447 | } | ||
5448 | for ( ; i < st_bp->sg_segs && do_count > 0; i++) { | ||
5449 | cnt = st_bp->sg[i].length - offset < do_count ? | ||
5450 | st_bp->sg[i].length - offset : do_count; | ||
5451 | res = copy_from_user(page_address(sg_page(&st_bp->sg[i])) + offset, ubp, cnt); | ||
5452 | if (res) | ||
5453 | return (-EFAULT); | ||
5454 | do_count -= cnt; | ||
5455 | st_bp->buffer_bytes += cnt; | ||
5456 | ubp += cnt; | ||
5457 | offset = 0; | ||
5458 | } | ||
5459 | if (do_count) { /* Should never happen */ | ||
5460 | printk(KERN_WARNING "osst :A: Append_to_buffer overflow (left %d).\n", | ||
5461 | do_count); | ||
5462 | return (-EIO); | ||
5463 | } | ||
5464 | return 0; | ||
5465 | } | ||
5466 | |||
5467 | |||
5468 | /* Move data from the tape buffer to the user buffer. Returns zero (success) or | ||
5469 | negative error code. */ | ||
5470 | static int from_buffer(struct osst_buffer *st_bp, char __user *ubp, int do_count) | ||
5471 | { | ||
5472 | int i, cnt, res, offset; | ||
5473 | |||
5474 | for (i=0, offset=st_bp->read_pointer; | ||
5475 | i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) | ||
5476 | offset -= st_bp->sg[i].length; | ||
5477 | if (i == st_bp->sg_segs) { /* Should never happen */ | ||
5478 | printk(KERN_WARNING "osst :A: From_buffer offset overflow.\n"); | ||
5479 | return (-EIO); | ||
5480 | } | ||
5481 | for ( ; i < st_bp->sg_segs && do_count > 0; i++) { | ||
5482 | cnt = st_bp->sg[i].length - offset < do_count ? | ||
5483 | st_bp->sg[i].length - offset : do_count; | ||
5484 | res = copy_to_user(ubp, page_address(sg_page(&st_bp->sg[i])) + offset, cnt); | ||
5485 | if (res) | ||
5486 | return (-EFAULT); | ||
5487 | do_count -= cnt; | ||
5488 | st_bp->buffer_bytes -= cnt; | ||
5489 | st_bp->read_pointer += cnt; | ||
5490 | ubp += cnt; | ||
5491 | offset = 0; | ||
5492 | } | ||
5493 | if (do_count) { /* Should never happen */ | ||
5494 | printk(KERN_WARNING "osst :A: From_buffer overflow (left %d).\n", do_count); | ||
5495 | return (-EIO); | ||
5496 | } | ||
5497 | return 0; | ||
5498 | } | ||
5499 | |||
5500 | /* Sets the tail of the buffer after fill point to zero. | ||
5501 | Returns zero (success) or negative error code. */ | ||
5502 | static int osst_zero_buffer_tail(struct osst_buffer *st_bp) | ||
5503 | { | ||
5504 | int i, offset, do_count, cnt; | ||
5505 | |||
5506 | for (i = 0, offset = st_bp->buffer_bytes; | ||
5507 | i < st_bp->sg_segs && offset >= st_bp->sg[i].length; i++) | ||
5508 | offset -= st_bp->sg[i].length; | ||
5509 | if (i == st_bp->sg_segs) { /* Should never happen */ | ||
5510 | printk(KERN_WARNING "osst :A: Zero_buffer offset overflow.\n"); | ||
5511 | return (-EIO); | ||
5512 | } | ||
5513 | for (do_count = OS_DATA_SIZE - st_bp->buffer_bytes; | ||
5514 | i < st_bp->sg_segs && do_count > 0; i++) { | ||
5515 | cnt = st_bp->sg[i].length - offset < do_count ? | ||
5516 | st_bp->sg[i].length - offset : do_count ; | ||
5517 | memset(page_address(sg_page(&st_bp->sg[i])) + offset, 0, cnt); | ||
5518 | do_count -= cnt; | ||
5519 | offset = 0; | ||
5520 | } | ||
5521 | if (do_count) { /* Should never happen */ | ||
5522 | printk(KERN_WARNING "osst :A: Zero_buffer overflow (left %d).\n", do_count); | ||
5523 | return (-EIO); | ||
5524 | } | ||
5525 | return 0; | ||
5526 | } | ||
5527 | |||
5528 | /* Copy a osst 32K chunk of memory into the buffer. | ||
5529 | Returns zero (success) or negative error code. */ | ||
5530 | static int osst_copy_to_buffer(struct osst_buffer *st_bp, unsigned char *ptr) | ||
5531 | { | ||
5532 | int i, cnt, do_count = OS_DATA_SIZE; | ||
5533 | |||
5534 | for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { | ||
5535 | cnt = st_bp->sg[i].length < do_count ? | ||
5536 | st_bp->sg[i].length : do_count ; | ||
5537 | memcpy(page_address(sg_page(&st_bp->sg[i])), ptr, cnt); | ||
5538 | do_count -= cnt; | ||
5539 | ptr += cnt; | ||
5540 | } | ||
5541 | if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ | ||
5542 | printk(KERN_WARNING "osst :A: Copy_to_buffer overflow (left %d at sg %d).\n", | ||
5543 | do_count, i); | ||
5544 | return (-EIO); | ||
5545 | } | ||
5546 | return 0; | ||
5547 | } | ||
5548 | |||
5549 | /* Copy a osst 32K chunk of memory from the buffer. | ||
5550 | Returns zero (success) or negative error code. */ | ||
5551 | static int osst_copy_from_buffer(struct osst_buffer *st_bp, unsigned char *ptr) | ||
5552 | { | ||
5553 | int i, cnt, do_count = OS_DATA_SIZE; | ||
5554 | |||
5555 | for (i = 0; i < st_bp->sg_segs && do_count > 0; i++) { | ||
5556 | cnt = st_bp->sg[i].length < do_count ? | ||
5557 | st_bp->sg[i].length : do_count ; | ||
5558 | memcpy(ptr, page_address(sg_page(&st_bp->sg[i])), cnt); | ||
5559 | do_count -= cnt; | ||
5560 | ptr += cnt; | ||
5561 | } | ||
5562 | if (do_count || i != st_bp->sg_segs-1) { /* Should never happen */ | ||
5563 | printk(KERN_WARNING "osst :A: Copy_from_buffer overflow (left %d at sg %d).\n", | ||
5564 | do_count, i); | ||
5565 | return (-EIO); | ||
5566 | } | ||
5567 | return 0; | ||
5568 | } | ||
5569 | |||
5570 | |||
5571 | /* Module housekeeping */ | ||
5572 | |||
5573 | static void validate_options (void) | ||
5574 | { | ||
5575 | if (max_dev > 0) | ||
5576 | osst_max_dev = max_dev; | ||
5577 | if (write_threshold_kbs > 0) | ||
5578 | osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; | ||
5579 | if (osst_write_threshold > osst_buffer_size) | ||
5580 | osst_write_threshold = osst_buffer_size; | ||
5581 | if (max_sg_segs >= OSST_FIRST_SG) | ||
5582 | osst_max_sg_segs = max_sg_segs; | ||
5583 | #if DEBUG | ||
5584 | printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, max s/g segs %d.\n", | ||
5585 | osst_max_dev, osst_write_threshold, osst_max_sg_segs); | ||
5586 | #endif | ||
5587 | } | ||
5588 | |||
5589 | #ifndef MODULE | ||
5590 | /* Set the boot options. Syntax: osst=xxx,yyy,... | ||
5591 | where xxx is write threshold in 1024 byte blocks, | ||
5592 | and yyy is number of s/g segments to use. */ | ||
5593 | static int __init osst_setup (char *str) | ||
5594 | { | ||
5595 | int i, ints[5]; | ||
5596 | char *stp; | ||
5597 | |||
5598 | stp = get_options(str, ARRAY_SIZE(ints), ints); | ||
5599 | |||
5600 | if (ints[0] > 0) { | ||
5601 | for (i = 0; i < ints[0] && i < ARRAY_SIZE(parms); i++) | ||
5602 | *parms[i].val = ints[i + 1]; | ||
5603 | } else { | ||
5604 | while (stp != NULL) { | ||
5605 | for (i = 0; i < ARRAY_SIZE(parms); i++) { | ||
5606 | int len = strlen(parms[i].name); | ||
5607 | if (!strncmp(stp, parms[i].name, len) && | ||
5608 | (*(stp + len) == ':' || *(stp + len) == '=')) { | ||
5609 | *parms[i].val = | ||
5610 | simple_strtoul(stp + len + 1, NULL, 0); | ||
5611 | break; | ||
5612 | } | ||
5613 | } | ||
5614 | if (i >= ARRAY_SIZE(parms)) | ||
5615 | printk(KERN_INFO "osst :I: Illegal parameter in '%s'\n", | ||
5616 | stp); | ||
5617 | stp = strchr(stp, ','); | ||
5618 | if (stp) | ||
5619 | stp++; | ||
5620 | } | ||
5621 | } | ||
5622 | |||
5623 | return 1; | ||
5624 | } | ||
5625 | |||
5626 | __setup("osst=", osst_setup); | ||
5627 | |||
5628 | #endif | ||
5629 | |||
5630 | static const struct file_operations osst_fops = { | ||
5631 | .owner = THIS_MODULE, | ||
5632 | .read = osst_read, | ||
5633 | .write = osst_write, | ||
5634 | .unlocked_ioctl = osst_ioctl, | ||
5635 | #ifdef CONFIG_COMPAT | ||
5636 | .compat_ioctl = osst_compat_ioctl, | ||
5637 | #endif | ||
5638 | .open = os_scsi_tape_open, | ||
5639 | .flush = os_scsi_tape_flush, | ||
5640 | .release = os_scsi_tape_close, | ||
5641 | .llseek = noop_llseek, | ||
5642 | }; | ||
5643 | |||
5644 | static int osst_supports(struct scsi_device * SDp) | ||
5645 | { | ||
5646 | struct osst_support_data { | ||
5647 | char *vendor; | ||
5648 | char *model; | ||
5649 | char *rev; | ||
5650 | char *driver_hint; /* Name of the correct driver, NULL if unknown */ | ||
5651 | }; | ||
5652 | |||
5653 | static struct osst_support_data support_list[] = { | ||
5654 | /* {"XXX", "Yy-", "", NULL}, example */ | ||
5655 | SIGS_FROM_OSST, | ||
5656 | {NULL, }}; | ||
5657 | |||
5658 | struct osst_support_data *rp; | ||
5659 | |||
5660 | /* We are willing to drive OnStream SC-x0 as well as the | ||
5661 | * * IDE, ParPort, FireWire, USB variants, if accessible by | ||
5662 | * * emulation layer (ide-scsi, usb-storage, ...) */ | ||
5663 | |||
5664 | for (rp=&(support_list[0]); rp->vendor != NULL; rp++) | ||
5665 | if (!strncmp(rp->vendor, SDp->vendor, strlen(rp->vendor)) && | ||
5666 | !strncmp(rp->model, SDp->model, strlen(rp->model)) && | ||
5667 | !strncmp(rp->rev, SDp->rev, strlen(rp->rev))) | ||
5668 | return 1; | ||
5669 | return 0; | ||
5670 | } | ||
5671 | |||
5672 | /* | ||
5673 | * sysfs support for osst driver parameter information | ||
5674 | */ | ||
5675 | |||
5676 | static ssize_t version_show(struct device_driver *ddd, char *buf) | ||
5677 | { | ||
5678 | return snprintf(buf, PAGE_SIZE, "%s\n", osst_version); | ||
5679 | } | ||
5680 | |||
5681 | static DRIVER_ATTR_RO(version); | ||
5682 | |||
5683 | static int osst_create_sysfs_files(struct device_driver *sysfs) | ||
5684 | { | ||
5685 | return driver_create_file(sysfs, &driver_attr_version); | ||
5686 | } | ||
5687 | |||
5688 | static void osst_remove_sysfs_files(struct device_driver *sysfs) | ||
5689 | { | ||
5690 | driver_remove_file(sysfs, &driver_attr_version); | ||
5691 | } | ||
5692 | |||
5693 | /* | ||
5694 | * sysfs support for accessing ADR header information | ||
5695 | */ | ||
5696 | |||
5697 | static ssize_t osst_adr_rev_show(struct device *dev, | ||
5698 | struct device_attribute *attr, char *buf) | ||
5699 | { | ||
5700 | struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); | ||
5701 | ssize_t l = 0; | ||
5702 | |||
5703 | if (STp && STp->header_ok && STp->linux_media) | ||
5704 | l = snprintf(buf, PAGE_SIZE, "%d.%d\n", STp->header_cache->major_rev, STp->header_cache->minor_rev); | ||
5705 | return l; | ||
5706 | } | ||
5707 | |||
5708 | DEVICE_ATTR(ADR_rev, S_IRUGO, osst_adr_rev_show, NULL); | ||
5709 | |||
5710 | static ssize_t osst_linux_media_version_show(struct device *dev, | ||
5711 | struct device_attribute *attr, | ||
5712 | char *buf) | ||
5713 | { | ||
5714 | struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); | ||
5715 | ssize_t l = 0; | ||
5716 | |||
5717 | if (STp && STp->header_ok && STp->linux_media) | ||
5718 | l = snprintf(buf, PAGE_SIZE, "LIN%d\n", STp->linux_media_version); | ||
5719 | return l; | ||
5720 | } | ||
5721 | |||
5722 | DEVICE_ATTR(media_version, S_IRUGO, osst_linux_media_version_show, NULL); | ||
5723 | |||
5724 | static ssize_t osst_capacity_show(struct device *dev, | ||
5725 | struct device_attribute *attr, char *buf) | ||
5726 | { | ||
5727 | struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); | ||
5728 | ssize_t l = 0; | ||
5729 | |||
5730 | if (STp && STp->header_ok && STp->linux_media) | ||
5731 | l = snprintf(buf, PAGE_SIZE, "%d\n", STp->capacity); | ||
5732 | return l; | ||
5733 | } | ||
5734 | |||
5735 | DEVICE_ATTR(capacity, S_IRUGO, osst_capacity_show, NULL); | ||
5736 | |||
5737 | static ssize_t osst_first_data_ppos_show(struct device *dev, | ||
5738 | struct device_attribute *attr, | ||
5739 | char *buf) | ||
5740 | { | ||
5741 | struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); | ||
5742 | ssize_t l = 0; | ||
5743 | |||
5744 | if (STp && STp->header_ok && STp->linux_media) | ||
5745 | l = snprintf(buf, PAGE_SIZE, "%d\n", STp->first_data_ppos); | ||
5746 | return l; | ||
5747 | } | ||
5748 | |||
5749 | DEVICE_ATTR(BOT_frame, S_IRUGO, osst_first_data_ppos_show, NULL); | ||
5750 | |||
5751 | static ssize_t osst_eod_frame_ppos_show(struct device *dev, | ||
5752 | struct device_attribute *attr, | ||
5753 | char *buf) | ||
5754 | { | ||
5755 | struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); | ||
5756 | ssize_t l = 0; | ||
5757 | |||
5758 | if (STp && STp->header_ok && STp->linux_media) | ||
5759 | l = snprintf(buf, PAGE_SIZE, "%d\n", STp->eod_frame_ppos); | ||
5760 | return l; | ||
5761 | } | ||
5762 | |||
5763 | DEVICE_ATTR(EOD_frame, S_IRUGO, osst_eod_frame_ppos_show, NULL); | ||
5764 | |||
5765 | static ssize_t osst_filemark_cnt_show(struct device *dev, | ||
5766 | struct device_attribute *attr, char *buf) | ||
5767 | { | ||
5768 | struct osst_tape * STp = (struct osst_tape *) dev_get_drvdata (dev); | ||
5769 | ssize_t l = 0; | ||
5770 | |||
5771 | if (STp && STp->header_ok && STp->linux_media) | ||
5772 | l = snprintf(buf, PAGE_SIZE, "%d\n", STp->filemark_cnt); | ||
5773 | return l; | ||
5774 | } | ||
5775 | |||
5776 | DEVICE_ATTR(file_count, S_IRUGO, osst_filemark_cnt_show, NULL); | ||
5777 | |||
5778 | static struct class *osst_sysfs_class; | ||
5779 | |||
5780 | static int osst_sysfs_init(void) | ||
5781 | { | ||
5782 | osst_sysfs_class = class_create(THIS_MODULE, "onstream_tape"); | ||
5783 | if (IS_ERR(osst_sysfs_class)) { | ||
5784 | printk(KERN_ERR "osst :W: Unable to register sysfs class\n"); | ||
5785 | return PTR_ERR(osst_sysfs_class); | ||
5786 | } | ||
5787 | |||
5788 | return 0; | ||
5789 | } | ||
5790 | |||
5791 | static void osst_sysfs_destroy(dev_t dev) | ||
5792 | { | ||
5793 | device_destroy(osst_sysfs_class, dev); | ||
5794 | } | ||
5795 | |||
5796 | static int osst_sysfs_add(dev_t dev, struct device *device, struct osst_tape * STp, char * name) | ||
5797 | { | ||
5798 | struct device *osst_member; | ||
5799 | int err; | ||
5800 | |||
5801 | osst_member = device_create(osst_sysfs_class, device, dev, STp, | ||
5802 | "%s", name); | ||
5803 | if (IS_ERR(osst_member)) { | ||
5804 | printk(KERN_WARNING "osst :W: Unable to add sysfs class member %s\n", name); | ||
5805 | return PTR_ERR(osst_member); | ||
5806 | } | ||
5807 | |||
5808 | err = device_create_file(osst_member, &dev_attr_ADR_rev); | ||
5809 | if (err) | ||
5810 | goto err_out; | ||
5811 | err = device_create_file(osst_member, &dev_attr_media_version); | ||
5812 | if (err) | ||
5813 | goto err_out; | ||
5814 | err = device_create_file(osst_member, &dev_attr_capacity); | ||
5815 | if (err) | ||
5816 | goto err_out; | ||
5817 | err = device_create_file(osst_member, &dev_attr_BOT_frame); | ||
5818 | if (err) | ||
5819 | goto err_out; | ||
5820 | err = device_create_file(osst_member, &dev_attr_EOD_frame); | ||
5821 | if (err) | ||
5822 | goto err_out; | ||
5823 | err = device_create_file(osst_member, &dev_attr_file_count); | ||
5824 | if (err) | ||
5825 | goto err_out; | ||
5826 | |||
5827 | return 0; | ||
5828 | |||
5829 | err_out: | ||
5830 | osst_sysfs_destroy(dev); | ||
5831 | return err; | ||
5832 | } | ||
5833 | |||
5834 | static void osst_sysfs_cleanup(void) | ||
5835 | { | ||
5836 | class_destroy(osst_sysfs_class); | ||
5837 | } | ||
5838 | |||
5839 | /* | ||
5840 | * osst startup / cleanup code | ||
5841 | */ | ||
5842 | |||
5843 | static int osst_probe(struct device *dev) | ||
5844 | { | ||
5845 | struct scsi_device * SDp = to_scsi_device(dev); | ||
5846 | struct osst_tape * tpnt; | ||
5847 | struct st_modedef * STm; | ||
5848 | struct st_partstat * STps; | ||
5849 | struct osst_buffer * buffer; | ||
5850 | struct gendisk * drive; | ||
5851 | int i, dev_num, err = -ENODEV; | ||
5852 | |||
5853 | if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) | ||
5854 | return -ENODEV; | ||
5855 | |||
5856 | drive = alloc_disk(1); | ||
5857 | if (!drive) { | ||
5858 | printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n"); | ||
5859 | return -ENODEV; | ||
5860 | } | ||
5861 | |||
5862 | /* if this is the first attach, build the infrastructure */ | ||
5863 | write_lock(&os_scsi_tapes_lock); | ||
5864 | if (os_scsi_tapes == NULL) { | ||
5865 | os_scsi_tapes = kmalloc_array(osst_max_dev, | ||
5866 | sizeof(struct osst_tape *), | ||
5867 | GFP_ATOMIC); | ||
5868 | if (os_scsi_tapes == NULL) { | ||
5869 | write_unlock(&os_scsi_tapes_lock); | ||
5870 | printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n"); | ||
5871 | goto out_put_disk; | ||
5872 | } | ||
5873 | for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL; | ||
5874 | } | ||
5875 | |||
5876 | if (osst_nr_dev >= osst_max_dev) { | ||
5877 | write_unlock(&os_scsi_tapes_lock); | ||
5878 | printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev); | ||
5879 | goto out_put_disk; | ||
5880 | } | ||
5881 | |||
5882 | /* find a free minor number */ | ||
5883 | for (i = 0; i < osst_max_dev && os_scsi_tapes[i]; i++) | ||
5884 | ; | ||
5885 | if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)"); | ||
5886 | dev_num = i; | ||
5887 | |||
5888 | /* allocate a struct osst_tape for this device */ | ||
5889 | tpnt = kzalloc(sizeof(struct osst_tape), GFP_ATOMIC); | ||
5890 | if (!tpnt) { | ||
5891 | write_unlock(&os_scsi_tapes_lock); | ||
5892 | printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n"); | ||
5893 | goto out_put_disk; | ||
5894 | } | ||
5895 | |||
5896 | /* allocate a buffer for this device */ | ||
5897 | i = SDp->host->sg_tablesize; | ||
5898 | if (osst_max_sg_segs < i) | ||
5899 | i = osst_max_sg_segs; | ||
5900 | buffer = new_tape_buffer(1, SDp->host->unchecked_isa_dma, i); | ||
5901 | if (buffer == NULL) { | ||
5902 | write_unlock(&os_scsi_tapes_lock); | ||
5903 | printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n"); | ||
5904 | kfree(tpnt); | ||
5905 | goto out_put_disk; | ||
5906 | } | ||
5907 | os_scsi_tapes[dev_num] = tpnt; | ||
5908 | tpnt->buffer = buffer; | ||
5909 | tpnt->device = SDp; | ||
5910 | drive->private_data = &tpnt->driver; | ||
5911 | sprintf(drive->disk_name, "osst%d", dev_num); | ||
5912 | tpnt->driver = &osst_template; | ||
5913 | tpnt->drive = drive; | ||
5914 | tpnt->in_use = 0; | ||
5915 | tpnt->capacity = 0xfffff; | ||
5916 | tpnt->dirty = 0; | ||
5917 | tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ | ||
5918 | tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; | ||
5919 | tpnt->density = 0; | ||
5920 | tpnt->do_auto_lock = OSST_AUTO_LOCK; | ||
5921 | tpnt->can_bsr = OSST_IN_FILE_POS; | ||
5922 | tpnt->can_partitions = 0; | ||
5923 | tpnt->two_fm = OSST_TWO_FM; | ||
5924 | tpnt->fast_mteom = OSST_FAST_MTEOM; | ||
5925 | tpnt->scsi2_logical = OSST_SCSI2LOGICAL; /* FIXME */ | ||
5926 | tpnt->write_threshold = osst_write_threshold; | ||
5927 | tpnt->default_drvbuffer = 0xff; /* No forced buffering */ | ||
5928 | tpnt->partition = 0; | ||
5929 | tpnt->new_partition = 0; | ||
5930 | tpnt->nbr_partitions = 0; | ||
5931 | tpnt->min_block = 512; | ||
5932 | tpnt->max_block = OS_DATA_SIZE; | ||
5933 | tpnt->timeout = OSST_TIMEOUT; | ||
5934 | tpnt->long_timeout = OSST_LONG_TIMEOUT; | ||
5935 | |||
5936 | /* Recognize OnStream tapes */ | ||
5937 | /* We don't need to test for OnStream, as this has been done in detect () */ | ||
5938 | tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev); | ||
5939 | tpnt->omit_blklims = 1; | ||
5940 | |||
5941 | tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || | ||
5942 | (strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp); | ||
5943 | tpnt->frame_in_buffer = 0; | ||
5944 | tpnt->header_ok = 0; | ||
5945 | tpnt->linux_media = 0; | ||
5946 | tpnt->header_cache = NULL; | ||
5947 | |||
5948 | for (i=0; i < ST_NBR_MODES; i++) { | ||
5949 | STm = &(tpnt->modes[i]); | ||
5950 | STm->defined = 0; | ||
5951 | STm->sysv = OSST_SYSV; | ||
5952 | STm->defaults_for_writes = 0; | ||
5953 | STm->do_async_writes = OSST_ASYNC_WRITES; | ||
5954 | STm->do_buffer_writes = OSST_BUFFER_WRITES; | ||
5955 | STm->do_read_ahead = OSST_READ_AHEAD; | ||
5956 | STm->default_compression = ST_DONT_TOUCH; | ||
5957 | STm->default_blksize = 512; | ||
5958 | STm->default_density = (-1); /* No forced density */ | ||
5959 | } | ||
5960 | |||
5961 | for (i=0; i < ST_NBR_PARTITIONS; i++) { | ||
5962 | STps = &(tpnt->ps[i]); | ||
5963 | STps->rw = ST_IDLE; | ||
5964 | STps->eof = ST_NOEOF; | ||
5965 | STps->at_sm = 0; | ||
5966 | STps->last_block_valid = 0; | ||
5967 | STps->drv_block = (-1); | ||
5968 | STps->drv_file = (-1); | ||
5969 | } | ||
5970 | |||
5971 | tpnt->current_mode = 0; | ||
5972 | tpnt->modes[0].defined = 1; | ||
5973 | tpnt->modes[2].defined = 1; | ||
5974 | tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = 0; | ||
5975 | |||
5976 | mutex_init(&tpnt->lock); | ||
5977 | osst_nr_dev++; | ||
5978 | write_unlock(&os_scsi_tapes_lock); | ||
5979 | |||
5980 | { | ||
5981 | char name[8]; | ||
5982 | |||
5983 | /* Rewind entry */ | ||
5984 | err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num), dev, tpnt, tape_name(tpnt)); | ||
5985 | if (err) | ||
5986 | goto out_free_buffer; | ||
5987 | |||
5988 | /* No-rewind entry */ | ||
5989 | snprintf(name, 8, "%s%s", "n", tape_name(tpnt)); | ||
5990 | err = osst_sysfs_add(MKDEV(OSST_MAJOR, dev_num + 128), dev, tpnt, name); | ||
5991 | if (err) | ||
5992 | goto out_free_sysfs1; | ||
5993 | } | ||
5994 | |||
5995 | sdev_printk(KERN_INFO, SDp, | ||
5996 | "osst :I: Attached OnStream %.5s tape as %s\n", | ||
5997 | SDp->model, tape_name(tpnt)); | ||
5998 | |||
5999 | return 0; | ||
6000 | |||
6001 | out_free_sysfs1: | ||
6002 | osst_sysfs_destroy(MKDEV(OSST_MAJOR, dev_num)); | ||
6003 | out_free_buffer: | ||
6004 | kfree(buffer); | ||
6005 | out_put_disk: | ||
6006 | put_disk(drive); | ||
6007 | return err; | ||
6008 | }; | ||
6009 | |||
6010 | static int osst_remove(struct device *dev) | ||
6011 | { | ||
6012 | struct scsi_device * SDp = to_scsi_device(dev); | ||
6013 | struct osst_tape * tpnt; | ||
6014 | int i; | ||
6015 | |||
6016 | if ((SDp->type != TYPE_TAPE) || (osst_nr_dev <= 0)) | ||
6017 | return 0; | ||
6018 | |||
6019 | write_lock(&os_scsi_tapes_lock); | ||
6020 | for(i=0; i < osst_max_dev; i++) { | ||
6021 | if((tpnt = os_scsi_tapes[i]) && (tpnt->device == SDp)) { | ||
6022 | osst_sysfs_destroy(MKDEV(OSST_MAJOR, i)); | ||
6023 | osst_sysfs_destroy(MKDEV(OSST_MAJOR, i+128)); | ||
6024 | tpnt->device = NULL; | ||
6025 | put_disk(tpnt->drive); | ||
6026 | os_scsi_tapes[i] = NULL; | ||
6027 | osst_nr_dev--; | ||
6028 | write_unlock(&os_scsi_tapes_lock); | ||
6029 | vfree(tpnt->header_cache); | ||
6030 | if (tpnt->buffer) { | ||
6031 | normalize_buffer(tpnt->buffer); | ||
6032 | kfree(tpnt->buffer); | ||
6033 | } | ||
6034 | kfree(tpnt); | ||
6035 | return 0; | ||
6036 | } | ||
6037 | } | ||
6038 | write_unlock(&os_scsi_tapes_lock); | ||
6039 | return 0; | ||
6040 | } | ||
6041 | |||
6042 | static int __init init_osst(void) | ||
6043 | { | ||
6044 | int err; | ||
6045 | |||
6046 | printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid); | ||
6047 | |||
6048 | validate_options(); | ||
6049 | |||
6050 | err = osst_sysfs_init(); | ||
6051 | if (err) | ||
6052 | return err; | ||
6053 | |||
6054 | err = register_chrdev(OSST_MAJOR, "osst", &osst_fops); | ||
6055 | if (err < 0) { | ||
6056 | printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n", OSST_MAJOR); | ||
6057 | goto err_out; | ||
6058 | } | ||
6059 | |||
6060 | err = scsi_register_driver(&osst_template.gendrv); | ||
6061 | if (err) | ||
6062 | goto err_out_chrdev; | ||
6063 | |||
6064 | err = osst_create_sysfs_files(&osst_template.gendrv); | ||
6065 | if (err) | ||
6066 | goto err_out_scsidrv; | ||
6067 | |||
6068 | return 0; | ||
6069 | |||
6070 | err_out_scsidrv: | ||
6071 | scsi_unregister_driver(&osst_template.gendrv); | ||
6072 | err_out_chrdev: | ||
6073 | unregister_chrdev(OSST_MAJOR, "osst"); | ||
6074 | err_out: | ||
6075 | osst_sysfs_cleanup(); | ||
6076 | return err; | ||
6077 | } | ||
6078 | |||
6079 | static void __exit exit_osst (void) | ||
6080 | { | ||
6081 | int i; | ||
6082 | struct osst_tape * STp; | ||
6083 | |||
6084 | osst_remove_sysfs_files(&osst_template.gendrv); | ||
6085 | scsi_unregister_driver(&osst_template.gendrv); | ||
6086 | unregister_chrdev(OSST_MAJOR, "osst"); | ||
6087 | osst_sysfs_cleanup(); | ||
6088 | |||
6089 | if (os_scsi_tapes) { | ||
6090 | for (i=0; i < osst_max_dev; ++i) { | ||
6091 | if (!(STp = os_scsi_tapes[i])) continue; | ||
6092 | /* This is defensive, supposed to happen during detach */ | ||
6093 | vfree(STp->header_cache); | ||
6094 | if (STp->buffer) { | ||
6095 | normalize_buffer(STp->buffer); | ||
6096 | kfree(STp->buffer); | ||
6097 | } | ||
6098 | put_disk(STp->drive); | ||
6099 | kfree(STp); | ||
6100 | } | ||
6101 | kfree(os_scsi_tapes); | ||
6102 | } | ||
6103 | printk(KERN_INFO "osst :I: Unloaded.\n"); | ||
6104 | } | ||
6105 | |||
6106 | module_init(init_osst); | ||
6107 | module_exit(exit_osst); | ||
diff --git a/drivers/scsi/osst.h b/drivers/scsi/osst.h deleted file mode 100644 index b90ae280853d..000000000000 --- a/drivers/scsi/osst.h +++ /dev/null | |||
@@ -1,651 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | * $Header: /cvsroot/osst/Driver/osst.h,v 1.16 2005/01/01 21:13:35 wriede Exp $ | ||
4 | */ | ||
5 | |||
6 | #include <asm/byteorder.h> | ||
7 | #include <linux/completion.h> | ||
8 | #include <linux/mutex.h> | ||
9 | |||
10 | /* FIXME - rename and use the following two types or delete them! | ||
11 | * and the types really should go to st.h anyway... | ||
12 | * INQUIRY packet command - Data Format (From Table 6-8 of QIC-157C) | ||
13 | */ | ||
14 | typedef struct { | ||
15 | unsigned device_type :5; /* Peripheral Device Type */ | ||
16 | unsigned reserved0_765 :3; /* Peripheral Qualifier - Reserved */ | ||
17 | unsigned reserved1_6t0 :7; /* Reserved */ | ||
18 | unsigned rmb :1; /* Removable Medium Bit */ | ||
19 | unsigned ansi_version :3; /* ANSI Version */ | ||
20 | unsigned ecma_version :3; /* ECMA Version */ | ||
21 | unsigned iso_version :2; /* ISO Version */ | ||
22 | unsigned response_format :4; /* Response Data Format */ | ||
23 | unsigned reserved3_45 :2; /* Reserved */ | ||
24 | unsigned reserved3_6 :1; /* TrmIOP - Reserved */ | ||
25 | unsigned reserved3_7 :1; /* AENC - Reserved */ | ||
26 | u8 additional_length; /* Additional Length (total_length-4) */ | ||
27 | u8 rsv5, rsv6, rsv7; /* Reserved */ | ||
28 | u8 vendor_id[8]; /* Vendor Identification */ | ||
29 | u8 product_id[16]; /* Product Identification */ | ||
30 | u8 revision_level[4]; /* Revision Level */ | ||
31 | u8 vendor_specific[20]; /* Vendor Specific - Optional */ | ||
32 | u8 reserved56t95[40]; /* Reserved - Optional */ | ||
33 | /* Additional information may be returned */ | ||
34 | } idetape_inquiry_result_t; | ||
35 | |||
36 | /* | ||
37 | * READ POSITION packet command - Data Format (From Table 6-57) | ||
38 | */ | ||
39 | typedef struct { | ||
40 | unsigned reserved0_10 :2; /* Reserved */ | ||
41 | unsigned bpu :1; /* Block Position Unknown */ | ||
42 | unsigned reserved0_543 :3; /* Reserved */ | ||
43 | unsigned eop :1; /* End Of Partition */ | ||
44 | unsigned bop :1; /* Beginning Of Partition */ | ||
45 | u8 partition; /* Partition Number */ | ||
46 | u8 reserved2, reserved3; /* Reserved */ | ||
47 | u32 first_block; /* First Block Location */ | ||
48 | u32 last_block; /* Last Block Location (Optional) */ | ||
49 | u8 reserved12; /* Reserved */ | ||
50 | u8 blocks_in_buffer[3]; /* Blocks In Buffer - (Optional) */ | ||
51 | u32 bytes_in_buffer; /* Bytes In Buffer (Optional) */ | ||
52 | } idetape_read_position_result_t; | ||
53 | |||
54 | /* | ||
55 | * Follows structures which are related to the SELECT SENSE / MODE SENSE | ||
56 | * packet commands. | ||
57 | */ | ||
58 | #define COMPRESSION_PAGE 0x0f | ||
59 | #define COMPRESSION_PAGE_LENGTH 16 | ||
60 | |||
61 | #define CAPABILITIES_PAGE 0x2a | ||
62 | #define CAPABILITIES_PAGE_LENGTH 20 | ||
63 | |||
64 | #define TAPE_PARAMTR_PAGE 0x2b | ||
65 | #define TAPE_PARAMTR_PAGE_LENGTH 16 | ||
66 | |||
67 | #define NUMBER_RETRIES_PAGE 0x2f | ||
68 | #define NUMBER_RETRIES_PAGE_LENGTH 4 | ||
69 | |||
70 | #define BLOCK_SIZE_PAGE 0x30 | ||
71 | #define BLOCK_SIZE_PAGE_LENGTH 4 | ||
72 | |||
73 | #define BUFFER_FILLING_PAGE 0x33 | ||
74 | #define BUFFER_FILLING_PAGE_LENGTH 4 | ||
75 | |||
76 | #define VENDOR_IDENT_PAGE 0x36 | ||
77 | #define VENDOR_IDENT_PAGE_LENGTH 8 | ||
78 | |||
79 | #define LOCATE_STATUS_PAGE 0x37 | ||
80 | #define LOCATE_STATUS_PAGE_LENGTH 0 | ||
81 | |||
82 | #define MODE_HEADER_LENGTH 4 | ||
83 | |||
84 | |||
85 | /* | ||
86 | * REQUEST SENSE packet command result - Data Format. | ||
87 | */ | ||
88 | typedef struct { | ||
89 | unsigned error_code :7; /* Current of deferred errors */ | ||
90 | unsigned valid :1; /* The information field conforms to QIC-157C */ | ||
91 | u8 reserved1 :8; /* Segment Number - Reserved */ | ||
92 | unsigned sense_key :4; /* Sense Key */ | ||
93 | unsigned reserved2_4 :1; /* Reserved */ | ||
94 | unsigned ili :1; /* Incorrect Length Indicator */ | ||
95 | unsigned eom :1; /* End Of Medium */ | ||
96 | unsigned filemark :1; /* Filemark */ | ||
97 | u32 information __attribute__ ((packed)); | ||
98 | u8 asl; /* Additional sense length (n-7) */ | ||
99 | u32 command_specific; /* Additional command specific information */ | ||
100 | u8 asc; /* Additional Sense Code */ | ||
101 | u8 ascq; /* Additional Sense Code Qualifier */ | ||
102 | u8 replaceable_unit_code; /* Field Replaceable Unit Code */ | ||
103 | unsigned sk_specific1 :7; /* Sense Key Specific */ | ||
104 | unsigned sksv :1; /* Sense Key Specific information is valid */ | ||
105 | u8 sk_specific2; /* Sense Key Specific */ | ||
106 | u8 sk_specific3; /* Sense Key Specific */ | ||
107 | u8 pad[2]; /* Padding to 20 bytes */ | ||
108 | } idetape_request_sense_result_t; | ||
109 | |||
110 | /* | ||
111 | * Mode Parameter Header for the MODE SENSE packet command | ||
112 | */ | ||
113 | typedef struct { | ||
114 | u8 mode_data_length; /* Length of the following data transfer */ | ||
115 | u8 medium_type; /* Medium Type */ | ||
116 | u8 dsp; /* Device Specific Parameter */ | ||
117 | u8 bdl; /* Block Descriptor Length */ | ||
118 | } osst_mode_parameter_header_t; | ||
119 | |||
120 | /* | ||
121 | * Mode Parameter Block Descriptor the MODE SENSE packet command | ||
122 | * | ||
123 | * Support for block descriptors is optional. | ||
124 | */ | ||
125 | typedef struct { | ||
126 | u8 density_code; /* Medium density code */ | ||
127 | u8 blocks[3]; /* Number of blocks */ | ||
128 | u8 reserved4; /* Reserved */ | ||
129 | u8 length[3]; /* Block Length */ | ||
130 | } osst_parameter_block_descriptor_t; | ||
131 | |||
132 | /* | ||
133 | * The Data Compression Page, as returned by the MODE SENSE packet command. | ||
134 | */ | ||
135 | typedef struct { | ||
136 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
137 | unsigned ps :1; | ||
138 | unsigned reserved0 :1; /* Reserved */ | ||
139 | unsigned page_code :6; /* Page Code - Should be 0xf */ | ||
140 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
141 | unsigned page_code :6; /* Page Code - Should be 0xf */ | ||
142 | unsigned reserved0 :1; /* Reserved */ | ||
143 | unsigned ps :1; | ||
144 | #else | ||
145 | #error "Please fix <asm/byteorder.h>" | ||
146 | #endif | ||
147 | u8 page_length; /* Page Length - Should be 14 */ | ||
148 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
149 | unsigned dce :1; /* Data Compression Enable */ | ||
150 | unsigned dcc :1; /* Data Compression Capable */ | ||
151 | unsigned reserved2 :6; /* Reserved */ | ||
152 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
153 | unsigned reserved2 :6; /* Reserved */ | ||
154 | unsigned dcc :1; /* Data Compression Capable */ | ||
155 | unsigned dce :1; /* Data Compression Enable */ | ||
156 | #else | ||
157 | #error "Please fix <asm/byteorder.h>" | ||
158 | #endif | ||
159 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
160 | unsigned dde :1; /* Data Decompression Enable */ | ||
161 | unsigned red :2; /* Report Exception on Decompression */ | ||
162 | unsigned reserved3 :5; /* Reserved */ | ||
163 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
164 | unsigned reserved3 :5; /* Reserved */ | ||
165 | unsigned red :2; /* Report Exception on Decompression */ | ||
166 | unsigned dde :1; /* Data Decompression Enable */ | ||
167 | #else | ||
168 | #error "Please fix <asm/byteorder.h>" | ||
169 | #endif | ||
170 | u32 ca; /* Compression Algorithm */ | ||
171 | u32 da; /* Decompression Algorithm */ | ||
172 | u8 reserved[4]; /* Reserved */ | ||
173 | } osst_data_compression_page_t; | ||
174 | |||
175 | /* | ||
176 | * The Medium Partition Page, as returned by the MODE SENSE packet command. | ||
177 | */ | ||
178 | typedef struct { | ||
179 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
180 | unsigned ps :1; | ||
181 | unsigned reserved1_6 :1; /* Reserved */ | ||
182 | unsigned page_code :6; /* Page Code - Should be 0x11 */ | ||
183 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
184 | unsigned page_code :6; /* Page Code - Should be 0x11 */ | ||
185 | unsigned reserved1_6 :1; /* Reserved */ | ||
186 | unsigned ps :1; | ||
187 | #else | ||
188 | #error "Please fix <asm/byteorder.h>" | ||
189 | #endif | ||
190 | u8 page_length; /* Page Length - Should be 6 */ | ||
191 | u8 map; /* Maximum Additional Partitions - Should be 0 */ | ||
192 | u8 apd; /* Additional Partitions Defined - Should be 0 */ | ||
193 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
194 | unsigned fdp :1; /* Fixed Data Partitions */ | ||
195 | unsigned sdp :1; /* Should be 0 */ | ||
196 | unsigned idp :1; /* Should be 0 */ | ||
197 | unsigned psum :2; /* Should be 0 */ | ||
198 | unsigned reserved4_012 :3; /* Reserved */ | ||
199 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
200 | unsigned reserved4_012 :3; /* Reserved */ | ||
201 | unsigned psum :2; /* Should be 0 */ | ||
202 | unsigned idp :1; /* Should be 0 */ | ||
203 | unsigned sdp :1; /* Should be 0 */ | ||
204 | unsigned fdp :1; /* Fixed Data Partitions */ | ||
205 | #else | ||
206 | #error "Please fix <asm/byteorder.h>" | ||
207 | #endif | ||
208 | u8 mfr; /* Medium Format Recognition */ | ||
209 | u8 reserved[2]; /* Reserved */ | ||
210 | } osst_medium_partition_page_t; | ||
211 | |||
212 | /* | ||
213 | * Capabilities and Mechanical Status Page | ||
214 | */ | ||
215 | typedef struct { | ||
216 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
217 | unsigned reserved1_67 :2; | ||
218 | unsigned page_code :6; /* Page code - Should be 0x2a */ | ||
219 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
220 | unsigned page_code :6; /* Page code - Should be 0x2a */ | ||
221 | unsigned reserved1_67 :2; | ||
222 | #else | ||
223 | #error "Please fix <asm/byteorder.h>" | ||
224 | #endif | ||
225 | u8 page_length; /* Page Length - Should be 0x12 */ | ||
226 | u8 reserved2, reserved3; | ||
227 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
228 | unsigned reserved4_67 :2; | ||
229 | unsigned sprev :1; /* Supports SPACE in the reverse direction */ | ||
230 | unsigned reserved4_1234 :4; | ||
231 | unsigned ro :1; /* Read Only Mode */ | ||
232 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
233 | unsigned ro :1; /* Read Only Mode */ | ||
234 | unsigned reserved4_1234 :4; | ||
235 | unsigned sprev :1; /* Supports SPACE in the reverse direction */ | ||
236 | unsigned reserved4_67 :2; | ||
237 | #else | ||
238 | #error "Please fix <asm/byteorder.h>" | ||
239 | #endif | ||
240 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
241 | unsigned reserved5_67 :2; | ||
242 | unsigned qfa :1; /* Supports the QFA two partition formats */ | ||
243 | unsigned reserved5_4 :1; | ||
244 | unsigned efmt :1; /* Supports ERASE command initiated formatting */ | ||
245 | unsigned reserved5_012 :3; | ||
246 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
247 | unsigned reserved5_012 :3; | ||
248 | unsigned efmt :1; /* Supports ERASE command initiated formatting */ | ||
249 | unsigned reserved5_4 :1; | ||
250 | unsigned qfa :1; /* Supports the QFA two partition formats */ | ||
251 | unsigned reserved5_67 :2; | ||
252 | #else | ||
253 | #error "Please fix <asm/byteorder.h>" | ||
254 | #endif | ||
255 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
256 | unsigned cmprs :1; /* Supports data compression */ | ||
257 | unsigned ecc :1; /* Supports error correction */ | ||
258 | unsigned reserved6_45 :2; /* Reserved */ | ||
259 | unsigned eject :1; /* The device can eject the volume */ | ||
260 | unsigned prevent :1; /* The device defaults in the prevent state after power up */ | ||
261 | unsigned locked :1; /* The volume is locked */ | ||
262 | unsigned lock :1; /* Supports locking the volume */ | ||
263 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
264 | unsigned lock :1; /* Supports locking the volume */ | ||
265 | unsigned locked :1; /* The volume is locked */ | ||
266 | unsigned prevent :1; /* The device defaults in the prevent state after power up */ | ||
267 | unsigned eject :1; /* The device can eject the volume */ | ||
268 | unsigned reserved6_45 :2; /* Reserved */ | ||
269 | unsigned ecc :1; /* Supports error correction */ | ||
270 | unsigned cmprs :1; /* Supports data compression */ | ||
271 | #else | ||
272 | #error "Please fix <asm/byteorder.h>" | ||
273 | #endif | ||
274 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
275 | unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ | ||
276 | /* transfers for slow buffer memory ??? */ | ||
277 | /* Also 32768 block size in some cases */ | ||
278 | unsigned reserved7_3_6 :4; | ||
279 | unsigned blk1024 :1; /* Supports 1024 bytes block size */ | ||
280 | unsigned blk512 :1; /* Supports 512 bytes block size */ | ||
281 | unsigned reserved7_0 :1; | ||
282 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
283 | unsigned reserved7_0 :1; | ||
284 | unsigned blk512 :1; /* Supports 512 bytes block size */ | ||
285 | unsigned blk1024 :1; /* Supports 1024 bytes block size */ | ||
286 | unsigned reserved7_3_6 :4; | ||
287 | unsigned blk32768 :1; /* slowb - the device restricts the byte count for PIO */ | ||
288 | /* transfers for slow buffer memory ??? */ | ||
289 | /* Also 32768 block size in some cases */ | ||
290 | #else | ||
291 | #error "Please fix <asm/byteorder.h>" | ||
292 | #endif | ||
293 | __be16 max_speed; /* Maximum speed supported in KBps */ | ||
294 | u8 reserved10, reserved11; | ||
295 | __be16 ctl; /* Continuous Transfer Limit in blocks */ | ||
296 | __be16 speed; /* Current Speed, in KBps */ | ||
297 | __be16 buffer_size; /* Buffer Size, in 512 bytes */ | ||
298 | u8 reserved18, reserved19; | ||
299 | } osst_capabilities_page_t; | ||
300 | |||
301 | /* | ||
302 | * Block Size Page | ||
303 | */ | ||
304 | typedef struct { | ||
305 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
306 | unsigned ps :1; | ||
307 | unsigned reserved1_6 :1; | ||
308 | unsigned page_code :6; /* Page code - Should be 0x30 */ | ||
309 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
310 | unsigned page_code :6; /* Page code - Should be 0x30 */ | ||
311 | unsigned reserved1_6 :1; | ||
312 | unsigned ps :1; | ||
313 | #else | ||
314 | #error "Please fix <asm/byteorder.h>" | ||
315 | #endif | ||
316 | u8 page_length; /* Page Length - Should be 2 */ | ||
317 | u8 reserved2; | ||
318 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
319 | unsigned one :1; | ||
320 | unsigned reserved2_6 :1; | ||
321 | unsigned record32_5 :1; | ||
322 | unsigned record32 :1; | ||
323 | unsigned reserved2_23 :2; | ||
324 | unsigned play32_5 :1; | ||
325 | unsigned play32 :1; | ||
326 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
327 | unsigned play32 :1; | ||
328 | unsigned play32_5 :1; | ||
329 | unsigned reserved2_23 :2; | ||
330 | unsigned record32 :1; | ||
331 | unsigned record32_5 :1; | ||
332 | unsigned reserved2_6 :1; | ||
333 | unsigned one :1; | ||
334 | #else | ||
335 | #error "Please fix <asm/byteorder.h>" | ||
336 | #endif | ||
337 | } osst_block_size_page_t; | ||
338 | |||
339 | /* | ||
340 | * Tape Parameters Page | ||
341 | */ | ||
342 | typedef struct { | ||
343 | #if defined(__BIG_ENDIAN_BITFIELD) | ||
344 | unsigned ps :1; | ||
345 | unsigned reserved1_6 :1; | ||
346 | unsigned page_code :6; /* Page code - Should be 0x2b */ | ||
347 | #elif defined(__LITTLE_ENDIAN_BITFIELD) | ||
348 | unsigned page_code :6; /* Page code - Should be 0x2b */ | ||
349 | unsigned reserved1_6 :1; | ||
350 | unsigned ps :1; | ||
351 | #else | ||
352 | #error "Please fix <asm/byteorder.h>" | ||
353 | #endif | ||
354 | u8 reserved2; | ||
355 | u8 density; | ||
356 | u8 reserved3,reserved4; | ||
357 | __be16 segtrk; | ||
358 | __be16 trks; | ||
359 | u8 reserved5,reserved6,reserved7,reserved8,reserved9,reserved10; | ||
360 | } osst_tape_paramtr_page_t; | ||
361 | |||
362 | /* OnStream definitions */ | ||
363 | |||
364 | #define OS_CONFIG_PARTITION (0xff) | ||
365 | #define OS_DATA_PARTITION (0) | ||
366 | #define OS_PARTITION_VERSION (1) | ||
367 | |||
368 | /* | ||
369 | * partition | ||
370 | */ | ||
371 | typedef struct os_partition_s { | ||
372 | __u8 partition_num; | ||
373 | __u8 par_desc_ver; | ||
374 | __be16 wrt_pass_cntr; | ||
375 | __be32 first_frame_ppos; | ||
376 | __be32 last_frame_ppos; | ||
377 | __be32 eod_frame_ppos; | ||
378 | } os_partition_t; | ||
379 | |||
380 | /* | ||
381 | * DAT entry | ||
382 | */ | ||
383 | typedef struct os_dat_entry_s { | ||
384 | __be32 blk_sz; | ||
385 | __be16 blk_cnt; | ||
386 | __u8 flags; | ||
387 | __u8 reserved; | ||
388 | } os_dat_entry_t; | ||
389 | |||
390 | /* | ||
391 | * DAT | ||
392 | */ | ||
393 | #define OS_DAT_FLAGS_DATA (0xc) | ||
394 | #define OS_DAT_FLAGS_MARK (0x1) | ||
395 | |||
396 | typedef struct os_dat_s { | ||
397 | __u8 dat_sz; | ||
398 | __u8 reserved1; | ||
399 | __u8 entry_cnt; | ||
400 | __u8 reserved3; | ||
401 | os_dat_entry_t dat_list[16]; | ||
402 | } os_dat_t; | ||
403 | |||
404 | /* | ||
405 | * Frame types | ||
406 | */ | ||
407 | #define OS_FRAME_TYPE_FILL (0) | ||
408 | #define OS_FRAME_TYPE_EOD (1 << 0) | ||
409 | #define OS_FRAME_TYPE_MARKER (1 << 1) | ||
410 | #define OS_FRAME_TYPE_HEADER (1 << 3) | ||
411 | #define OS_FRAME_TYPE_DATA (1 << 7) | ||
412 | |||
413 | /* | ||
414 | * AUX | ||
415 | */ | ||
416 | typedef struct os_aux_s { | ||
417 | __be32 format_id; /* hardware compatibility AUX is based on */ | ||
418 | char application_sig[4]; /* driver used to write this media */ | ||
419 | __be32 hdwr; /* reserved */ | ||
420 | __be32 update_frame_cntr; /* for configuration frame */ | ||
421 | __u8 frame_type; | ||
422 | __u8 frame_type_reserved; | ||
423 | __u8 reserved_18_19[2]; | ||
424 | os_partition_t partition; | ||
425 | __u8 reserved_36_43[8]; | ||
426 | __be32 frame_seq_num; | ||
427 | __be32 logical_blk_num_high; | ||
428 | __be32 logical_blk_num; | ||
429 | os_dat_t dat; | ||
430 | __u8 reserved188_191[4]; | ||
431 | __be32 filemark_cnt; | ||
432 | __be32 phys_fm; | ||
433 | __be32 last_mark_ppos; | ||
434 | __u8 reserved204_223[20]; | ||
435 | |||
436 | /* | ||
437 | * __u8 app_specific[32]; | ||
438 | * | ||
439 | * Linux specific fields: | ||
440 | */ | ||
441 | __be32 next_mark_ppos; /* when known, points to next marker */ | ||
442 | __be32 last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ | ||
443 | __u8 linux_specific[24]; | ||
444 | |||
445 | __u8 reserved_256_511[256]; | ||
446 | } os_aux_t; | ||
447 | |||
448 | #define OS_FM_TAB_MAX 1024 | ||
449 | |||
450 | typedef struct os_fm_tab_s { | ||
451 | __u8 fm_part_num; | ||
452 | __u8 reserved_1; | ||
453 | __u8 fm_tab_ent_sz; | ||
454 | __u8 reserved_3; | ||
455 | __be16 fm_tab_ent_cnt; | ||
456 | __u8 reserved6_15[10]; | ||
457 | __be32 fm_tab_ent[OS_FM_TAB_MAX]; | ||
458 | } os_fm_tab_t; | ||
459 | |||
460 | typedef struct os_ext_trk_ey_s { | ||
461 | __u8 et_part_num; | ||
462 | __u8 fmt; | ||
463 | __be16 fm_tab_off; | ||
464 | __u8 reserved4_7[4]; | ||
465 | __be32 last_hlb_hi; | ||
466 | __be32 last_hlb; | ||
467 | __be32 last_pp; | ||
468 | __u8 reserved20_31[12]; | ||
469 | } os_ext_trk_ey_t; | ||
470 | |||
471 | typedef struct os_ext_trk_tb_s { | ||
472 | __u8 nr_stream_part; | ||
473 | __u8 reserved_1; | ||
474 | __u8 et_ent_sz; | ||
475 | __u8 reserved3_15[13]; | ||
476 | os_ext_trk_ey_t dat_ext_trk_ey; | ||
477 | os_ext_trk_ey_t qfa_ext_trk_ey; | ||
478 | } os_ext_trk_tb_t; | ||
479 | |||
480 | typedef struct os_header_s { | ||
481 | char ident_str[8]; | ||
482 | __u8 major_rev; | ||
483 | __u8 minor_rev; | ||
484 | __be16 ext_trk_tb_off; | ||
485 | __u8 reserved12_15[4]; | ||
486 | __u8 pt_par_num; | ||
487 | __u8 pt_reserved1_3[3]; | ||
488 | os_partition_t partition[16]; | ||
489 | __be32 cfg_col_width; | ||
490 | __be32 dat_col_width; | ||
491 | __be32 qfa_col_width; | ||
492 | __u8 cartridge[16]; | ||
493 | __u8 reserved304_511[208]; | ||
494 | __be32 old_filemark_list[16680/4]; /* in ADR 1.4 __u8 track_table[16680] */ | ||
495 | os_ext_trk_tb_t ext_track_tb; | ||
496 | __u8 reserved17272_17735[464]; | ||
497 | os_fm_tab_t dat_fm_tab; | ||
498 | os_fm_tab_t qfa_fm_tab; | ||
499 | __u8 reserved25960_32767[6808]; | ||
500 | } os_header_t; | ||
501 | |||
502 | |||
503 | /* | ||
504 | * OnStream ADRL frame | ||
505 | */ | ||
506 | #define OS_FRAME_SIZE (32 * 1024 + 512) | ||
507 | #define OS_DATA_SIZE (32 * 1024) | ||
508 | #define OS_AUX_SIZE (512) | ||
509 | //#define OSST_MAX_SG 2 | ||
510 | |||
511 | /* The OnStream tape buffer descriptor. */ | ||
512 | struct osst_buffer { | ||
513 | unsigned char in_use; | ||
514 | unsigned char dma; /* DMA-able buffer */ | ||
515 | int buffer_size; | ||
516 | int buffer_blocks; | ||
517 | int buffer_bytes; | ||
518 | int read_pointer; | ||
519 | int writing; | ||
520 | int midlevel_result; | ||
521 | int syscall_result; | ||
522 | struct osst_request *last_SRpnt; | ||
523 | struct st_cmdstatus cmdstat; | ||
524 | struct rq_map_data map_data; | ||
525 | unsigned char *b_data; | ||
526 | os_aux_t *aux; /* onstream AUX structure at end of each block */ | ||
527 | unsigned short use_sg; /* zero or number of s/g segments for this adapter */ | ||
528 | unsigned short sg_segs; /* number of segments in s/g list */ | ||
529 | unsigned short orig_sg_segs; /* number of segments allocated at first try */ | ||
530 | struct scatterlist sg[1]; /* MUST BE last item */ | ||
531 | } ; | ||
532 | |||
533 | /* The OnStream tape drive descriptor */ | ||
534 | struct osst_tape { | ||
535 | struct scsi_driver *driver; | ||
536 | unsigned capacity; | ||
537 | struct scsi_device *device; | ||
538 | struct mutex lock; /* for serialization */ | ||
539 | struct completion wait; /* for SCSI commands */ | ||
540 | struct osst_buffer * buffer; | ||
541 | |||
542 | /* Drive characteristics */ | ||
543 | unsigned char omit_blklims; | ||
544 | unsigned char do_auto_lock; | ||
545 | unsigned char can_bsr; | ||
546 | unsigned char can_partitions; | ||
547 | unsigned char two_fm; | ||
548 | unsigned char fast_mteom; | ||
549 | unsigned char restr_dma; | ||
550 | unsigned char scsi2_logical; | ||
551 | unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ | ||
552 | unsigned char pos_unknown; /* after reset position unknown */ | ||
553 | int write_threshold; | ||
554 | int timeout; /* timeout for normal commands */ | ||
555 | int long_timeout; /* timeout for commands known to take long time*/ | ||
556 | |||
557 | /* Mode characteristics */ | ||
558 | struct st_modedef modes[ST_NBR_MODES]; | ||
559 | int current_mode; | ||
560 | |||
561 | /* Status variables */ | ||
562 | int partition; | ||
563 | int new_partition; | ||
564 | int nbr_partitions; /* zero until partition support enabled */ | ||
565 | struct st_partstat ps[ST_NBR_PARTITIONS]; | ||
566 | unsigned char dirty; | ||
567 | unsigned char ready; | ||
568 | unsigned char write_prot; | ||
569 | unsigned char drv_write_prot; | ||
570 | unsigned char in_use; | ||
571 | unsigned char blksize_changed; | ||
572 | unsigned char density_changed; | ||
573 | unsigned char compression_changed; | ||
574 | unsigned char drv_buffer; | ||
575 | unsigned char density; | ||
576 | unsigned char door_locked; | ||
577 | unsigned char rew_at_close; | ||
578 | unsigned char inited; | ||
579 | int block_size; | ||
580 | int min_block; | ||
581 | int max_block; | ||
582 | int recover_count; /* from tape opening */ | ||
583 | int abort_count; | ||
584 | int write_count; | ||
585 | int read_count; | ||
586 | int recover_erreg; /* from last status call */ | ||
587 | /* | ||
588 | * OnStream specific data | ||
589 | */ | ||
590 | int os_fw_rev; /* the firmware revision * 10000 */ | ||
591 | unsigned char raw; /* flag OnStream raw access (32.5KB block size) */ | ||
592 | unsigned char poll; /* flag that this drive needs polling (IDE|firmware) */ | ||
593 | unsigned char frame_in_buffer; /* flag that the frame as per frame_seq_number | ||
594 | * has been read into STp->buffer and is valid */ | ||
595 | int frame_seq_number; /* logical frame number */ | ||
596 | int logical_blk_num; /* logical block number */ | ||
597 | unsigned first_frame_position; /* physical frame to be transferred to/from host */ | ||
598 | unsigned last_frame_position; /* physical frame to be transferd to/from tape */ | ||
599 | int cur_frames; /* current number of frames in internal buffer */ | ||
600 | int max_frames; /* max number of frames in internal buffer */ | ||
601 | char application_sig[5]; /* application signature */ | ||
602 | unsigned char fast_open; /* flag that reminds us we didn't check headers at open */ | ||
603 | unsigned short wrt_pass_cntr; /* write pass counter */ | ||
604 | int update_frame_cntr; /* update frame counter */ | ||
605 | int onstream_write_error; /* write error recovery active */ | ||
606 | int header_ok; /* header frame verified ok */ | ||
607 | int linux_media; /* reading linux-specifc media */ | ||
608 | int linux_media_version; | ||
609 | os_header_t * header_cache; /* cache is kept for filemark positions */ | ||
610 | int filemark_cnt; | ||
611 | int first_mark_ppos; | ||
612 | int last_mark_ppos; | ||
613 | int last_mark_lbn; /* storing log_blk_num of last mark is extends ADR spec */ | ||
614 | int first_data_ppos; | ||
615 | int eod_frame_ppos; | ||
616 | int eod_frame_lfa; | ||
617 | int write_type; /* used in write error recovery */ | ||
618 | int read_error_frame; /* used in read error recovery */ | ||
619 | unsigned long cmd_start_time; | ||
620 | unsigned long max_cmd_time; | ||
621 | |||
622 | #if DEBUG | ||
623 | unsigned char write_pending; | ||
624 | int nbr_finished; | ||
625 | int nbr_waits; | ||
626 | unsigned char last_cmnd[6]; | ||
627 | unsigned char last_sense[16]; | ||
628 | #endif | ||
629 | struct gendisk *drive; | ||
630 | } ; | ||
631 | |||
632 | /* scsi tape command */ | ||
633 | struct osst_request { | ||
634 | unsigned char cmd[MAX_COMMAND_SIZE]; | ||
635 | unsigned char sense[SCSI_SENSE_BUFFERSIZE]; | ||
636 | int result; | ||
637 | struct osst_tape *stp; | ||
638 | struct completion *waiting; | ||
639 | struct bio *bio; | ||
640 | }; | ||
641 | |||
642 | /* Values of write_type */ | ||
643 | #define OS_WRITE_DATA 0 | ||
644 | #define OS_WRITE_EOD 1 | ||
645 | #define OS_WRITE_NEW_MARK 2 | ||
646 | #define OS_WRITE_LAST_MARK 3 | ||
647 | #define OS_WRITE_HEADER 4 | ||
648 | #define OS_WRITE_FILLER 5 | ||
649 | |||
650 | /* Additional rw state */ | ||
651 | #define OS_WRITING_COMPLETE 3 | ||
diff --git a/drivers/scsi/osst_detect.h b/drivers/scsi/osst_detect.h deleted file mode 100644 index 83c1d4fb11db..000000000000 --- a/drivers/scsi/osst_detect.h +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | #define SIGS_FROM_OSST \ | ||
3 | {"OnStream", "SC-", "", "osst"}, \ | ||
4 | {"OnStream", "DI-", "", "osst"}, \ | ||
5 | {"OnStream", "DP-", "", "osst"}, \ | ||
6 | {"OnStream", "FW-", "", "osst"}, \ | ||
7 | {"OnStream", "USB", "", "osst"} | ||
diff --git a/drivers/scsi/osst_options.h b/drivers/scsi/osst_options.h deleted file mode 100644 index a6a389b88876..000000000000 --- a/drivers/scsi/osst_options.h +++ /dev/null | |||
@@ -1,107 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | The compile-time configurable defaults for the Linux SCSI tape driver. | ||
4 | |||
5 | Copyright 1995 Kai Makisara. | ||
6 | |||
7 | Last modified: Wed Sep 2 21:24:07 1998 by root@home | ||
8 | |||
9 | Changed (and renamed) for OnStream SCSI drives garloff@suse.de | ||
10 | 2000-06-21 | ||
11 | |||
12 | $Header: /cvsroot/osst/Driver/osst_options.h,v 1.6 2003/12/23 14:22:12 wriede Exp $ | ||
13 | */ | ||
14 | |||
15 | #ifndef _OSST_OPTIONS_H | ||
16 | #define _OSST_OPTIONS_H | ||
17 | |||
18 | /* The minimum limit for the number of SCSI tape devices is determined by | ||
19 | OSST_MAX_TAPES. If the number of tape devices and the "slack" defined by | ||
20 | OSST_EXTRA_DEVS exceeds OSST_MAX_TAPES, the large number is used. */ | ||
21 | #define OSST_MAX_TAPES 4 | ||
22 | |||
23 | /* If OSST_IN_FILE_POS is nonzero, the driver positions the tape after the | ||
24 | record been read by the user program even if the tape has moved further | ||
25 | because of buffered reads. Should be set to zero to support also drives | ||
26 | that can't space backwards over records. NOTE: The tape will be | ||
27 | spaced backwards over an "accidentally" crossed filemark in any case. */ | ||
28 | #define OSST_IN_FILE_POS 1 | ||
29 | |||
30 | /* The tape driver buffer size in kilobytes. */ | ||
31 | /* Don't change, as this is the HW blocksize */ | ||
32 | #define OSST_BUFFER_BLOCKS 32 | ||
33 | |||
34 | /* The number of kilobytes of data in the buffer that triggers an | ||
35 | asynchronous write in fixed block mode. See also OSST_ASYNC_WRITES | ||
36 | below. */ | ||
37 | #define OSST_WRITE_THRESHOLD_BLOCKS 32 | ||
38 | |||
39 | /* OSST_EOM_RESERVE defines the number of frames are kept in reserve for | ||
40 | * * write error recovery when writing near end of medium. ENOSPC is returned | ||
41 | * * when write() is called and the tape write position is within this number | ||
42 | * * of blocks from the tape capacity. */ | ||
43 | #define OSST_EOM_RESERVE 300 | ||
44 | |||
45 | /* The maximum number of tape buffers the driver allocates. The number | ||
46 | is also constrained by the number of drives detected. Determines the | ||
47 | maximum number of concurrently active tape drives. */ | ||
48 | #define OSST_MAX_BUFFERS OSST_MAX_TAPES | ||
49 | |||
50 | /* Maximum number of scatter/gather segments */ | ||
51 | /* Fit one buffer in pages and add one for the AUX header */ | ||
52 | #define OSST_MAX_SG (((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) + 1) | ||
53 | |||
54 | /* The number of scatter/gather segments to allocate at first try (must be | ||
55 | smaller or equal to the maximum). */ | ||
56 | #define OSST_FIRST_SG ((OSST_BUFFER_BLOCKS*1024) / PAGE_SIZE) | ||
57 | |||
58 | /* The size of the first scatter/gather segments (determines the maximum block | ||
59 | size for SCSI adapters not supporting scatter/gather). The default is set | ||
60 | to try to allocate the buffer as one chunk. */ | ||
61 | #define OSST_FIRST_ORDER (15-PAGE_SHIFT) | ||
62 | |||
63 | |||
64 | /* The following lines define defaults for properties that can be set | ||
65 | separately for each drive using the MTSTOPTIONS ioctl. */ | ||
66 | |||
67 | /* If OSST_TWO_FM is non-zero, the driver writes two filemarks after a | ||
68 | file being written. Some drives can't handle two filemarks at the | ||
69 | end of data. */ | ||
70 | #define OSST_TWO_FM 0 | ||
71 | |||
72 | /* If OSST_BUFFER_WRITES is non-zero, writes in fixed block mode are | ||
73 | buffered until the driver buffer is full or asynchronous write is | ||
74 | triggered. */ | ||
75 | #define OSST_BUFFER_WRITES 1 | ||
76 | |||
77 | /* If OSST_ASYNC_WRITES is non-zero, the SCSI write command may be started | ||
78 | without waiting for it to finish. May cause problems in multiple | ||
79 | tape backups. */ | ||
80 | #define OSST_ASYNC_WRITES 1 | ||
81 | |||
82 | /* If OSST_READ_AHEAD is non-zero, blocks are read ahead in fixed block | ||
83 | mode. */ | ||
84 | #define OSST_READ_AHEAD 1 | ||
85 | |||
86 | /* If OSST_AUTO_LOCK is non-zero, the drive door is locked at the first | ||
87 | read or write command after the device is opened. The door is opened | ||
88 | when the device is closed. */ | ||
89 | #define OSST_AUTO_LOCK 0 | ||
90 | |||
91 | /* If OSST_FAST_MTEOM is non-zero, the MTEOM ioctl is done using the | ||
92 | direct SCSI command. The file number status is lost but this method | ||
93 | is fast with some drives. Otherwise MTEOM is done by spacing over | ||
94 | files and the file number status is retained. */ | ||
95 | #define OSST_FAST_MTEOM 0 | ||
96 | |||
97 | /* If OSST_SCSI2LOGICAL is nonzero, the logical block addresses are used for | ||
98 | MTIOCPOS and MTSEEK by default. Vendor addresses are used if OSST_SCSI2LOGICAL | ||
99 | is zero. */ | ||
100 | #define OSST_SCSI2LOGICAL 0 | ||
101 | |||
102 | /* If OSST_SYSV is non-zero, the tape behaves according to the SYS V semantics. | ||
103 | The default is BSD semantics. */ | ||
104 | #define OSST_SYSV 0 | ||
105 | |||
106 | |||
107 | #endif | ||
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c index 9c4c710dcccf..b9e7b291c129 100644 --- a/drivers/scsi/st.c +++ b/drivers/scsi/st.c | |||
@@ -228,7 +228,6 @@ static DEFINE_IDR(st_index_idr); | |||
228 | 228 | ||
229 | 229 | ||
230 | 230 | ||
231 | #include "osst_detect.h" | ||
232 | #ifndef SIGS_FROM_OSST | 231 | #ifndef SIGS_FROM_OSST |
233 | #define SIGS_FROM_OSST \ | 232 | #define SIGS_FROM_OSST \ |
234 | {"OnStream", "SC-", "", "osst"}, \ | 233 | {"OnStream", "SC-", "", "osst"}, \ |
@@ -4267,9 +4266,10 @@ static int st_probe(struct device *dev) | |||
4267 | if (SDp->type != TYPE_TAPE) | 4266 | if (SDp->type != TYPE_TAPE) |
4268 | return -ENODEV; | 4267 | return -ENODEV; |
4269 | if ((stp = st_incompatible(SDp))) { | 4268 | if ((stp = st_incompatible(SDp))) { |
4270 | sdev_printk(KERN_INFO, SDp, "Found incompatible tape\n"); | ||
4271 | sdev_printk(KERN_INFO, SDp, | 4269 | sdev_printk(KERN_INFO, SDp, |
4272 | "st: The suggested driver is %s.\n", stp); | 4270 | "OnStream tapes are no longer supported;\n"); |
4271 | sdev_printk(KERN_INFO, SDp, | ||
4272 | "please mail to linux-scsi@vger.kernel.org.\n"); | ||
4273 | return -ENODEV; | 4273 | return -ENODEV; |
4274 | } | 4274 | } |
4275 | 4275 | ||