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