Commit 45f841b0 authored by Willem Riede's avatar Willem Riede Committed by Doug Ledford

osst update

fro Willem Riede.
parent 30950d15
...@@ -13,18 +13,18 @@ ...@@ -13,18 +13,18 @@
order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer, order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale. Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
Copyright 1992 - 2000 Kai Makisara Copyright 1992 - 2002 Kai Makisara / Willem Riede
email Kai.Makisara@metla.fi email Kai.Makisara@metla.fi / osst@riede.org
$Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $ $Header: /home/cvsroot/Driver/osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $
Microscopic alterations - Rik Ling, 2000/12/21 Microscopic alterations - Rik Ling, 2000/12/21
Last modified: Wed Feb 2 22:04:05 2000 by makisara@kai.makisara.local Last st.c sync: Tue Oct 15 22:01:04 2002 by makisara
Some small formal changes - aeb, 950809 Some small formal changes - aeb, 950809
*/ */
static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $"; static const char * cvsid = "$Id: osst.c,v 1.65 2001/11/11 20:38:56 riede Exp $";
const char * osst_version = "0.9.10"; const char * osst_version = "0.99.0p3";
/* The "failure to reconnect" firmware bug */ /* The "failure to reconnect" firmware bug */
#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/ #define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
...@@ -60,7 +60,6 @@ const char * osst_version = "0.9.10"; ...@@ -60,7 +60,6 @@ const char * osst_version = "0.9.10";
#define OSST_DEB_MSG KERN_NOTICE #define OSST_DEB_MSG KERN_NOTICE
#define MAJOR_NR OSST_MAJOR #define MAJOR_NR OSST_MAJOR
#define DEVICE_NR(device) (minor(device) & 0x7f)
#include <linux/blk.h> #include <linux/blk.h>
#include "scsi.h" #include "scsi.h"
...@@ -74,30 +73,32 @@ const char * osst_version = "0.9.10"; ...@@ -74,30 +73,32 @@ const char * osst_version = "0.9.10";
#include "osst_options.h" #include "osst_options.h"
#include "osst_detect.h" #include "osst_detect.h"
static int buffer_kbs = 0; static int max_dev = 0;
static int write_threshold_kbs = 0; static int write_threshold_kbs = 0;
static int max_buffers = 0;
static int max_sg_segs = 0; static int max_sg_segs = 0;
#ifdef MODULE #ifdef MODULE
MODULE_AUTHOR("Willem Riede"); MODULE_AUTHOR("Willem Riede");
MODULE_DESCRIPTION("OnStream SCSI Tape Driver"); MODULE_DESCRIPTION("OnStream {DI-|FW-|SC-|USB}{30|50} Tape Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
MODULE_PARM(buffer_kbs, "i"); MODULE_PARM(max_dev, "i");
MODULE_PARM_DESC(max_dev, "Maximum number of OnStream Tape Drives to attach (4)");
MODULE_PARM(write_threshold_kbs, "i"); MODULE_PARM(write_threshold_kbs, "i");
MODULE_PARM(max_buffers, "i"); MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 30)");
MODULE_PARM(max_sg_segs, "i"); MODULE_PARM(max_sg_segs, "i");
MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
#else #else
static struct osst_dev_parm { static struct osst_dev_parm {
char *name; char *name;
int *val; int *val;
} parms[] __initdata = { } parms[] __initdata = {
{ "buffer_kbs", &buffer_kbs }, { "max_dev", &max_dev },
{ "write_threshold_kbs", &write_threshold_kbs }, { "write_threshold_kbs", &write_threshold_kbs },
{ "max_buffers", &max_buffers },
{ "max_sg_segs", &max_sg_segs } { "max_sg_segs", &max_sg_segs }
}; };
#endif #endif
/* Some default definitions have been moved to osst_options.h */ /* Some default definitions have been moved to osst_options.h */
...@@ -116,34 +117,41 @@ static int debugging = 1; ...@@ -116,34 +117,41 @@ static int debugging = 1;
// #define OSST_INJECT_ERRORS 1 // #define OSST_INJECT_ERRORS 1
#endif #endif
#define MAX_RETRIES 0 #define MAX_RETRIES 2
#define MAX_READ_RETRIES 0
#define MAX_WRITE_RETRIES 0 #define MAX_WRITE_RETRIES 0
#define MAX_READY_RETRIES 5 #define MAX_READY_RETRIES 0
#define NO_TAPE NOT_READY #define NO_TAPE NOT_READY
#define OSST_WAIT_POSITION_COMPLETE (HZ > 200 ? HZ / 200 : 1)
#define OSST_WAIT_WRITE_COMPLETE (HZ / 12)
#define OSST_WAIT_LONG_WRITE_COMPLETE (HZ / 2)
#define OSST_TIMEOUT (200 * HZ) #define OSST_TIMEOUT (200 * HZ)
#define OSST_LONG_TIMEOUT (1800 * HZ) #define OSST_LONG_TIMEOUT (1800 * HZ)
#define TAPE_NR(x) (minor(x) & ~(128 | ST_MODE_MASK)) #define TAPE_NR(x) (minor(x) & ~(-1 << ST_MODE_SHIFT))
#define TAPE_MODE(x) ((minor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT) #define TAPE_MODE(x) ((minor(x) & ST_MODE_MASK) >> ST_MODE_SHIFT)
#define TAPE_REWIND(x) ((minor(x) & 0x80) == 0)
#define TAPE_IS_RAW(x) (TAPE_MODE(x) & (ST_NBR_MODES >> 1))
/* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower /* Internal ioctl to set both density (uppermost 8 bits) and blocksize (lower
24 bits) */ 24 bits) */
#define SET_DENS_AND_BLK 0x10001 #define SET_DENS_AND_BLK 0x10001
static int osst_nbr_buffers;
static int osst_buffer_size = OSST_BUFFER_SIZE; static int osst_buffer_size = OSST_BUFFER_SIZE;
static int osst_write_threshold = OSST_WRITE_THRESHOLD; static int osst_write_threshold = OSST_WRITE_THRESHOLD;
static int osst_max_buffers = OSST_MAX_BUFFERS;
static int osst_max_sg_segs = OSST_MAX_SG; static int osst_max_sg_segs = OSST_MAX_SG;
static int osst_max_dev = OSST_MAX_TAPES;
static int osst_nr_dev;
static OS_Scsi_Tape **os_scsi_tapes = NULL; static OS_Scsi_Tape **os_scsi_tapes = NULL;
static OSST_buffer **osst_buffers = NULL; static rwlock_t os_scsi_tapes_lock = RW_LOCK_UNLOCKED;
static int modes_defined = FALSE; static int modes_defined = FALSE;
static OSST_buffer *new_tape_buffer(int, int); static OSST_buffer *new_tape_buffer(int, int, int);
static int enlarge_buffer(OSST_buffer *, int, int); static int enlarge_buffer(OSST_buffer *, int);
static void normalize_buffer(OSST_buffer *); static void normalize_buffer(OSST_buffer *);
static int append_to_buffer(const char *, OSST_buffer *, int); static int append_to_buffer(const char *, OSST_buffer *, int);
static int from_buffer(OSST_buffer *, char *, int); static int from_buffer(OSST_buffer *, char *, int);
...@@ -151,22 +159,18 @@ static int osst_zero_buffer_tail(OSST_buffer *); ...@@ -151,22 +159,18 @@ static int osst_zero_buffer_tail(OSST_buffer *);
static int osst_copy_to_buffer(OSST_buffer *, unsigned char *); static int osst_copy_to_buffer(OSST_buffer *, unsigned char *);
static int osst_copy_from_buffer(OSST_buffer *, unsigned char *); static int osst_copy_from_buffer(OSST_buffer *, unsigned char *);
static int osst_init(void);
static int osst_attach(Scsi_Device *); static int osst_attach(Scsi_Device *);
static void osst_detach(Scsi_Device *); static void osst_detach(Scsi_Device *);
static int osst_nr_dev;
static int osst_dev_max;
struct Scsi_Device_Template osst_template = struct Scsi_Device_Template osst_template =
{ {
.module = THIS_MODULE, .module = THIS_MODULE,
.list = LIST_HEAD_INIT(osst_template.list), .list = LIST_HEAD_INIT(osst_template.list),
.name = "OnStream tape", .name = "OnStream Tape",
.tag = "osst", .tag = "osst",
.scsi_type = TYPE_TAPE, .scsi_type = TYPE_TAPE,
.attach = osst_attach, .attach = osst_attach,
.detach = osst_detach .detach = osst_detach
}; };
static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, unsigned int cmd_in,unsigned long arg); static int osst_int_ioctl(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, unsigned int cmd_in,unsigned long arg);
...@@ -181,9 +185,8 @@ static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, ...@@ -181,9 +185,8 @@ static int osst_write_error_recovery(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
static inline char *tape_name(OS_Scsi_Tape *tape) static inline char *tape_name(OS_Scsi_Tape *tape)
{ {
return tape->disk->disk_name; return tape->drive->disk_name;
} }
/* Routines that handle the interaction with mid-layer SCSI routines */ /* Routines that handle the interaction with mid-layer SCSI routines */
...@@ -201,13 +204,12 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt) ...@@ -201,13 +204,12 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
sense[0] = 0; /* We don't have sense data if this byte is zero */ sense[0] = 0; /* We don't have sense data if this byte is zero */
return 0; return 0;
} }
if (driver_byte(result) & DRIVER_SENSE) if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
scode = sense[2] & 0x0f; scode = sense[2] & 0x0f;
else { else {
sense[0] = 0; /* We don't have sense data if this byte is zero */ sense[0] = 0; /* We don't have sense data if this byte is zero */
scode = 0; scode = 0;
} }
#if DEBUG #if DEBUG
if (debugging) { if (debugging) {
printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n", printk(OSST_DEB_MSG "%s:D: Error: %x, cmd: %x %x %x %x %x %x Len: %d\n",
...@@ -215,10 +217,12 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt) ...@@ -215,10 +217,12 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2], SRpnt->sr_cmnd[0], SRpnt->sr_cmnd[1], SRpnt->sr_cmnd[2],
SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5], SRpnt->sr_cmnd[3], SRpnt->sr_cmnd[4], SRpnt->sr_cmnd[5],
SRpnt->sr_bufflen); SRpnt->sr_bufflen);
if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
name, scode, sense[12], sense[13]);
if (driver_byte(result) & DRIVER_SENSE) if (driver_byte(result) & DRIVER_SENSE)
print_req_sense("osst", SRpnt); print_req_sense("osst", SRpnt);
} }
else // else
#endif #endif
if (!(driver_byte(result) & DRIVER_SENSE) || if (!(driver_byte(result) & DRIVER_SENSE) ||
((sense[0] & 0x70) == 0x70 && ((sense[0] & 0x70) == 0x70 &&
...@@ -249,6 +253,8 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt) ...@@ -249,6 +253,8 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
} }
} }
} }
STp->pos_unknown |= STp->device->was_reset;
if ((sense[0] & 0x70) == 0x70 && if ((sense[0] & 0x70) == 0x70 &&
scode == RECOVERED_ERROR) { scode == RECOVERED_ERROR) {
STp->recover_count++; STp->recover_count++;
...@@ -275,22 +281,21 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt) ...@@ -275,22 +281,21 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
/* Wakeup from interrupt */ /* Wakeup from interrupt */
static void osst_sleep_done (Scsi_Cmnd * SCpnt) static void osst_sleep_done (Scsi_Cmnd * SCpnt)
{ {
OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data, OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data, OS_Scsi_Tape, driver);
OS_Scsi_Tape, driver);
if ((STp->buffer)->writing && if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 && (SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) { (SCpnt->sense_buffer[2] & 0x40)) {
/* EOM at write-behind, has all been written? */ /* EOM at write-behind, has all been written? */
if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
(STp->buffer)->midlevel_result = SCpnt->result; /* Error */ STp->buffer->midlevel_result = SCpnt->result; /* Error */
else else
(STp->buffer)->midlevel_result = INT_MAX; /* OK */ STp->buffer->midlevel_result = INT_MAX; /* OK */
} }
else else
(STp->buffer)->midlevel_result = SCpnt->result; STp->buffer->midlevel_result = SCpnt->result;
SCpnt->request->rq_status = RQ_SCSI_DONE; SCpnt->request->rq_status = RQ_SCSI_DONE;
(STp->buffer)->last_SRpnt = SCpnt->sc_request; STp->buffer->last_SRpnt = SCpnt->sc_request;
#if DEBUG #if DEBUG
STp->write_pending = 0; STp->write_pending = 0;
...@@ -312,7 +317,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp, ...@@ -312,7 +317,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp,
#endif #endif
if (SRpnt == NULL) { if (SRpnt == NULL) {
if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) { if ((SRpnt = scsi_allocate_request(STp->device)) == NULL) {
printk(KERN_ERR "%s:E: Can't get SCSI request->\n", tape_name(STp)); printk(KERN_ERR "%s:E: Can't get SCSI request.\n", tape_name(STp));
if (signal_pending(current)) if (signal_pending(current))
(STp->buffer)->syscall_result = (-EINTR); (STp->buffer)->syscall_result = (-EINTR);
else else
...@@ -335,7 +340,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp, ...@@ -335,7 +340,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp,
SRpnt->sr_cmd_len = 0; SRpnt->sr_cmd_len = 0;
SRpnt->sr_request->waiting = &(STp->wait); SRpnt->sr_request->waiting = &(STp->wait);
SRpnt->sr_request->rq_status = RQ_SCSI_BUSY; SRpnt->sr_request->rq_status = RQ_SCSI_BUSY;
SRpnt->sr_request->rq_disk = STp->disk; SRpnt->sr_request->rq_disk = STp->drive;
scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries); scsi_do_req(SRpnt, (void *)cmd, bp, bytes, osst_sleep_done, timeout, retries);
...@@ -387,7 +392,7 @@ static void osst_write_behind_check(OS_Scsi_Tape *STp) ...@@ -387,7 +392,7 @@ static void osst_write_behind_check(OS_Scsi_Tape *STp)
scsi_release_request((STp->buffer)->last_SRpnt); scsi_release_request((STp->buffer)->last_SRpnt);
if (STbuffer->writing < STbuffer->buffer_bytes) if (STbuffer->writing < STbuffer->buffer_bytes)
printk(KERN_WARNING "osst:A: write_behind_check: something left in buffer!\n"); printk(KERN_WARNING "osst :A: write_behind_check: something left in buffer!\n");
STbuffer->buffer_bytes -= STbuffer->writing; STbuffer->buffer_bytes -= STbuffer->writing;
STbuffer->writing = 0; STbuffer->writing = 0;
...@@ -537,7 +542,7 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet ...@@ -537,7 +542,7 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet
STp->first_frame_position); STp->first_frame_position);
goto err_out; goto err_out;
} }
STp->frame_in_buffer = 1; // STp->frame_in_buffer = 1;
if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) { if (frame_seq_number != -1 && ntohl(aux->frame_seq_num) != frame_seq_number) {
if (!quiet) if (!quiet)
...@@ -565,12 +570,14 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet ...@@ -565,12 +570,14 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet
} }
if (aux->frame_type == OS_FRAME_TYPE_EOD) { if (aux->frame_type == OS_FRAME_TYPE_EOD) {
STps->eof = ST_EOD_1; STps->eof = ST_EOD_1;
STp->frame_in_buffer = 1;
} }
if (aux->frame_type == OS_FRAME_TYPE_DATA) { if (aux->frame_type == OS_FRAME_TYPE_DATA) {
blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt); blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
blk_sz = ntohl(aux->dat.dat_list[0].blk_sz); blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
STp->buffer->buffer_bytes = blk_cnt * blk_sz; STp->buffer->buffer_bytes = blk_cnt * blk_sz;
STp->buffer->read_pointer = 0; STp->buffer->read_pointer = 0;
STp->frame_in_buffer = 1;
/* See what block size was used to write file */ /* See what block size was used to write file */
if (STp->block_size != blk_sz && blk_sz > 0) { if (STp->block_size != blk_sz && blk_sz > 0) {
...@@ -597,18 +604,23 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet ...@@ -597,18 +604,23 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet
/* /*
* Wait for the unit to become Ready * Wait for the unit to become Ready
*/ */
static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout) static int osst_wait_ready(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned timeout, int initial_delay)
{ {
unsigned char cmd[MAX_COMMAND_SIZE]; unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request * SRpnt; Scsi_Request * SRpnt;
long startwait = jiffies; long startwait = jiffies;
#if DEBUG #if DEBUG
int dbg = debugging; int dbg = debugging;
char *name = tape_name(STp); char * name = tape_name(STp);
printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name); printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
#endif #endif
if (initial_delay > 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(initial_delay);
}
memset(cmd, 0, MAX_COMMAND_SIZE); memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY; cmd[0] = TEST_UNIT_READY;
...@@ -720,10 +732,10 @@ static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aS ...@@ -720,10 +732,10 @@ static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aS
{ {
int retval; int retval;
osst_wait_ready(STp, aSRpnt, 15 * 60); /* TODO - can this catch a write error? */ osst_wait_ready(STp, aSRpnt, 15 * 60, 0); /* TODO - can this catch a write error? */
retval = osst_set_frame_position(STp, aSRpnt, frame, 0); retval = osst_set_frame_position(STp, aSRpnt, frame, 0);
if (retval) return (retval); if (retval) return (retval);
osst_wait_ready(STp, aSRpnt, 15 * 60); osst_wait_ready(STp, aSRpnt, 15 * 60, OSST_WAIT_POSITION_COMPLETE);
return (osst_get_frame_position(STp, aSRpnt)); return (osst_get_frame_position(STp, aSRpnt));
} }
...@@ -736,6 +748,7 @@ static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt) ...@@ -736,6 +748,7 @@ static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
Scsi_Request * SRpnt; Scsi_Request * SRpnt;
int result = 0; int result = 0;
int delay = OSST_WAIT_LONG_WRITE_COMPLETE;
#if DEBUG #if DEBUG
char *name = tape_name(STp); char *name = tape_name(STp);
...@@ -749,12 +762,20 @@ static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt) ...@@ -749,12 +762,20 @@ static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE); SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_WRITE_RETRIES, TRUE);
*aSRpnt = SRpnt; *aSRpnt = SRpnt;
if (!SRpnt) return (-EBUSY); if (!SRpnt) return (-EBUSY);
//printk(OSST_DEB_MSG "%s:X: Write filemark returned %x:%02x:%02x:%02x\n",dev,STp->buffer->syscall_result,SRpnt->sr_sense_buffer[2] & 0x0f,SRpnt->sr_sense_buffer[12],SRpnt->sr_sense_buffer[13]);
if ((STp->buffer)->syscall_result) if (STp->buffer->syscall_result) {
result = osst_write_error_recovery(STp, aSRpnt, 0); if ((SRpnt->sr_sense_buffer[2] & 0x0f) == 2 && SRpnt->sr_sense_buffer[12] == 4) {
if (SRpnt->sr_sense_buffer[13] == 8) {
result |= osst_wait_ready(STp, aSRpnt, 5 * 60); //printk(OSST_DEB_MSG "%s:X: Long initial delay\n", dev);
delay = OSST_WAIT_LONG_WRITE_COMPLETE;
}
} else
result = osst_write_error_recovery(STp, aSRpnt, 0);
}
//printk(OSST_DEB_MSG "%s:X: Entering wait ready (%d)\n",dev,delay);
result |= osst_wait_ready(STp, aSRpnt, 5 * 60, delay);
STp->ps[STp->partition].rw = OS_WRITING_COMPLETE; STp->ps[STp->partition].rw = OS_WRITING_COMPLETE;
return (result); return (result);
} }
...@@ -845,7 +866,7 @@ static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeo ...@@ -845,7 +866,7 @@ static int osst_read_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int timeo
printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name); printk(OSST_DEB_MSG "%s:D: Reading frame from OnStream tape\n", name);
#endif #endif
SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ, SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
STp->timeout, MAX_RETRIES, TRUE); STp->timeout, MAX_READ_RETRIES, TRUE);
*aSRpnt = SRpnt; *aSRpnt = SRpnt;
if (!SRpnt) if (!SRpnt)
return (-EBUSY); return (-EBUSY);
...@@ -901,7 +922,8 @@ static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt) ...@@ -901,7 +922,8 @@ static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
#endif #endif
if (STps->rw != ST_READING) { /* Initialize read operation */ if (STps->rw != ST_READING) { /* Initialize read operation */
if (STps->rw == ST_WRITING) { if (STps->rw == ST_WRITING || STp->dirty) {
STp->write_type = OS_WRITE_DATA;
osst_flush_write_buffer(STp, aSRpnt); osst_flush_write_buffer(STp, aSRpnt);
osst_flush_drive_buffer(STp, aSRpnt); osst_flush_drive_buffer(STp, aSRpnt);
} }
...@@ -919,7 +941,7 @@ static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt) ...@@ -919,7 +941,7 @@ static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name); printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
#endif #endif
SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_RETRIES, TRUE); SRpnt = osst_do_scsi(*aSRpnt, STp, cmd, 0, SCSI_DATA_NONE, STp->timeout, MAX_READ_RETRIES, TRUE);
*aSRpnt = SRpnt; *aSRpnt = SRpnt;
retval = STp->buffer->syscall_result; retval = STp->buffer->syscall_result;
} }
...@@ -937,6 +959,15 @@ static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, in ...@@ -937,6 +959,15 @@ static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, in
x, x,
position; position;
/*
* If we want just any frame (-1) and there is a frame in the buffer, return it
*/
if (frame_seq_number == -1 && STp->frame_in_buffer) {
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Frame %d still in buffer\n", name, STp->frame_seq_number);
#endif
return (STps->eof);
}
/* /*
* Search and wait for the next logical tape frame * Search and wait for the next logical tape frame
*/ */
...@@ -1090,6 +1121,7 @@ static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int ...@@ -1090,6 +1121,7 @@ static int osst_seek_logical_blk(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int
if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1; if (move < 0) move -= (OS_DATA_SIZE / STp->block_size) - 1;
move /= (OS_DATA_SIZE / STp->block_size); move /= (OS_DATA_SIZE / STp->block_size);
} }
if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG printk(OSST_DEB_MSG
"%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n", "%s:D: Seek retry %d at ppos %d fsq %d (est %d) lbn %d (need %d) move %d\n",
...@@ -1287,7 +1319,7 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** ...@@ -1287,7 +1319,7 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request **
cmd[8] = 32768 & 0xff; cmd[8] = 32768 & 0xff;
SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ, SRpnt = osst_do_scsi(SRpnt, STp, cmd, OS_FRAME_SIZE, SCSI_DATA_READ,
STp->timeout, MAX_RETRIES, TRUE); STp->timeout, MAX_READ_RETRIES, TRUE);
if ((STp->buffer)->syscall_result || !SRpnt) { if ((STp->buffer)->syscall_result || !SRpnt) {
printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name); printk(KERN_ERR "%s:E: Failed to read frame back from OnStream buffer\n", name);
...@@ -1327,7 +1359,7 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** ...@@ -1327,7 +1359,7 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request **
name, new_frame+i, frame_seq_number+i); name, new_frame+i, frame_seq_number+i);
#endif #endif
osst_set_frame_position(STp, aSRpnt, new_frame + i, 0); osst_set_frame_position(STp, aSRpnt, new_frame + i, 0);
osst_wait_ready(STp, aSRpnt, 60); osst_wait_ready(STp, aSRpnt, 60, OSST_WAIT_POSITION_COMPLETE);
osst_get_frame_position(STp, aSRpnt); osst_get_frame_position(STp, aSRpnt);
SRpnt = * aSRpnt; SRpnt = * aSRpnt;
...@@ -1395,6 +1427,7 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request ** ...@@ -1395,6 +1427,7 @@ static int osst_read_back_buffer_and_rewrite(OS_Scsi_Tape * STp, Scsi_Request **
if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 && if (SRpnt->sr_sense_buffer[2] == 2 && SRpnt->sr_sense_buffer[12] == 4 &&
(SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) { (SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) {
/* in the process of becoming ready */ /* in the process of becoming ready */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10); schedule_timeout(HZ / 10);
continue; continue;
} }
...@@ -1467,6 +1500,8 @@ static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, ...@@ -1467,6 +1500,8 @@ static int osst_reposition_and_retry(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt,
osst_set_frame_position(STp, aSRpnt, frame + skip, 1); osst_set_frame_position(STp, aSRpnt, frame + skip, 1);
flag = 0; flag = 0;
attempts--; attempts--;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
} }
if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */ if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
#if DEBUG #if DEBUG
...@@ -1909,6 +1944,7 @@ static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Reque ...@@ -1909,6 +1944,7 @@ static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Reque
if (mt_op == MTFSF) { if (mt_op == MTFSF) {
STp->frame_seq_number++; STp->frame_seq_number++;
STp->frame_in_buffer = 0; STp->frame_in_buffer = 0;
STp->buffer->read_pointer = 0;
STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt); STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
} }
return 0; return 0;
...@@ -2009,7 +2045,7 @@ static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int whe ...@@ -2009,7 +2045,7 @@ static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int whe
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where); printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
#endif #endif
osst_wait_ready(STp, aSRpnt, 60 * 5); osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
osst_set_frame_position(STp, aSRpnt, where, 0); osst_set_frame_position(STp, aSRpnt, where, 0);
STp->write_type = OS_WRITE_FILLER; STp->write_type = OS_WRITE_FILLER;
while (count--) { while (count--) {
...@@ -2035,7 +2071,7 @@ static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int w ...@@ -2035,7 +2071,7 @@ static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int w
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where); printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
#endif #endif
osst_wait_ready(STp, aSRpnt, 60 * 5); osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
osst_set_frame_position(STp, aSRpnt, where, 0); osst_set_frame_position(STp, aSRpnt, where, 0);
STp->write_type = OS_WRITE_HEADER; STp->write_type = OS_WRITE_HEADER;
while (count--) { while (count--) {
...@@ -2669,7 +2705,7 @@ static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt) ...@@ -2669,7 +2705,7 @@ static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, SCSI_DATA_READ, SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, SCSI_DATA_READ,
STp->timeout, MAX_READY_RETRIES, TRUE); STp->timeout, MAX_RETRIES, TRUE);
if (!SRpnt) { if (!SRpnt) {
STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize; STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
return (-EBUSY); return (-EBUSY);
...@@ -2690,7 +2726,7 @@ static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt) ...@@ -2690,7 +2726,7 @@ static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
scmd[0] = READ_POSITION; scmd[0] = READ_POSITION;
STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24; STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, SCSI_DATA_READ, SRpnt = osst_do_scsi(SRpnt, STp, scmd, 20, SCSI_DATA_READ,
STp->timeout, MAX_READY_RETRIES, TRUE); STp->timeout, MAX_RETRIES, TRUE);
if (!STp->buffer->syscall_result) if (!STp->buffer->syscall_result)
memcpy (SRpnt->sr_sense_buffer, mysense, 16); memcpy (SRpnt->sr_sense_buffer, mysense, 16);
} }
...@@ -2762,7 +2798,7 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in ...@@ -2762,7 +2798,7 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in
scmd[9] = 0x80; scmd[9] = 0x80;
SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout, SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout,
MAX_READY_RETRIES, TRUE); MAX_RETRIES, TRUE);
if (!SRpnt) if (!SRpnt)
return (-EBUSY); return (-EBUSY);
*aSRpnt = SRpnt; *aSRpnt = SRpnt;
...@@ -2775,7 +2811,7 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in ...@@ -2775,7 +2811,7 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in
result = (-EIO); result = (-EIO);
} }
if (pp != ppos) if (pp != ppos)
osst_wait_ready(STp, aSRpnt, 5 * 60); osst_wait_ready(STp, aSRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
} while ((pp != ppos) && (pp = ppos)); } while ((pp != ppos) && (pp = ppos));
STp->first_frame_position = STp->last_frame_position = ppos; STp->first_frame_position = STp->last_frame_position = ppos;
STps->eof = ST_NOEOF; STps->eof = ST_NOEOF;
...@@ -2932,16 +2968,17 @@ static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int see ...@@ -2932,16 +2968,17 @@ static int osst_flush_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int see
* If there was a bus reset, block further access * If there was a bus reset, block further access
* to this device. * to this device.
*/ */
if( STp->device->was_reset ) if( STp->pos_unknown)
return (-EIO); return (-EIO);
if (STp->ready != ST_READY) if (STp->ready != ST_READY)
return 0; return 0;
STps = &(STp->ps[STp->partition]); STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_WRITING) /* Writing */ if (STps->rw == ST_WRITING || STp->dirty) { /* Writing */
STp->write_type = OS_WRITE_DATA;
return osst_flush_write_buffer(STp, aSRpnt); return osst_flush_write_buffer(STp, aSRpnt);
}
if (STp->block_size == 0) if (STp->block_size == 0)
return 0; return 0;
...@@ -3063,6 +3100,43 @@ static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sync ...@@ -3063,6 +3100,43 @@ static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sync
return 0; return 0;
} }
/* Lock or unlock the drive door. Don't use when Scsi_Request allocated. */
static int do_door_lock(OS_Scsi_Tape * STp, int do_lock)
{
int retval, cmd;
cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
#if DEBUG
printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
#endif
retval = scsi_ioctl(STp->device, cmd, NULL);
if (!retval) {
STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
}
else {
STp->door_locked = ST_LOCK_FAILS;
}
return retval;
}
/* Set the internal state after reset */
static void reset_state(OS_Scsi_Tape *STp)
{
int i;
ST_partstat *STps;
STp->pos_unknown = 0;
for (i = 0; i < ST_NBR_PARTITIONS; i++) {
STps = &(STp->ps[i]);
STps->rw = ST_IDLE;
STps->eof = ST_NOEOF;
STps->at_sm = 0;
STps->last_block_valid = FALSE;
STps->drv_block = -1;
STps->drv_file = -1;
}
}
/* Entry points to osst */ /* Entry points to osst */
...@@ -3120,7 +3194,7 @@ static ssize_t osst_write(struct file * filp, const char * buf, size_t count, lo ...@@ -3120,7 +3194,7 @@ static ssize_t osst_write(struct file * filp, const char * buf, size_t count, lo
* If there was a bus reset, block further access * If there was a bus reset, block further access
* to this device. * to this device.
*/ */
if (STp->device->was_reset) { if (STp->pos_unknown) {
retval = (-EIO); retval = (-EIO);
goto out; goto out;
} }
...@@ -3154,20 +3228,22 @@ static ssize_t osst_write(struct file * filp, const char * buf, size_t count, lo ...@@ -3154,20 +3228,22 @@ static ssize_t osst_write(struct file * filp, const char * buf, size_t count, lo
goto out; goto out;
} }
STps = &(STp->ps[STp->partition]); if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
!osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
STp->door_locked = ST_LOCKED_AUTO; STp->door_locked = ST_LOCKED_AUTO;
STps = &(STp->ps[STp->partition]);
if (STps->rw == ST_READING) { if (STps->rw == ST_READING) {
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Switching from read to write at file %d, block %d\n", name,
STps->drv_file, STps->drv_block);
#endif
retval = osst_flush_buffer(STp, &SRpnt, 0); retval = osst_flush_buffer(STp, &SRpnt, 0);
if (retval) if (retval)
goto out; goto out;
STps->rw = ST_IDLE; STps->rw = ST_IDLE;
} }
else if (STps->rw != ST_WRITING) { if (STps->rw != ST_WRITING) {
/* Are we totally rewriting this tape? */ /* Are we totally rewriting this tape? */
if (!STp->header_ok || if (!STp->header_ok ||
(STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) || (STp->first_frame_position == STp->first_data_ppos && STps->drv_block < 0) ||
...@@ -3518,9 +3594,19 @@ static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *p ...@@ -3518,9 +3594,19 @@ static ssize_t osst_read(struct file * filp, char * buf, size_t count, loff_t *p
printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name, printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
STps->eof, (STp->buffer)->buffer_bytes, count - total); STps->eof, (STp->buffer)->buffer_bytes, count - total);
#endif #endif
/* force multiple of block size, note block_size may have been adjusted */
transfer = (((STp->buffer)->buffer_bytes < count - total ? transfer = (((STp->buffer)->buffer_bytes < count - total ?
(STp->buffer)->buffer_bytes : count - total)/ (STp->buffer)->buffer_bytes : count - total)/
STp->block_size) * STp->block_size; /* force multiple of block size */ STp->block_size) * STp->block_size;
if (transfer == 0) {
printk(KERN_WARNING
"%s:W: Nothing can be transfered, requested %d, tape block size (%d%c).\n",
name, count, STp->block_size < 1024?
STp->block_size:STp->block_size/1024,
STp->block_size<1024?'b':'k');
break;
}
i = from_buffer(STp->buffer, buf, transfer); i = from_buffer(STp->buffer, buf, transfer);
if (i) { if (i) {
retval = i; retval = i;
...@@ -3870,9 +3956,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -3870,9 +3956,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
} }
break; break;
case MTWEOF: case MTWEOF:
if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
STp->write_type = OS_WRITE_DATA;
ioctl_result = osst_flush_write_buffer(STp, &SRpnt); ioctl_result = osst_flush_write_buffer(STp, &SRpnt);
else } else
ioctl_result = 0; ioctl_result = 0;
#if DEBUG #if DEBUG
if (debugging) if (debugging)
...@@ -3993,26 +4080,6 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -3993,26 +4080,6 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ; fileno = blkno = at_sm = frame_seq_numbr = logical_blk_num = 0 ;
break; break;
case MTLOCK:
chg_eof = FALSE;
cmd[0] = ALLOW_MEDIUM_REMOVAL;
cmd[4] = SCSI_REMOVAL_PREVENT;
#if DEBUG
if (debugging)
printk(OSST_DEB_MSG "%s:D: Locking drive door.\n", name);
#endif
break;
case MTUNLOCK:
chg_eof = FALSE;
cmd[0] = ALLOW_MEDIUM_REMOVAL;
cmd[4] = SCSI_REMOVAL_ALLOW;
#if DEBUG
if (debugging)
printk(OSST_DEB_MSG "%s:D: Unlocking drive door.\n", name);
#endif
break;
case MTSETBLK: /* Set block length */ case MTSETBLK: /* Set block length */
case MTSETDENSITY: /* Set tape density */ case MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */ case MTSETDRVBUFFER: /* Set drive buffering */
...@@ -4070,13 +4137,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4070,13 +4137,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
STps->drv_file = fileno; STps->drv_file = fileno;
STps->at_sm = at_sm; STps->at_sm = at_sm;
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCKED_EXPLICIT;
else if (cmd_in == MTUNLOCK)
STp->door_locked = ST_UNLOCKED;
if (cmd_in == MTEOM) if (cmd_in == MTEOM)
STps->eof = ST_EOD; STps->eof = ST_EOD;
else if ((cmd_in == MTFSFM || cmd_in == MTBSF) && STps->eof == ST_FM_HIT)
ioctl_result = osst_seek_logical_blk(STp, &SRpnt, STp->logical_blk_num - 1);
else if (cmd_in == MTFSF) else if (cmd_in == MTFSF)
STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM; STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
else if (chg_eof) else if (chg_eof)
...@@ -4085,7 +4149,6 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4085,7 +4149,6 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
if (cmd_in == MTOFFL || cmd_in == MTUNLOAD) if (cmd_in == MTOFFL || cmd_in == MTUNLOAD)
STp->rew_at_close = 0; STp->rew_at_close = 0;
else if (cmd_in == MTLOAD) { else if (cmd_in == MTLOAD) {
/* STp->rew_at_close = (minor(inode->i_rdev) & 0x80) == 0; FIXME */
for (i=0; i < ST_NBR_PARTITIONS; i++) { for (i=0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE; STp->ps[i].rw = ST_IDLE;
STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */ STp->ps[i].last_block_valid = FALSE;/* FIXME - where else is this field maintained? */
...@@ -4130,11 +4193,8 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4130,11 +4193,8 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK) if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
STps->eof = ST_EOD; STps->eof = ST_EOD;
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCK_FAILS;
if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60)) if (cmd_in == MTLOAD && osst_wait_for_medium(STp, &SRpnt, 60))
ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60); ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
} }
*aSRpnt = SRpnt; *aSRpnt = SRpnt;
...@@ -4146,38 +4206,48 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i ...@@ -4146,38 +4206,48 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
static int os_scsi_tape_open(struct inode * inode, struct file * filp) static int os_scsi_tape_open(struct inode * inode, struct file * filp)
{ {
unsigned short flags; unsigned short flags;
int i, b_size, need_dma_buffer, new_session = FALSE, retval = 0; int i, b_size, new_session = FALSE, retval = 0;
unsigned char cmd[MAX_COMMAND_SIZE]; unsigned char cmd[MAX_COMMAND_SIZE];
Scsi_Request * SRpnt; Scsi_Request * SRpnt;
OS_Scsi_Tape * STp; OS_Scsi_Tape * STp;
ST_mode * STm; ST_mode * STm;
ST_partstat * STps; ST_partstat * STps;
int dev = TAPE_NR(inode->i_rdev);
char *name; char *name;
int dev = TAPE_NR(inode->i_rdev);
int mode = TAPE_MODE(inode->i_rdev); int mode = TAPE_MODE(inode->i_rdev);
if (dev >= osst_dev_max || (STp = os_scsi_tapes[dev]) == NULL || !STp->device) write_lock(&os_scsi_tapes_lock);
if (dev >= osst_max_dev || os_scsi_tapes == NULL ||
(STp = os_scsi_tapes[dev]) == NULL || !STp->device) {
write_unlock(&os_scsi_tapes_lock);
return (-ENXIO); return (-ENXIO);
}
filp->private_data = STp;
name = tape_name(STp); name = tape_name(STp);
if( !scsi_block_when_processing_errors(STp->device) ) {
return -ENXIO;
}
if (STp->in_use) { if (STp->in_use) {
write_unlock(&os_scsi_tapes_lock);
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name); printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
#endif #endif
return (-EBUSY); return (-EBUSY);
} }
if (!try_module_get(STp->device->host->hostt->module)) {
if (!try_module_get(STp->device->host->hostt->module)) write_unlock(&os_scsi_tapes_lock);
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Failed try_module_get.\n", name);
#endif
return (-ENXIO); return (-ENXIO);
}
STp->device->access_count++; STp->device->access_count++;
STp->in_use = 1; filp->private_data = STp;
STp->rew_at_close = (minor(inode->i_rdev) & 0x80) == 0; STp->in_use = 1;
write_unlock(&os_scsi_tapes_lock);
STp->rew_at_close = TAPE_REWIND(inode->i_rdev);
if( !scsi_block_when_processing_errors(STp->device) ) {
return -ENXIO;
}
if (mode != STp->current_mode) { if (mode != STp->current_mode) {
#if DEBUG #if DEBUG
...@@ -4193,10 +4263,10 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4193,10 +4263,10 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
flags = filp->f_flags; flags = filp->f_flags;
STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY);
STp->raw = (minor(inode->i_rdev) & 0x40) != 0; STp->raw = TAPE_IS_RAW(inode->i_rdev);
if (STp->raw) if (STp->raw)
STp->header_ok = 0; STp->header_ok = 0;
#if 0
/* Allocate a buffer for this user */ /* Allocate a buffer for this user */
need_dma_buffer = STp->restr_dma; need_dma_buffer = STp->restr_dma;
for (i=0; i < osst_nbr_buffers; i++) for (i=0; i < osst_nbr_buffers; i++)
...@@ -4213,9 +4283,16 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4213,9 +4283,16 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
} }
else else
STp->buffer = osst_buffers[i]; STp->buffer = osst_buffers[i];
(STp->buffer)->in_use = 1; #endif /* now pre_allocated */
/* Allocate data segments for this device's tape buffer */
if (!enlarge_buffer(STp->buffer, STp->restr_dma)) {
printk(KERN_ERR "%s:E: Unable to allocate memory segments for tape buffer.\n", name);
retval = (-EOVERFLOW);
goto err_out;
}
(STp->buffer)->writing = 0; (STp->buffer)->writing = 0;
(STp->buffer)->syscall_result = 0; (STp->buffer)->syscall_result = 0;
#if 0
(STp->buffer)->use_sg = STp->device->host->sg_tablesize; (STp->buffer)->use_sg = STp->device->host->sg_tablesize;
/* Compute the usable buffer size for this SCSI adapter */ /* Compute the usable buffer size for this SCSI adapter */
...@@ -4226,7 +4303,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4226,7 +4303,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
i < (STp->buffer)->sg_segs; i++) i < (STp->buffer)->sg_segs; i++)
(STp->buffer)->buffer_size += (STp->buffer)->sg[i].length; (STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
} }
#endif
STp->dirty = 0; STp->dirty = 0;
for (i=0; i < ST_NBR_PARTITIONS; i++) { for (i=0; i < ST_NBR_PARTITIONS; i++) {
STps = &(STp->ps[i]); STps = &(STp->ps[i]);
...@@ -4251,6 +4328,10 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4251,6 +4328,10 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]); printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]);
#endif #endif
if (filp->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
goto err_out;
}
if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */ if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */
memset (cmd, 0, MAX_COMMAND_SIZE); memset (cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = START_STOP; cmd[0] = START_STOP;
...@@ -4259,7 +4340,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4259,7 +4340,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE, SRpnt = osst_do_scsi(SRpnt, STp, cmd, 0, SCSI_DATA_NONE,
STp->timeout, MAX_READY_RETRIES, TRUE); STp->timeout, MAX_READY_RETRIES, TRUE);
} }
osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60); osst_wait_ready(STp, &SRpnt, (SRpnt->sr_sense_buffer[13]==1?15:3) * 60, 0);
} }
if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 && if ((SRpnt->sr_sense_buffer[0] & 0x70) == 0x70 &&
(SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ (SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */
...@@ -4280,7 +4361,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4280,7 +4361,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
break; break;
} }
STp->device->was_reset = 0; STp->pos_unknown = 0;
STp->partition = STp->new_partition = 0; STp->partition = STp->new_partition = 0;
if (STp->can_partitions) if (STp->can_partitions)
STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
...@@ -4388,7 +4469,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4388,7 +4469,7 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
break; break;
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
STp->device->was_reset = 0; STp->pos_unknown = 0;
STp->partition = STp->new_partition = 0; STp->partition = STp->new_partition = 0;
if (STp->can_partitions) if (STp->can_partitions)
STp->nbr_partitions = 1; /* This guess will be updated later if necessary */ STp->nbr_partitions = 1; /* This guess will be updated later if necessary */
...@@ -4406,8 +4487,8 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4406,8 +4487,8 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
} }
} }
if (osst_wait_ready(STp, &SRpnt, 15 * 60)) /* FIXME - not allowed with NOBLOCK */ if (osst_wait_ready(STp, &SRpnt, 15 * 60, 0)) /* FIXME - not allowed with NOBLOCK */
printk(KERN_INFO "%s:I: Device did not become Ready in open\n",name); printk(KERN_INFO "%s:I: Device did not become Ready in open\n", name);
if ((STp->buffer)->syscall_result != 0) { if ((STp->buffer)->syscall_result != 0) {
if ((STp->device)->scsi_level >= SCSI_2 && if ((STp->device)->scsi_level >= SCSI_2 &&
...@@ -4430,19 +4511,9 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4430,19 +4511,9 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
osst_configure_onstream(STp, &SRpnt); osst_configure_onstream(STp, &SRpnt);
/* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */ if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
if (OS_FRAME_SIZE > (STp->buffer)->buffer_size &&
!enlarge_buffer(STp->buffer, OS_FRAME_SIZE, STp->restr_dma)) {
printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name,
OS_FRAME_SIZE);
retval = (-EIO);
goto err_out;
}
if ((STp->buffer)->buffer_size >= OS_FRAME_SIZE) {
for (i = 0, b_size = 0; for (i = 0, b_size = 0;
i < STp->buffer->sg_segs && (b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE; (i < STp->buffer->sg_segs) && ((b_size + STp->buffer->sg[i].length) <= OS_DATA_SIZE);
b_size += STp->buffer->sg[i++].length); b_size += STp->buffer->sg[i++].length);
STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size); STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
#if DEBUG #if DEBUG
...@@ -4451,8 +4522,12 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4451,8 +4522,12 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name, printk(OSST_DEB_MSG "%s:D: AUX points to %p in segment %d at %p\n", name,
STp->buffer->aux, i, page_address(STp->buffer->sg[i].page)); STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
#endif #endif
} else } else {
STp->buffer->aux = NULL; /* this had better never happen! */ STp->buffer->aux = NULL; /* this had better never happen! */
printk(KERN_NOTICE "%s:A: Framesize %d too large for buffer.\n", name, OS_FRAME_SIZE);
retval = (-EIO);
goto err_out;
}
STp->block_size = STp->raw ? OS_FRAME_SIZE : ( STp->block_size = STp->raw ? OS_FRAME_SIZE : (
(STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE); (STm->default_blksize > 0) ? STm->default_blksize : OS_DATA_SIZE);
...@@ -4509,12 +4584,9 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp) ...@@ -4509,12 +4584,9 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
err_out: err_out:
if (SRpnt != NULL) if (SRpnt != NULL)
scsi_release_request(SRpnt); scsi_release_request(SRpnt);
if (STp->buffer != NULL) { normalize_buffer(STp->buffer);
STp->buffer->in_use = 0;
STp->buffer = NULL;
}
STp->in_use = 0;
STp->header_ok = 0; STp->header_ok = 0;
STp->in_use = 0;
STp->device->access_count--; STp->device->access_count--;
module_put(STp->device->host->hostt->module); module_put(STp->device->host->hostt->module);
...@@ -4536,12 +4608,13 @@ static int os_scsi_tape_flush(struct file * filp) ...@@ -4536,12 +4608,13 @@ static int os_scsi_tape_flush(struct file * filp)
if (file_count(filp) > 1) if (file_count(filp) > 1)
return 0; return 0;
if ( STps->rw == ST_WRITING && !(STp->device)->was_reset) { if ((STps->rw == ST_WRITING || STp->dirty) && !STp->pos_unknown) {
STp->write_type = OS_WRITE_DATA;
result = osst_flush_write_buffer(STp, &SRpnt); result = osst_flush_write_buffer(STp, &SRpnt);
if (result != 0 && result != (-ENOSPC)) if (result != 0 && result != (-ENOSPC))
goto out; goto out;
} }
if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) { if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
#if DEBUG #if DEBUG
if (debugging) { if (debugging) {
...@@ -4632,17 +4705,18 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp) ...@@ -4632,17 +4705,18 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
OS_Scsi_Tape * STp = filp->private_data; OS_Scsi_Tape * STp = filp->private_data;
Scsi_Request * SRpnt = NULL; Scsi_Request * SRpnt = NULL;
if (STp->door_locked == ST_LOCKED_AUTO)
osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0);
if (SRpnt) scsi_release_request(SRpnt); if (SRpnt) scsi_release_request(SRpnt);
if (STp->buffer != NULL) if (STp->door_locked == ST_LOCKED_AUTO)
STp->buffer->in_use = 0; do_door_lock(STp, 0);
if (STp->raw) if (STp->raw)
STp->header_ok = 0; STp->header_ok = 0;
normalize_buffer(STp->buffer);
write_lock(&os_scsi_tapes_lock);
STp->in_use = 0; STp->in_use = 0;
write_unlock(&os_scsi_tapes_lock);
STp->device->access_count--; STp->device->access_count--;
module_put(STp->device->host->hostt->module); module_put(STp->device->host->hostt->module);
...@@ -4718,7 +4792,7 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4718,7 +4792,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
goto out; goto out;
} }
if (!(STp->device)->was_reset) { if (!STp->pos_unknown) {
if (STps->eof == ST_FM_HIT) { if (STps->eof == ST_FM_HIT) {
if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) { if (mtc.mt_op == MTFSF || mtc.mt_op == MTFSFM|| mtc.mt_op == MTEOM) {
...@@ -4764,15 +4838,9 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4764,15 +4838,9 @@ static int osst_ioctl(struct inode * inode,struct file * file,
retval = (-EIO); retval = (-EIO);
goto out; goto out;
} }
reset_state(STp);
/* remove this when the midlevel properly clears was_reset */
STp->device->was_reset = 0; STp->device->was_reset = 0;
if (STp->door_locked != ST_UNLOCKED &&
STp->door_locked != ST_LOCK_FAILS) {
if (osst_int_ioctl(STp, &SRpnt, MTLOCK, 0)) {
printk(KERN_NOTICE "%s:I: Could not relock door after bus reset.\n",
name);
STp->door_locked = ST_UNLOCKED;
}
}
} }
if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM && if (mtc.mt_op != MTNOP && mtc.mt_op != MTWEOF && mtc.mt_op != MTWSM &&
...@@ -4781,7 +4849,7 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4781,7 +4849,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */ STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED) if (mtc.mt_op == MTOFFL && STp->door_locked != ST_UNLOCKED)
osst_int_ioctl(STp, &SRpnt, MTUNLOCK, 0); /* Ignore result! */ do_door_lock(STp, 0); /* Ignore result! */
if (mtc.mt_op == MTSETDRVBUFFER && if (mtc.mt_op == MTSETDRVBUFFER &&
(mtc.mt_count & MT_ST_OPTIONS) != 0) { (mtc.mt_count & MT_ST_OPTIONS) != 0) {
...@@ -4837,7 +4905,12 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4837,7 +4905,12 @@ static int osst_ioctl(struct inode * inode,struct file * file,
retval = i; retval = i;
goto out; goto out;
} }
if (mtc.mt_op == MTLOCK || mtc.mt_op == MTUNLOCK) {
retval = do_door_lock(STp, (mtc.mt_op == MTLOCK));
goto out;
}
/* if (STp->can_partitions && STp->ready == ST_READY && /* if (STp->can_partitions && STp->ready == ST_READY &&
(i = update_partition(inode)) < 0) (i = update_partition(inode)) < 0)
{retval=i;goto out;}*/ {retval=i;goto out;}*/
...@@ -4967,15 +5040,12 @@ static int osst_ioctl(struct inode * inode,struct file * file, ...@@ -4967,15 +5040,12 @@ static int osst_ioctl(struct inode * inode,struct file * file,
/* Memory handling routines */ /* Memory handling routines */
/* Try to allocate a new tape buffer */ /* Try to allocate a new tape buffer skeleton. Caller must not hold os_scsi_tapes_lock */
static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma ) static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma, int max_sg )
{ {
int i, priority, b_size, order, got = 0, segs = 0; int i, priority;
OSST_buffer *tb; OSST_buffer *tb;
if (osst_nbr_buffers >= osst_dev_max)
return NULL; /* Should never happen */
if (from_initialization) if (from_initialization)
priority = GFP_ATOMIC; priority = GFP_ATOMIC;
else else
...@@ -4983,144 +5053,94 @@ static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma ) ...@@ -4983,144 +5053,94 @@ static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma )
i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist); i = sizeof(OSST_buffer) + (osst_max_sg_segs - 1) * sizeof(struct scatterlist);
tb = (OSST_buffer *)kmalloc(i, priority); tb = (OSST_buffer *)kmalloc(i, priority);
if (tb) {
// tb->this_size = i;
if (need_dma)
priority |= GFP_DMA;
/* Try to allocate the first segment up to OSST_FIRST_ORDER and the
others big enough to reach the goal */
for (b_size = PAGE_SIZE, order = 0;
b_size < osst_buffer_size && order < OSST_FIRST_ORDER;
b_size *= 2, order++ );
for ( ; b_size >= PAGE_SIZE; order--, b_size /= 2) {
tb->sg[0].page = alloc_pages(priority, order);
tb->sg[0].offset = 0;
if (tb->sg[0].page != NULL) {
tb->sg[0].length = b_size;
break;
}
}
if (tb->sg[segs].page == NULL) {
kfree(tb);
tb = NULL;
}
else { /* Got something, continue */
for (b_size = PAGE_SIZE, order = 0;
osst_buffer_size > tb->sg[0].length + (OSST_FIRST_SG - 1) * b_size;
b_size *= 2, order++ );
for (segs=1, got=tb->sg[0].length;
got < osst_buffer_size && segs < OSST_FIRST_SG; ) {
tb->sg[segs].page = alloc_pages(priority, order);
tb->sg[segs].offset = 0;
if (tb->sg[segs].page == NULL) {
if (osst_buffer_size - got <=
(OSST_FIRST_SG - segs) * b_size / 2) {
b_size /= 2; /* Large enough for the rest of the buffers */
order--;
continue;
}
tb->sg_segs = segs;
tb->orig_sg_segs = 0;
#if DEBUG
tb->buffer_size = got;
#endif
normalize_buffer(tb);
kfree(tb);
tb = NULL;
break;
}
tb->sg[segs].page = NULL;
tb->sg[segs].length = b_size;
got += b_size;
segs++;
}
}
}
if (!tb) { if (!tb) {
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer (nbr %d).\n", printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
osst_nbr_buffers);
return NULL; return NULL;
} }
tb->sg_segs = tb->orig_sg_segs = segs; memset(tb, 0, i);
tb->b_data = page_address(tb->sg[0].page); tb->sg_segs = tb->orig_sg_segs = 0;
tb->use_sg = max_sg;
tb->in_use = TRUE;
tb->dma = need_dma;
tb->buffer_size = 0;
#if DEBUG #if DEBUG
if (debugging) { if (debugging)
printk(OSST_DEB_MSG
"osst :D: Allocated tape buffer %d (%d bytes, %d segments, dma: %d, a: %p).\n",
osst_nbr_buffers, got, tb->sg_segs, need_dma, tb->b_data);
printk(OSST_DEB_MSG printk(OSST_DEB_MSG
"osst :D: segment sizes: first %d, last %d bytes.\n", "osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
tb->sg[0].length, tb->sg[segs-1].length); i, max_sg, need_dma);
}
#endif #endif
tb->in_use = 0;
tb->dma = need_dma;
tb->buffer_size = got;
tb->writing = 0;
osst_buffers[osst_nbr_buffers++] = tb;
return tb; return tb;
} }
/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
/* Try to allocate a temporary enlarged tape buffer */ static int enlarge_buffer(OSST_buffer *STbuffer, int need_dma)
static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma)
{ {
int segs, nbr, max_segs, b_size, priority, order, got; int segs, nbr, max_segs, b_size, priority, order, got;
normalize_buffer(STbuffer); if (STbuffer->buffer_size >= OS_FRAME_SIZE)
return TRUE;
max_segs = STbuffer->use_sg; if (STbuffer->sg_segs) {
if (max_segs > osst_max_sg_segs) printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
max_segs = osst_max_sg_segs; normalize_buffer(STbuffer);
nbr = max_segs - STbuffer->sg_segs; }
if (nbr <= 0) /* See how many segments we can use -- need at least two */
nbr = max_segs = STbuffer->use_sg;
if (nbr <= 2)
return FALSE; return FALSE;
priority = GFP_KERNEL; priority = GFP_KERNEL;
if (need_dma) if (need_dma)
priority |= GFP_DMA; priority |= GFP_DMA;
for (b_size = PAGE_SIZE, order = 0;
b_size * nbr < new_size - STbuffer->buffer_size;
b_size *= 2, order++);
for (segs=STbuffer->sg_segs, got=STbuffer->buffer_size; /* Try to allocate the first segment up to OS_DATA_SIZE and the others
segs < max_segs && got < new_size; ) { big enough to reach the goal (code assumes no segments in place) */
STbuffer->sg[segs].page = alloc_pages(priority, order); for (b_size = OS_DATA_SIZE, order = OSST_FIRST_ORDER; b_size >= PAGE_SIZE; order--, b_size /= 2) {
STbuffer->sg[0].page = alloc_pages(priority, order);
STbuffer->sg[0].offset = 0;
if (STbuffer->sg[0].page != NULL) {
STbuffer->sg[0].length = b_size;
STbuffer->b_data = page_address(STbuffer->sg[0].page);
break;
}
}
if (STbuffer->sg[0].page == NULL) {
printk(KERN_NOTICE "osst :I: Can't allocate tape buffer main segment.\n");
return FALSE;
}
/* Got initial segment of 'bsize,order', continue with same size if possible, except for AUX */
for (segs=STbuffer->sg_segs=1, got=b_size;
segs < max_segs && got < OS_FRAME_SIZE; ) {
STbuffer->sg[segs].page =
(OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ?
kmalloc(OS_FRAME_SIZE - got, priority):
alloc_pages(priority, order);
STbuffer->sg[segs].offset = 0; STbuffer->sg[segs].offset = 0;
if (STbuffer->sg[segs].page == NULL) { if (STbuffer->sg[segs].page == NULL) {
if (new_size - got <= (max_segs - segs) * b_size / 2) { if (OS_FRAME_SIZE - got <= (max_segs - segs) * b_size / 2 && order) {
b_size /= 2; /* Large enough for the rest of the buffers */ b_size /= 2; /* Large enough for the rest of the buffers */
order--; order--;
continue; continue;
} }
printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n", printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
new_size); OS_FRAME_SIZE);
#if DEBUG #if DEBUG
STbuffer->buffer_size = got; STbuffer->buffer_size = got;
#endif #endif
normalize_buffer(STbuffer); normalize_buffer(STbuffer);
return FALSE; return FALSE;
} }
STbuffer->sg[segs].page = NULL; STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
STbuffer->sg[segs].length = b_size; got += STbuffer->sg[segs].length;
STbuffer->sg_segs += 1;
got += b_size;
STbuffer->buffer_size = got; STbuffer->buffer_size = got;
segs++; STbuffer->sg_segs = ++segs;
} }
#if DEBUG #if DEBUG
if (debugging) { if (debugging) {
for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++); printk(OSST_DEB_MSG
printk(OSST_DEB_MSG "osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
"osst :D: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n", got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data); printk(OSST_DEB_MSG
printk(OSST_DEB_MSG
"osst :D: segment sizes: first %d, last %d bytes.\n", "osst :D: segment sizes: first %d, last %d bytes.\n",
STbuffer->sg[0].length, STbuffer->sg[segs-1].length); STbuffer->sg[0].length, STbuffer->sg[segs-1].length);
} }
...@@ -5130,12 +5150,12 @@ static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma) ...@@ -5130,12 +5150,12 @@ static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma)
} }
/* Release the extra buffer */ /* Release the segments */
static void normalize_buffer(OSST_buffer *STbuffer) static void normalize_buffer(OSST_buffer *STbuffer)
{ {
int i, order, b_size; int i, order, b_size;
for (i=STbuffer->orig_sg_segs; i < STbuffer->sg_segs; i++) { for (i=0; i < STbuffer->sg_segs; i++) {
for (b_size = PAGE_SIZE, order = 0; for (b_size = PAGE_SIZE, order = 0;
b_size < STbuffer->sg[i].length; b_size < STbuffer->sg[i].length;
...@@ -5149,7 +5169,7 @@ static void normalize_buffer(OSST_buffer *STbuffer) ...@@ -5149,7 +5169,7 @@ static void normalize_buffer(OSST_buffer *STbuffer)
printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n", printk(OSST_DEB_MSG "osst :D: Buffer at %p normalized to %d bytes (segs %d).\n",
STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs); STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
#endif #endif
STbuffer->sg_segs = STbuffer->orig_sg_segs; STbuffer->sg_segs = STbuffer->orig_sg_segs = 0;
} }
...@@ -5293,19 +5313,17 @@ static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr) ...@@ -5293,19 +5313,17 @@ static int osst_copy_from_buffer(OSST_buffer *st_bp, unsigned char *ptr)
static void validate_options (void) static void validate_options (void)
{ {
if (buffer_kbs > 0) if (max_dev > 0)
osst_buffer_size = buffer_kbs * ST_KILOBYTE; osst_max_dev = max_dev;
if (write_threshold_kbs > 0) if (write_threshold_kbs > 0)
osst_write_threshold = write_threshold_kbs * ST_KILOBYTE; osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
if (osst_write_threshold > osst_buffer_size) if (osst_write_threshold > osst_buffer_size)
osst_write_threshold = osst_buffer_size; osst_write_threshold = osst_buffer_size;
if (max_buffers > 0)
osst_max_buffers = max_buffers;
if (max_sg_segs >= OSST_FIRST_SG) if (max_sg_segs >= OSST_FIRST_SG)
osst_max_sg_segs = max_sg_segs; osst_max_sg_segs = max_sg_segs;
#if DEBUG #if DEBUG
printk(OSST_DEB_MSG "osst :D: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n", printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, s/g segs %d.\n",
osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs); osst_max_dev, osst_write_threshold, osst_max_sg_segs);
//printk(OSST_DEB_MSG "osst :D: sizeof(header) = %d (%s)\n", //printk(OSST_DEB_MSG "osst :D: sizeof(header) = %d (%s)\n",
// sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error"); // sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
#endif #endif
...@@ -5313,8 +5331,8 @@ static void validate_options (void) ...@@ -5313,8 +5331,8 @@ static void validate_options (void)
#ifndef MODULE #ifndef MODULE
/* Set the boot options. Syntax: osst=xxx,yyy,... /* Set the boot options. Syntax: osst=xxx,yyy,...
where xxx is buffer size in 1024 byte blocks and yyy is write threshold where xxx is write threshold in 1024 byte blocks,
in 1024 byte blocks. */ and yyy is number of s/g segments to use. */
static int __init osst_setup (char *str) static int __init osst_setup (char *str)
{ {
int i, ints[5]; int i, ints[5];
...@@ -5352,14 +5370,30 @@ __setup("osst=", osst_setup); ...@@ -5352,14 +5370,30 @@ __setup("osst=", osst_setup);
#endif #endif
/* Driverfs file support */
static ssize_t osst_device_kdev_read(struct device *driverfs_dev, char *page, size_t count, loff_t off)
{
kdev_t kdev;
kdev.value=(int)(long)driverfs_dev->driver_data;
return off ? 0 : sprintf(page, "%x\n",kdev.value);
}
static DEVICE_ATTR(kdev,S_IRUGO,osst_device_kdev_read,NULL);
static ssize_t osst_device_type_read(struct device *driverfs_dev, char *page, size_t count, loff_t off)
{
return off ? 0 : sprintf (page, "CHR\n");
}
static DEVICE_ATTR(type,S_IRUGO,osst_device_type_read,NULL);
static struct file_operations osst_fops = { static struct file_operations osst_fops = {
.read = osst_read, .owner = THIS_MODULE,
.write = osst_write, .read = osst_read,
.ioctl = osst_ioctl, .write = osst_write,
.open = os_scsi_tape_open, .ioctl = osst_ioctl,
.flush = os_scsi_tape_flush, .open = os_scsi_tape_open,
.release = os_scsi_tape_close, .flush = os_scsi_tape_flush,
.release = os_scsi_tape_close,
}; };
static int osst_supports(Scsi_Device * SDp) static int osst_supports(Scsi_Device * SDp)
...@@ -5390,102 +5424,93 @@ static struct osst_support_data support_list[] = { ...@@ -5390,102 +5424,93 @@ static struct osst_support_data support_list[] = {
return 0; return 0;
} }
/*
* osst startup / cleanup code
*/
static int osst_attach(Scsi_Device * SDp) static int osst_attach(Scsi_Device * SDp)
{ {
OS_Scsi_Tape * tpnt; OS_Scsi_Tape * tpnt;
ST_mode * STm; ST_mode * STm;
ST_partstat * STps; ST_partstat * STps;
int i, dev; OSST_buffer *buffer;
struct gendisk *disk; struct gendisk *drive;
#ifdef CONFIG_DEVFS_FS int i, mode, dev_num;
int mode;
#endif
if (SDp->type != TYPE_TAPE || !osst_supports(SDp)) if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
return 1;
osst_init();
disk = alloc_disk(1);
if (!disk)
return 1; return 1;
if (osst_nr_dev >= osst_dev_max) { if (scsi_slave_attach(SDp)) {
put_disk(disk); printk(KERN_ERR "osst :E: Failed to attach scsi slave.\n");
return 1; return 1;
} }
if (scsi_slave_attach(SDp)) drive = alloc_disk(1);
if (!drive) {
printk(KERN_ERR "osst :E: Out of memory. Device not attached.\n");
return 1; return 1;
}
/* if this is the first attach, build the infrastructure */
write_lock(&os_scsi_tapes_lock);
if (os_scsi_tapes == NULL) {
os_scsi_tapes =
(OS_Scsi_Tape **)kmalloc(osst_max_dev * sizeof(OS_Scsi_Tape *),
GFP_ATOMIC);
if (os_scsi_tapes == NULL) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Unable to allocate array for OnStream SCSI tapes.\n");
return 1;
}
for (i=0; i < osst_max_dev; ++i) os_scsi_tapes[i] = NULL;
}
if (osst_nr_dev >= osst_max_dev) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Too many tape devices (max. %d).\n", osst_max_dev);
put_disk(drive);
return 1;
}
/* find a free minor number */ /* find a free minor number */
for (i=0; os_scsi_tapes[i] && i<osst_dev_max; i++); for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
if(i >= osst_dev_max) panic ("Scsi_devices corrupt (osst)"); if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
dev_num = i;
/* allocate a OS_Scsi_Tape for this device */ /* allocate a OS_Scsi_Tape for this device */
tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC); tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
if (tpnt == NULL) { if (tpnt == NULL) {
printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n"); write_unlock(&os_scsi_tapes_lock);
put_disk(disk); printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
put_disk(drive);
scsi_slave_detach(SDp); scsi_slave_detach(SDp);
return 1; return 1;
} }
memset(tpnt, 0, sizeof(OS_Scsi_Tape)); memset(tpnt, 0, sizeof(OS_Scsi_Tape));
os_scsi_tapes[i] = tpnt;
dev = i;
tpnt->capacity = 0xfffff;
/* allocate a buffer for this device */ /* allocate a buffer for this device */
if (!new_tape_buffer(TRUE, TRUE)) i = SDp->host->sg_tablesize;
printk(KERN_ERR "osst :W: Unable to allocate a tape buffer.\n"); if (osst_max_sg_segs < i)
i = osst_max_sg_segs;
#ifdef CONFIG_DEVFS_FS buffer = new_tape_buffer(TRUE, SDp->host->unchecked_isa_dma, i);
for (mode = 0; mode < ST_NBR_MODES; ++mode) { if (buffer == NULL) {
char name[8]; write_unlock(&os_scsi_tapes_lock);
static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"}; printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
kfree(tpnt);
/* Rewind entry */ put_disk(drive);
sprintf (name, "mt%s", formats[mode]); scsi_slave_detach(SDp);
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) return 1;
tpnt->de_r[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5),
S_IFCHR | S_IRUGO | S_IWUGO,
&osst_fops, NULL);
# else
tpnt->de_r[mode] =
devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5),
S_IFCHR | S_IRUGO | S_IWUGO,
0, 0, &osst_fops, NULL);
# endif
/* No-rewind entry */
sprintf (name, "mt%sn", formats[mode]);
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
tpnt->de_n[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5) + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
&osst_fops, NULL);
# else
tpnt->de_n[mode] =
devfs_register (SDp->de, name, 0, DEVFS_FL_DEFAULT,
MAJOR_NR, i + (mode << 5) + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
0, 0, &osst_fops, NULL);
# endif
} }
disk->number = devfs_register_tape(SDp->de); os_scsi_tapes[dev_num] = tpnt;
#endif tpnt->buffer = buffer;
tpnt->device = SDp; tpnt->device = SDp;
disk->private_data = &tpnt->driver; drive->private_data = &tpnt->driver;
sprintf(disk->disk_name, "osst%d", i); sprintf(drive->disk_name, "osst%d", dev_num);
tpnt->driver = &osst_template; tpnt->driver = &osst_template;
tpnt->disk = disk; tpnt->drive = drive;
tpnt->dirty = 0;
tpnt->in_use = 0; tpnt->in_use = 0;
tpnt->capacity = 0xfffff;
tpnt->dirty = 0;
tpnt->drv_buffer = 1; /* Try buffering if no mode sense */ tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
tpnt->restr_dma = (SDp->host)->unchecked_isa_dma; tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
tpnt->density = 0; tpnt->density = 0;
...@@ -5510,7 +5535,8 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5510,7 +5535,8 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev); tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
tpnt->omit_blklims = 1; tpnt->omit_blklims = 1;
tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp); tpnt->poll = (strncmp(SDp->model, "DI-", 3) == 0) ||
(strncmp(SDp->model, "FW-", 3) == 0) || OSST_FW_NEED_POLL(tpnt->os_fw_rev,SDp);
tpnt->frame_in_buffer = 0; tpnt->frame_in_buffer = 0;
tpnt->header_ok = 0; tpnt->header_ok = 0;
tpnt->linux_media = 0; tpnt->linux_media = 0;
...@@ -5543,9 +5569,56 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5543,9 +5569,56 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->modes[0].defined = TRUE; tpnt->modes[0].defined = TRUE;
tpnt->modes[2].defined = TRUE; tpnt->modes[2].defined = TRUE;
tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE; tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
init_MUTEX(&tpnt->lock);
init_MUTEX(&tpnt->lock);
osst_nr_dev++; osst_nr_dev++;
write_unlock(&os_scsi_tapes_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
/* Rewind entry */
sprintf (name, "ot%s", formats[mode]);
sprintf(tpnt->driverfs_dev_r[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.bus_id, name);
sprintf(tpnt->driverfs_dev_r[mode].name, "%s%s",
SDp->sdev_driverfs_dev.name, name);
tpnt->driverfs_dev_r[mode].parent = &SDp->sdev_driverfs_dev;
tpnt->driverfs_dev_r[mode].bus = &scsi_driverfs_bus_type;
tpnt->driverfs_dev_r[mode].driver_data =
(void *)(long)__mkdev(MAJOR_NR, dev_num + (mode << 5));
device_register(&tpnt->driverfs_dev_r[mode]);
device_create_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_r[mode], &dev_attr_kdev);
tpnt->de_r[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, dev_num + (mode << 5),
S_IFCHR | S_IRUGO | S_IWUGO,
&osst_fops, NULL);
/* No-rewind entry */
sprintf (name, "ot%sn", formats[mode]);
sprintf(tpnt->driverfs_dev_n[mode].bus_id, "%s:%s",
SDp->sdev_driverfs_dev.bus_id, name);
sprintf(tpnt->driverfs_dev_n[mode].name, "%s%s",
SDp->sdev_driverfs_dev.name, name);
tpnt->driverfs_dev_n[mode].parent= &SDp->sdev_driverfs_dev;
tpnt->driverfs_dev_n[mode].bus = &scsi_driverfs_bus_type;
tpnt->driverfs_dev_n[mode].driver_data =
(void *)(long)__mkdev(MAJOR_NR, dev_num + (mode << 5) + 128);
device_register(&tpnt->driverfs_dev_n[mode]);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_create_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
tpnt->de_n[mode] =
devfs_register (SDp->de, name, DEVFS_FL_DEFAULT,
MAJOR_NR, dev_num + (mode << 5) + 128,
S_IFCHR | S_IRUGO | S_IWUGO,
&osst_fops, NULL);
}
drive->number = devfs_register_tape (SDp->de);
printk(KERN_INFO printk(KERN_INFO
"osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n", "osst :I: Attached OnStream %.5s tape at scsi%d, channel %d, id %d, lun %d as %s\n",
...@@ -5554,94 +5627,71 @@ static int osst_attach(Scsi_Device * SDp) ...@@ -5554,94 +5627,71 @@ static int osst_attach(Scsi_Device * SDp)
return 0; return 0;
}; };
static int osst_registered = 0;
/* Driver initialization (not __initfunc because may be called later) */
static int osst_init()
{
int i;
if (!osst_registered) {
if (register_chrdev(MAJOR_NR,"osst",&osst_fops)) {
printk(KERN_ERR "osst :W: Unable to get major %d for OnStream tapes\n",MAJOR_NR);
return 1;
}
osst_registered++;
}
if (os_scsi_tapes)
return 0;
osst_dev_max = OSST_MAX_TAPES;
if (osst_dev_max > 128 / ST_NBR_MODES)
printk(KERN_INFO "osst :I: Only %d tapes accessible.\n", 128 / ST_NBR_MODES);
os_scsi_tapes = kmalloc(osst_dev_max * sizeof(OS_Scsi_Tape *),
GFP_ATOMIC);
if (!os_scsi_tapes) {
printk(KERN_ERR "osst :W: Unable to allocate array for OnStream SCSI tapes.\n");
unregister_chrdev(MAJOR_NR, "osst");
return 1;
}
for (i=0; i < osst_dev_max; ++i)
os_scsi_tapes[i] = NULL;
/* Allocate the buffer pointers */
osst_buffers = kmalloc(osst_dev_max * sizeof(OSST_buffer *),
GFP_ATOMIC);
if (!osst_buffers) {
printk(KERN_ERR "osst :W: Unable to allocate tape buffer pointers.\n");
unregister_chrdev(MAJOR_NR, "osst");
kfree(os_scsi_tapes);
return 1;
}
osst_nbr_buffers = 0;
printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
#if DEBUG
printk(OSST_DEB_MSG "osst :D: Buffer size %d bytes, write threshold %d bytes.\n",
osst_buffer_size, osst_write_threshold);
#endif
return 0;
}
static void osst_detach(Scsi_Device * SDp) static void osst_detach(Scsi_Device * SDp)
{ {
OS_Scsi_Tape * tpnt; OS_Scsi_Tape * tpnt;
int i; int i, mode;
#ifdef CONFIG_DEVFS_FS
int mode;
#endif
for(i=0; i<osst_dev_max; i++) { write_lock(&os_scsi_tapes_lock);
for(i=0; i<osst_max_dev; i++) {
tpnt = os_scsi_tapes[i]; tpnt = os_scsi_tapes[i];
if(tpnt != NULL && tpnt->device == SDp) { if(tpnt != NULL && tpnt->device == SDp) {
tpnt->device = NULL; tpnt->device = NULL;
#ifdef CONFIG_DEVFS_FS
for (mode = 0; mode < ST_NBR_MODES; ++mode) { for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_unregister (tpnt->de_r[mode]); devfs_unregister (tpnt->de_r[mode]);
tpnt->de_r[mode] = NULL; tpnt->de_r[mode] = NULL;
devfs_unregister (tpnt->de_n[mode]); devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL; tpnt->de_n[mode] = NULL;
} }
devfs_unregister_tape(tpnt->disk->number); devfs_unregister_tape(tpnt->drive->number);
#endif put_disk(tpnt->drive);
put_disk(tpnt->disk);
kfree(tpnt);
os_scsi_tapes[i] = NULL; os_scsi_tapes[i] = NULL;
scsi_slave_detach(SDp); scsi_slave_detach(SDp);
osst_nr_dev--; osst_nr_dev--;
write_unlock(&os_scsi_tapes_lock);
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_r[mode],
&dev_attr_kdev);
device_unregister(&tpnt->driverfs_dev_r[mode]);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_type);
device_remove_file(&tpnt->driverfs_dev_n[mode],
&dev_attr_kdev);
device_unregister(&tpnt->driverfs_dev_n[mode]);
}
if (tpnt->header_cache != NULL) vfree(tpnt->header_cache);
if (tpnt->buffer) {
normalize_buffer(tpnt->buffer);
kfree(tpnt->buffer);
}
kfree(tpnt);
return; return;
} }
} }
write_unlock(&os_scsi_tapes_lock);
return; return;
} }
static int __init init_osst(void) static int __init init_osst(void)
{ {
printk(KERN_INFO "osst :I: Tape driver with OnStream support version %s\nosst :I: %s\n", osst_version, cvsid);
validate_options(); validate_options();
return scsi_register_device(&osst_template); #if DEBUG
printk(OSST_DEB_MSG "osst :D: %d s/g segments, write threshold %d bytes.\n",
max_sg_segs, osst_write_threshold);
#endif
if ((register_chrdev(MAJOR_NR,"osst",&osst_fops) < 0) || scsi_register_device(&osst_template)) {
printk(KERN_ERR "osst :E: Unable to register major %d for OnStream tapes\n",MAJOR_NR);
return 1;
}
osst_template.scsi_driverfs_driver.name = (char *)osst_template.tag;
osst_template.scsi_driverfs_driver.bus = &scsi_driverfs_bus_type;
driver_register(&osst_template.scsi_driverfs_driver);
return 0;
} }
static void __exit exit_osst (void) static void __exit exit_osst (void)
...@@ -5651,31 +5701,23 @@ static void __exit exit_osst (void) ...@@ -5651,31 +5701,23 @@ static void __exit exit_osst (void)
scsi_unregister_device(&osst_template); scsi_unregister_device(&osst_template);
unregister_chrdev(MAJOR_NR, "osst"); unregister_chrdev(MAJOR_NR, "osst");
osst_registered--; driver_unregister(&osst_template.scsi_driverfs_driver);
if (os_scsi_tapes) { if (os_scsi_tapes) {
for (i=0; i < osst_dev_max; ++i) { for (i=0; i < osst_max_dev; ++i) {
STp = os_scsi_tapes[i]; if (!(STp = os_scsi_tapes[i])) continue;
if (!STp) /* This is defensive, supposed to happen during detach */
continue;
if (STp->header_cache) if (STp->header_cache)
vfree(STp->header_cache); vfree(STp->header_cache);
put_disk(STp->disk); if (STp->buffer) {
normalize_buffer(STp->buffer);
kfree(STp->buffer);
}
put_disk(STp->drive);
kfree(STp); kfree(STp);
} }
kfree(os_scsi_tapes); kfree(os_scsi_tapes);
if (osst_buffers) {
for (i=0; i < osst_nbr_buffers; i++) {
if (osst_buffers[i]) {
osst_buffers[i]->orig_sg_segs = 0;
normalize_buffer(osst_buffers[i]);
kfree(osst_buffers[i]);
}
}
kfree(osst_buffers);
}
} }
osst_dev_max = 0;
printk(KERN_INFO "osst :I: Unloaded.\n"); printk(KERN_INFO "osst :I: Unloaded.\n");
} }
......
...@@ -510,7 +510,7 @@ typedef struct os_header_s { ...@@ -510,7 +510,7 @@ typedef struct os_header_s {
#define OS_AUX_SIZE (512) #define OS_AUX_SIZE (512)
//#define OSST_MAX_SG 2 //#define OSST_MAX_SG 2
/* The tape buffer descriptor. */ /* The OnStream tape buffer descriptor. */
typedef struct { typedef struct {
unsigned char in_use; unsigned char in_use;
unsigned char dma; /* DMA-able buffer */ unsigned char dma; /* DMA-able buffer */
...@@ -523,14 +523,14 @@ typedef struct { ...@@ -523,14 +523,14 @@ typedef struct {
int syscall_result; int syscall_result;
Scsi_Request *last_SRpnt; Scsi_Request *last_SRpnt;
unsigned char *b_data; unsigned char *b_data;
os_aux_t *aux; /* onstream AUX structure at end of each block */ os_aux_t *aux; /* onstream AUX structure at end of each block */
unsigned short use_sg; /* zero or number of segments for this adapter */ unsigned short use_sg; /* zero or number of s/g segments for this adapter */
unsigned short sg_segs; /* total number of allocated segments */ unsigned short sg_segs; /* number of segments in s/g list */
unsigned short orig_sg_segs; /* number of segments allocated at first try */ unsigned short orig_sg_segs; /* number of segments allocated at first try */
struct scatterlist sg[1]; /* MUST BE last item */ struct scatterlist sg[1]; /* MUST BE last item */
} OSST_buffer; } OSST_buffer;
/* The tape drive descriptor */ /* The OnStream tape drive descriptor */
typedef struct { typedef struct {
struct Scsi_Device_Template *driver; struct Scsi_Device_Template *driver;
unsigned capacity; unsigned capacity;
...@@ -549,6 +549,7 @@ typedef struct { ...@@ -549,6 +549,7 @@ typedef struct {
unsigned char restr_dma; unsigned char restr_dma;
unsigned char scsi2_logical; unsigned char scsi2_logical;
unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */ unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */
unsigned char pos_unknown; /* after reset position unknown */
int write_threshold; int write_threshold;
int timeout; /* timeout for normal commands */ int timeout; /* timeout for normal commands */
int long_timeout; /* timeout for commands known to take long time*/ int long_timeout; /* timeout for commands known to take long time*/
...@@ -556,10 +557,10 @@ typedef struct { ...@@ -556,10 +557,10 @@ typedef struct {
/* Mode characteristics */ /* Mode characteristics */
ST_mode modes[ST_NBR_MODES]; ST_mode modes[ST_NBR_MODES];
int current_mode; int current_mode;
#ifdef CONFIG_DEVFS_FS
devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */ devfs_handle_t de_r[ST_NBR_MODES]; /* Rewind entries */
devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */ devfs_handle_t de_n[ST_NBR_MODES]; /* No-rewind entries */
#endif struct device driverfs_dev_r[ST_NBR_MODES];
struct device driverfs_dev_n[ST_NBR_MODES];
/* Status variables */ /* Status variables */
int partition; int partition;
...@@ -628,7 +629,7 @@ typedef struct { ...@@ -628,7 +629,7 @@ typedef struct {
unsigned char last_cmnd[6]; unsigned char last_cmnd[6];
unsigned char last_sense[16]; unsigned char last_sense[16];
#endif #endif
struct gendisk *disk; struct gendisk *drive;
} OS_Scsi_Tape; } OS_Scsi_Tape;
/* Values of write_type */ /* Values of write_type */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment