Commit 1b75d964 authored by James Bottomley's avatar James Bottomley

Merge mulgrave.(none):/home/jejb/BK/scsi-misc-2.5

into mulgrave.(none):/home/jejb/BK/scsi-misc-new-2.5
parents c9e54010 45f841b0
......@@ -124,8 +124,6 @@
#include <linux/spinlock.h>
#include <linux/sched.h>
#include <linux/proc_fs.h>
#include <linux/init.h>
#include <linux/mca.h>
#include <asm/dma.h>
#include <asm/system.h>
#include <asm/io.h>
......@@ -236,7 +234,7 @@ static __u8 NCR_700_SDTR_msg[] = {
NCR_700_MAX_OFFSET
};
struct Scsi_Host * __init
struct Scsi_Host *
NCR_700_detect(Scsi_Host_Template *tpnt,
struct NCR_700_Host_Parameters *hostdata)
{
......@@ -2020,3 +2018,5 @@ NCR_700_slave_destroy(Scsi_Device *SDp)
EXPORT_SYMBOL(NCR_700_detect);
EXPORT_SYMBOL(NCR_700_release);
EXPORT_SYMBOL(NCR_700_intr);
no_module_init;
......@@ -22,11 +22,11 @@ static int D700_release(struct Scsi_Host *host);
* remaining parameters shown below must be filled in. The 53c700
* routine NCR_700_detect will fill in all of the missing routines */
#define NCR_D700_SCSI { \
name: "NCR Dual 700 MCA", \
proc_name: "NCR_D700", \
detect: D700_detect, \
release: D700_release, \
this_id: 7, \
.name = "NCR Dual 700 MCA", \
.proc_name = "NCR_D700", \
.detect = D700_detect, \
.release = D700_release, \
.this_id = 7, \
}
......
......@@ -36,7 +36,6 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/list.h>
#include <linux/smp_lock.h>
#define __KERNEL_SYSCALLS__
......@@ -50,7 +49,6 @@ static LIST_HEAD(scsi_host_list);
static spinlock_t scsi_host_list_lock = SPIN_LOCK_UNLOCKED;
static int scsi_host_next_hn; /* host_no for next new host */
static int scsi_hosts_registered; /* cnt of registered scsi hosts */
static char *scsihosts;
MODULE_PARM(scsihosts, "s");
......@@ -192,7 +190,7 @@ static void scsi_host_legacy_release(struct Scsi_Host *shost)
static int scsi_remove_legacy_host(struct Scsi_Host *shost)
{
int error, pcount = scsi_hosts_registered;
int error;
error = scsi_remove_host(shost);
if (error)
......@@ -203,8 +201,6 @@ static int scsi_remove_legacy_host(struct Scsi_Host *shost)
else
scsi_host_legacy_release(shost);
if (pcount == scsi_hosts_registered)
scsi_unregister(shost);
return 0;
}
......@@ -260,7 +256,6 @@ static int scsi_check_device_busy(struct scsi_device *sdev)
int scsi_remove_host(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
struct list_head *le, *lh;
/*
* FIXME Do ref counting. We force all of the devices offline to
......@@ -287,16 +282,9 @@ int scsi_remove_host(struct Scsi_Host *shost)
sdev->attached);
return 1;
}
devfs_unregister(sdev->de);
device_unregister(&sdev->sdev_driverfs_dev);
}
/* Next we free up the Scsi_Cmnd structures for this host */
list_for_each_safe(le, lh, &shost->my_devices) {
scsi_free_sdev(list_entry(le, Scsi_Device, siblings));
}
scsi_forget_host(shost);
return 0;
}
......@@ -343,7 +331,6 @@ void scsi_unregister(struct Scsi_Host *shost)
shost->eh_notify = NULL;
}
scsi_hosts_registered--;
shost->hostt->present--;
/* Cleanup proc and driverfs */
......@@ -395,7 +382,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
memset(shost, 0, sizeof(struct Scsi_Host) + xtr_bytes);
shost->host_no = scsi_alloc_host_num(shost_tp->proc_name);
scsi_hosts_registered++;
spin_lock_init(&shost->default_lock);
scsi_assign_lock(shost, &shost->default_lock);
......@@ -491,7 +477,6 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template *shost_tp, int xtr_bytes)
int scsi_register_host(Scsi_Host_Template *shost_tp)
{
struct Scsi_Host *shost;
int cur_cnt;
/*
* Check no detect routine.
......@@ -503,8 +488,6 @@ int scsi_register_host(Scsi_Host_Template *shost_tp)
if (!shost_tp->max_sectors)
shost_tp->max_sectors = 1024;
cur_cnt = scsi_hosts_registered;
/*
* The detect routine must carefully spinunlock/spinlock if it
* enables interrupts, since all interrupt handlers do spinlock as
......@@ -520,28 +503,6 @@ int scsi_register_host(Scsi_Host_Template *shost_tp)
if (!shost_tp->present)
return 0;
if (cur_cnt == scsi_hosts_registered) {
if (shost_tp->present > 1) {
printk(KERN_ERR "scsi: Failure to register"
"low-level scsi driver");
scsi_unregister_host(shost_tp);
return 1;
}
/*
* The low-level driver failed to register a driver.
* We can do this now.
*
* XXX Who needs manual registration and why???
*/
if (!scsi_register(shost_tp, 0)) {
printk(KERN_ERR "scsi: register failed.\n");
scsi_unregister_host(shost_tp);
return 1;
}
}
/*
* XXX(hch) use scsi_tp_for_each_host() once it propagates
* error returns properly.
......@@ -575,20 +536,7 @@ int scsi_register_host(Scsi_Host_Template *shost_tp)
**/
int scsi_unregister_host(Scsi_Host_Template *shost_tp)
{
int pcount;
/* get the big kernel lock, so we don't race with open() */
lock_kernel();
pcount = scsi_hosts_registered;
scsi_tp_for_each_host(shost_tp, scsi_remove_legacy_host);
if (pcount != scsi_hosts_registered)
printk(KERN_INFO "scsi : %d host%s left.\n", scsi_hosts_registered,
(scsi_hosts_registered == 1) ? "" : "s");
unlock_kernel();
return 0;
}
......@@ -668,64 +616,6 @@ void __init scsi_host_init(void)
}
}
/*
* Function: scsi_get_host_dev()
*
* Purpose: Create a Scsi_Device that points to the host adapter itself.
*
* Arguments: SHpnt - Host that needs a Scsi_Device
*
* Lock status: None assumed.
*
* Returns: The Scsi_Device or NULL
*
* Notes:
* Attach a single Scsi_Device to the Scsi_Host - this should
* be made to look like a "pseudo-device" that points to the
* HA itself.
*
* Note - this device is not accessible from any high-level
* drivers (including generics), which is probably not
* optimal. We can add hooks later to attach
*/
struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0);
if (sdev) {
scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0)
goto fail;
sdev->borken = 0;
}
return sdev;
fail:
kfree(sdev);
return NULL;
}
/*
* Function: scsi_free_host_dev()
*
* Purpose: Free a scsi_device that points to the host adapter itself.
*
* Arguments: SHpnt - Host that needs a Scsi_Device
*
* Lock status: None assumed.
*
* Returns: Nothing
*
* Notes:
*/
void scsi_free_host_dev(struct scsi_device *sdev)
{
BUG_ON(sdev->id != sdev->host->this_id);
scsi_free_sdev(sdev);
}
void scsi_host_busy_inc(struct Scsi_Host *shost, Scsi_Device *sdev)
{
unsigned long flags;
......@@ -765,22 +655,3 @@ void scsi_host_failed_inc_and_test(struct Scsi_Host *shost)
}
spin_unlock_irqrestore(shost->host_lock, flags);
}
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
* c-indent-level: 4
* c-brace-imaginary-offset: 0
* c-brace-offset: -4
* c-argdecl-indent: 4
* c-label-offset: -4
* c-continued-statement-offset: 4
* c-continued-brace-offset: 0
* indent-tabs-mode: nil
* tab-width: 8
* End:
*/
......@@ -532,6 +532,8 @@ static inline void scsi_set_pci_device(struct Scsi_Host *shost,
* Prototypes for functions/data in scsi_scan.c
*/
extern void scsi_scan_host(struct Scsi_Host *);
extern void scsi_forget_host(struct Scsi_Host *);
struct Scsi_Device_Template
{
......
......@@ -13,18 +13,18 @@
order) Klaus Ehrenfried, Wolfgang Denk, Steve Hirsch, Andreas Koppenh"ofer,
Michael Leodolter, Eyal Lebedinsky, J"org Weule, and Eric Youngdale.
Copyright 1992 - 2000 Kai Makisara
email Kai.Makisara@metla.fi
Copyright 1992 - 2002 Kai Makisara / Willem Riede
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 $
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
*/
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 */
#define OSST_FW_NEED_POLL_MIN 10601 /*(107A)*/
......@@ -60,7 +60,6 @@ const char * osst_version = "0.9.10";
#define OSST_DEB_MSG KERN_NOTICE
#define MAJOR_NR OSST_MAJOR
#define DEVICE_NR(device) (minor(device) & 0x7f)
#include <linux/blk.h>
#include "scsi.h"
......@@ -74,30 +73,32 @@ const char * osst_version = "0.9.10";
#include "osst_options.h"
#include "osst_detect.h"
static int buffer_kbs = 0;
static int max_dev = 0;
static int write_threshold_kbs = 0;
static int max_buffers = 0;
static int max_sg_segs = 0;
#ifdef MODULE
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_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(max_buffers, "i");
MODULE_PARM_DESC(write_threshold_kbs, "Asynchronous write threshold (KB; 30)");
MODULE_PARM(max_sg_segs, "i");
MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (9)");
#else
static struct osst_dev_parm {
char *name;
int *val;
} parms[] __initdata = {
{ "buffer_kbs", &buffer_kbs },
{ "max_dev", &max_dev },
{ "write_threshold_kbs", &write_threshold_kbs },
{ "max_buffers", &max_buffers },
{ "max_sg_segs", &max_sg_segs }
};
};
#endif
/* Some default definitions have been moved to osst_options.h */
......@@ -116,34 +117,41 @@ static int debugging = 1;
// #define OSST_INJECT_ERRORS 1
#endif
#define MAX_RETRIES 0
#define MAX_RETRIES 2
#define MAX_READ_RETRIES 0
#define MAX_WRITE_RETRIES 0
#define MAX_READY_RETRIES 5
#define MAX_READY_RETRIES 0
#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_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_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
24 bits) */
#define SET_DENS_AND_BLK 0x10001
static int osst_nbr_buffers;
static int osst_buffer_size = OSST_BUFFER_SIZE;
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_dev = OSST_MAX_TAPES;
static int osst_nr_dev;
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 OSST_buffer *new_tape_buffer(int, int);
static int enlarge_buffer(OSST_buffer *, int, int);
static OSST_buffer *new_tape_buffer(int, int, int);
static int enlarge_buffer(OSST_buffer *, int);
static void normalize_buffer(OSST_buffer *);
static int append_to_buffer(const char *, OSST_buffer *, int);
static int from_buffer(OSST_buffer *, char *, int);
......@@ -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_from_buffer(OSST_buffer *, unsigned char *);
static int osst_init(void);
static int osst_attach(Scsi_Device *);
static void osst_detach(Scsi_Device *);
static int osst_nr_dev;
static int osst_dev_max;
struct Scsi_Device_Template osst_template =
{
.module = THIS_MODULE,
.list = LIST_HEAD_INIT(osst_template.list),
.name = "OnStream tape",
.tag = "osst",
.scsi_type = TYPE_TAPE,
.attach = osst_attach,
.detach = osst_detach
.module = THIS_MODULE,
.list = LIST_HEAD_INIT(osst_template.list),
.name = "OnStream Tape",
.tag = "osst",
.scsi_type = TYPE_TAPE,
.attach = osst_attach,
.detach = osst_detach
};
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,
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 */
......@@ -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 */
return 0;
}
if (driver_byte(result) & DRIVER_SENSE)
if ((driver_byte(result) & DRIVER_MASK) == DRIVER_SENSE)
scode = sense[2] & 0x0f;
else {
sense[0] = 0; /* We don't have sense data if this byte is zero */
scode = 0;
}
#if DEBUG
if (debugging) {
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)
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_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)
print_req_sense("osst", SRpnt);
}
else
// else
#endif
if (!(driver_byte(result) & DRIVER_SENSE) ||
((sense[0] & 0x70) == 0x70 &&
......@@ -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 &&
scode == RECOVERED_ERROR) {
STp->recover_count++;
......@@ -275,22 +281,21 @@ static int osst_chk_result(OS_Scsi_Tape * STp, Scsi_Request * SRpnt)
/* Wakeup from interrupt */
static void osst_sleep_done (Scsi_Cmnd * SCpnt)
{
OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data,
OS_Scsi_Tape, driver);
OS_Scsi_Tape * STp = container_of(SCpnt->request->rq_disk->private_data, OS_Scsi_Tape, driver);
if ((STp->buffer)->writing &&
(SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x40)) {
/* EOM at write-behind, has all been written? */
if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW)
(STp->buffer)->midlevel_result = SCpnt->result; /* Error */
STp->buffer->midlevel_result = SCpnt->result; /* Error */
else
(STp->buffer)->midlevel_result = INT_MAX; /* OK */
STp->buffer->midlevel_result = INT_MAX; /* OK */
}
else
(STp->buffer)->midlevel_result = SCpnt->result;
STp->buffer->midlevel_result = SCpnt->result;
SCpnt->request->rq_status = RQ_SCSI_DONE;
(STp->buffer)->last_SRpnt = SCpnt->sc_request;
STp->buffer->last_SRpnt = SCpnt->sc_request;
#if DEBUG
STp->write_pending = 0;
......@@ -312,7 +317,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp,
#endif
if (SRpnt == 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))
(STp->buffer)->syscall_result = (-EINTR);
else
......@@ -335,7 +340,7 @@ static Scsi_Request * osst_do_scsi(Scsi_Request *SRpnt, OS_Scsi_Tape *STp,
SRpnt->sr_cmd_len = 0;
SRpnt->sr_request->waiting = &(STp->wait);
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);
......@@ -387,7 +392,7 @@ static void osst_write_behind_check(OS_Scsi_Tape *STp)
scsi_release_request((STp->buffer)->last_SRpnt);
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->writing = 0;
......@@ -537,7 +542,7 @@ static int osst_verify_frame(OS_Scsi_Tape * STp, int frame_seq_number, int quiet
STp->first_frame_position);
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 (!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) {
STps->eof = ST_EOD_1;
STp->frame_in_buffer = 1;
}
if (aux->frame_type == OS_FRAME_TYPE_DATA) {
blk_cnt = ntohs(aux->dat.dat_list[0].blk_cnt);
blk_sz = ntohl(aux->dat.dat_list[0].blk_sz);
STp->buffer->buffer_bytes = blk_cnt * blk_sz;
STp->buffer->read_pointer = 0;
STp->frame_in_buffer = 1;
/* See what block size was used to write file */
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
/*
* 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];
Scsi_Request * SRpnt;
long startwait = jiffies;
#if DEBUG
int dbg = debugging;
char *name = tape_name(STp);
int dbg = debugging;
char * name = tape_name(STp);
printk(OSST_DEB_MSG "%s:D: Reached onstream wait ready\n", name);
#endif
if (initial_delay > 0) {
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(initial_delay);
}
memset(cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = TEST_UNIT_READY;
......@@ -720,10 +732,10 @@ static int osst_position_tape_and_confirm(OS_Scsi_Tape * STp, Scsi_Request ** aS
{
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);
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));
}
......@@ -736,6 +748,7 @@ static int osst_flush_drive_buffer(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
Scsi_Request * SRpnt;
int result = 0;
int delay = OSST_WAIT_LONG_WRITE_COMPLETE;
#if DEBUG
char *name = tape_name(STp);
......@@ -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);
*aSRpnt = SRpnt;
if (!SRpnt) return (-EBUSY);
if ((STp->buffer)->syscall_result)
result = osst_write_error_recovery(STp, aSRpnt, 0);
result |= osst_wait_ready(STp, aSRpnt, 5 * 60);
//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 ((SRpnt->sr_sense_buffer[2] & 0x0f) == 2 && SRpnt->sr_sense_buffer[12] == 4) {
if (SRpnt->sr_sense_buffer[13] == 8) {
//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;
return (result);
}
......@@ -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);
#endif
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;
if (!SRpnt)
return (-EBUSY);
......@@ -901,7 +922,8 @@ static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
#endif
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_drive_buffer(STp, aSRpnt);
}
......@@ -919,7 +941,7 @@ static int osst_initiate_read(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt)
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Start Read Ahead on OnStream tape\n", name);
#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;
retval = STp->buffer->syscall_result;
}
......@@ -937,6 +959,15 @@ static int osst_get_logical_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, in
x,
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
*/
......@@ -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;
move /= (OS_DATA_SIZE / STp->block_size);
}
if (!move) move = logical_blk_num > STp->logical_blk_num ? 1 : -1;
#if DEBUG
printk(OSST_DEB_MSG
"%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 **
cmd[8] = 32768 & 0xff;
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) {
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 **
name, new_frame+i, frame_seq_number+i);
#endif
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);
SRpnt = * aSRpnt;
......@@ -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 &&
(SRpnt->sr_sense_buffer[13] == 1 || SRpnt->sr_sense_buffer[13] == 8)) {
/* in the process of becoming ready */
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
continue;
}
......@@ -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);
flag = 0;
attempts--;
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(HZ / 10);
}
if (osst_get_frame_position(STp, aSRpnt) < 0) { /* additional write error */
#if DEBUG
......@@ -1909,6 +1944,7 @@ static int osst_space_over_filemarks_forward_fast(OS_Scsi_Tape * STp, Scsi_Reque
if (mt_op == MTFSF) {
STp->frame_seq_number++;
STp->frame_in_buffer = 0;
STp->buffer->read_pointer = 0;
STp->logical_blk_num += ntohs(STp->buffer->aux->dat.dat_list[0].blk_cnt);
}
return 0;
......@@ -2009,7 +2045,7 @@ static int osst_write_filler(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int whe
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Reached onstream write filler group %d\n", name, where);
#endif
osst_wait_ready(STp, aSRpnt, 60 * 5);
osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
osst_set_frame_position(STp, aSRpnt, where, 0);
STp->write_type = OS_WRITE_FILLER;
while (count--) {
......@@ -2035,7 +2071,7 @@ static int __osst_write_header(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int w
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Reached onstream write header group %d\n", name, where);
#endif
osst_wait_ready(STp, aSRpnt, 60 * 5);
osst_wait_ready(STp, aSRpnt, 60 * 5, 0);
osst_set_frame_position(STp, aSRpnt, where, 0);
STp->write_type = OS_WRITE_HEADER;
while (count--) {
......@@ -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;
SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 20, SCSI_DATA_READ,
STp->timeout, MAX_READY_RETRIES, TRUE);
STp->timeout, MAX_RETRIES, TRUE);
if (!SRpnt) {
STp->buffer->b_data = olddata; STp->buffer->buffer_size = oldsize;
return (-EBUSY);
......@@ -2690,7 +2726,7 @@ static int osst_get_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt)
scmd[0] = READ_POSITION;
STp->buffer->b_data = mybuf; STp->buffer->buffer_size = 24;
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)
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
scmd[9] = 0x80;
SRpnt = osst_do_scsi(*aSRpnt, STp, scmd, 0, SCSI_DATA_NONE, STp->long_timeout,
MAX_READY_RETRIES, TRUE);
MAX_RETRIES, TRUE);
if (!SRpnt)
return (-EBUSY);
*aSRpnt = SRpnt;
......@@ -2775,7 +2811,7 @@ static int osst_set_frame_position(OS_Scsi_Tape *STp, Scsi_Request ** aSRpnt, in
result = (-EIO);
}
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));
STp->first_frame_position = STp->last_frame_position = ppos;
STps->eof = ST_NOEOF;
......@@ -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
* to this device.
*/
if( STp->device->was_reset )
if( STp->pos_unknown)
return (-EIO);
if (STp->ready != ST_READY)
return 0;
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);
}
if (STp->block_size == 0)
return 0;
......@@ -3063,6 +3100,43 @@ static int osst_write_frame(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, int sync
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 */
......@@ -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
* to this device.
*/
if (STp->device->was_reset) {
if (STp->pos_unknown) {
retval = (-EIO);
goto out;
}
......@@ -3154,20 +3228,22 @@ static ssize_t osst_write(struct file * filp, const char * buf, size_t count, lo
goto out;
}
STps = &(STp->ps[STp->partition]);
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED &&
!osst_int_ioctl(STp, &SRpnt, MTLOCK, 0))
if (STp->do_auto_lock && STp->door_locked == ST_UNLOCKED && !do_door_lock(STp, 1))
STp->door_locked = ST_LOCKED_AUTO;
STps = &(STp->ps[STp->partition]);
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);
if (retval)
goto out;
STps->rw = ST_IDLE;
}
else if (STps->rw != ST_WRITING) {
if (STps->rw != ST_WRITING) {
/* Are we totally rewriting this tape? */
if (!STp->header_ok ||
(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
printk(OSST_DEB_MSG "%s:D: EOF up (%d). Left %d, needed %d.\n", name,
STps->eof, (STp->buffer)->buffer_bytes, count - total);
#endif
/* force multiple of block size, note block_size may have been adjusted */
transfer = (((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);
if (i) {
retval = i;
......@@ -3870,9 +3956,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
}
break;
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);
else
} else
ioctl_result = 0;
#if DEBUG
if (debugging)
......@@ -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 ;
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 MTSETDENSITY: /* Set tape density */
case MTSETDRVBUFFER: /* Set drive buffering */
......@@ -4070,13 +4137,10 @@ static int osst_int_ioctl(OS_Scsi_Tape * STp, Scsi_Request ** aSRpnt, unsigned i
STps->drv_file = fileno;
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)
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)
STps->eof = (STp->first_frame_position >= STp->eod_frame_ppos)?ST_EOD:ST_FM;
else if (chg_eof)
......@@ -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)
STp->rew_at_close = 0;
else if (cmd_in == MTLOAD) {
/* STp->rew_at_close = (minor(inode->i_rdev) & 0x80) == 0; FIXME */
for (i=0; i < ST_NBR_PARTITIONS; i++) {
STp->ps[i].rw = ST_IDLE;
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
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == BLANK_CHECK)
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))
ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60);
ioctl_result = osst_wait_ready(STp, &SRpnt, 5 * 60, OSST_WAIT_POSITION_COMPLETE);
}
*aSRpnt = SRpnt;
......@@ -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)
{
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];
Scsi_Request * SRpnt;
OS_Scsi_Tape * STp;
ST_mode * STm;
ST_partstat * STps;
int dev = TAPE_NR(inode->i_rdev);
char *name;
int dev = TAPE_NR(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);
}
filp->private_data = STp;
name = tape_name(STp);
if( !scsi_block_when_processing_errors(STp->device) ) {
return -ENXIO;
}
if (STp->in_use) {
write_unlock(&os_scsi_tapes_lock);
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Device already in use.\n", name);
#endif
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);
}
STp->device->access_count++;
STp->in_use = 1;
STp->rew_at_close = (minor(inode->i_rdev) & 0x80) == 0;
filp->private_data = STp;
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 DEBUG
......@@ -4193,10 +4263,10 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
flags = filp->f_flags;
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)
STp->header_ok = 0;
#if 0
/* Allocate a buffer for this user */
need_dma_buffer = STp->restr_dma;
for (i=0; i < osst_nbr_buffers; i++)
......@@ -4213,9 +4283,16 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
}
else
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)->syscall_result = 0;
#if 0
(STp->buffer)->use_sg = STp->device->host->sg_tablesize;
/* 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)
i < (STp->buffer)->sg_segs; i++)
(STp->buffer)->buffer_size += (STp->buffer)->sg[i].length;
}
#endif
STp->dirty = 0;
for (i=0; i < ST_NBR_PARTITIONS; i++) {
STps = &(STp->ps[i]);
......@@ -4251,6 +4328,10 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
#if DEBUG
printk(OSST_DEB_MSG "%s:D: Unit not ready, cause %x\n", name, SRpnt->sr_sense_buffer[13]);
#endif
if (filp->f_flags & O_NONBLOCK) {
retval = -EAGAIN;
goto err_out;
}
if (SRpnt->sr_sense_buffer[13] == 2) { /* initialize command required (LOAD) */
memset (cmd, 0, MAX_COMMAND_SIZE);
cmd[0] = START_STOP;
......@@ -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,
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 &&
(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)
break;
}
STp->device->was_reset = 0;
STp->pos_unknown = 0;
STp->partition = STp->new_partition = 0;
if (STp->can_partitions)
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)
break;
if ((SRpnt->sr_sense_buffer[2] & 0x0f) == UNIT_ATTENTION) {
STp->device->was_reset = 0;
STp->pos_unknown = 0;
STp->partition = STp->new_partition = 0;
if (STp->can_partitions)
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)
}
}
if (osst_wait_ready(STp, &SRpnt, 15 * 60)) /* FIXME - not allowed with NOBLOCK */
printk(KERN_INFO "%s:I: Device did not become Ready in open\n",name);
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);
if ((STp->buffer)->syscall_result != 0) {
if ((STp->device)->scsi_level >= SCSI_2 &&
......@@ -4430,19 +4511,9 @@ static int os_scsi_tape_open(struct inode * inode, struct file * filp)
osst_configure_onstream(STp, &SRpnt);
/* STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; FIXME */
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) {
if (STp->buffer->buffer_size >= OS_FRAME_SIZE) {
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);
STp->buffer->aux = (os_aux_t *) (page_address(STp->buffer->sg[i].page) + OS_DATA_SIZE - b_size);
#if DEBUG
......@@ -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,
STp->buffer->aux, i, page_address(STp->buffer->sg[i].page));
#endif
} else
} else {
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 : (
(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)
err_out:
if (SRpnt != NULL)
scsi_release_request(SRpnt);
if (STp->buffer != NULL) {
STp->buffer->in_use = 0;
STp->buffer = NULL;
}
STp->in_use = 0;
normalize_buffer(STp->buffer);
STp->header_ok = 0;
STp->in_use = 0;
STp->device->access_count--;
module_put(STp->device->host->hostt->module);
......@@ -4536,12 +4608,13 @@ static int os_scsi_tape_flush(struct file * filp)
if (file_count(filp) > 1)
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);
if (result != 0 && result != (-ENOSPC))
goto out;
}
if ( STps->rw >= ST_WRITING && !(STp->device)->was_reset) {
if ( STps->rw >= ST_WRITING && !STp->pos_unknown) {
#if DEBUG
if (debugging) {
......@@ -4632,17 +4705,18 @@ static int os_scsi_tape_close(struct inode * inode, struct file * filp)
OS_Scsi_Tape * STp = filp->private_data;
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 (STp->buffer != NULL)
STp->buffer->in_use = 0;
if (STp->door_locked == ST_LOCKED_AUTO)
do_door_lock(STp, 0);
if (STp->raw)
STp->header_ok = 0;
normalize_buffer(STp->buffer);
write_lock(&os_scsi_tapes_lock);
STp->in_use = 0;
write_unlock(&os_scsi_tapes_lock);
STp->device->access_count--;
module_put(STp->device->host->hostt->module);
......@@ -4718,7 +4792,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
goto out;
}
if (!(STp->device)->was_reset) {
if (!STp->pos_unknown) {
if (STps->eof == ST_FM_HIT) {
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,
retval = (-EIO);
goto out;
}
reset_state(STp);
/* remove this when the midlevel properly clears was_reset */
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 &&
......@@ -4781,7 +4849,7 @@ static int osst_ioctl(struct inode * inode,struct file * file,
STps->rw = ST_IDLE; /* Prevent automatic WEOF and fsf */
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 &&
(mtc.mt_count & MT_ST_OPTIONS) != 0) {
......@@ -4837,7 +4905,12 @@ static int osst_ioctl(struct inode * inode,struct file * file,
retval = i;
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 &&
(i = update_partition(inode)) < 0)
{retval=i;goto out;}*/
......@@ -4967,15 +5040,12 @@ static int osst_ioctl(struct inode * inode,struct file * file,
/* Memory handling routines */
/* Try to allocate a new tape buffer */
static OSST_buffer * new_tape_buffer( int from_initialization, int need_dma )
/* 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, int max_sg )
{
int i, priority, b_size, order, got = 0, segs = 0;
int i, priority;
OSST_buffer *tb;
if (osst_nbr_buffers >= osst_dev_max)
return NULL; /* Should never happen */
if (from_initialization)
priority = GFP_ATOMIC;
else
......@@ -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);
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) {
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer (nbr %d).\n",
osst_nbr_buffers);
printk(KERN_NOTICE "osst :I: Can't allocate new tape buffer.\n");
return NULL;
}
tb->sg_segs = tb->orig_sg_segs = segs;
tb->b_data = page_address(tb->sg[0].page);
memset(tb, 0, i);
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 (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);
if (debugging)
printk(OSST_DEB_MSG
"osst :D: segment sizes: first %d, last %d bytes.\n",
tb->sg[0].length, tb->sg[segs-1].length);
}
"osst :D: Allocated tape buffer skeleton (%d bytes, %d segments, dma: %d).\n",
i, max_sg, need_dma);
#endif
tb->in_use = 0;
tb->dma = need_dma;
tb->buffer_size = got;
tb->writing = 0;
osst_buffers[osst_nbr_buffers++] = tb;
return tb;
}
/* Try to allocate a temporary enlarged tape buffer */
static int enlarge_buffer(OSST_buffer *STbuffer, int new_size, int need_dma)
/* Try to allocate a temporary (while a user has the device open) enlarged tape buffer */
static int enlarge_buffer(OSST_buffer *STbuffer, int need_dma)
{
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 (max_segs > osst_max_sg_segs)
max_segs = osst_max_sg_segs;
nbr = max_segs - STbuffer->sg_segs;
if (nbr <= 0)
if (STbuffer->sg_segs) {
printk(KERN_WARNING "osst :A: Buffer not previously normalized.\n");
normalize_buffer(STbuffer);
}
/* See how many segments we can use -- need at least two */
nbr = max_segs = STbuffer->use_sg;
if (nbr <= 2)
return FALSE;
priority = GFP_KERNEL;
if (need_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;
segs < max_segs && got < new_size; ) {
STbuffer->sg[segs].page = alloc_pages(priority, order);
/* Try to allocate the first segment up to OS_DATA_SIZE and the others
big enough to reach the goal (code assumes no segments in place) */
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;
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 */
order--;
continue;
}
printk(KERN_WARNING "osst :W: Failed to enlarge buffer to %d bytes.\n",
new_size);
OS_FRAME_SIZE);
#if DEBUG
STbuffer->buffer_size = got;
#endif
normalize_buffer(STbuffer);
return FALSE;
}
STbuffer->sg[segs].page = NULL;
STbuffer->sg[segs].length = b_size;
STbuffer->sg_segs += 1;
got += b_size;
STbuffer->sg[segs].length = (OS_FRAME_SIZE - got <= PAGE_SIZE / 2) ? (OS_FRAME_SIZE - got) : b_size;
got += STbuffer->sg[segs].length;
STbuffer->buffer_size = got;
segs++;
STbuffer->sg_segs = ++segs;
}
#if DEBUG
if (debugging) {
for (nbr=0; osst_buffers[nbr] != STbuffer && nbr < osst_nbr_buffers; nbr++);
printk(OSST_DEB_MSG
"osst :D: Expanded tape buffer %d (%d bytes, %d->%d segments, dma: %d, a: %p).\n",
nbr, got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
printk(OSST_DEB_MSG
printk(OSST_DEB_MSG
"osst :D: Expanded tape buffer (%d bytes, %d->%d segments, dma: %d, at: %p).\n",
got, STbuffer->orig_sg_segs, STbuffer->sg_segs, need_dma, STbuffer->b_data);
printk(OSST_DEB_MSG
"osst :D: segment sizes: first %d, last %d bytes.\n",
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)
}
/* Release the extra buffer */
/* Release the segments */
static void normalize_buffer(OSST_buffer *STbuffer)
{
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;
b_size < STbuffer->sg[i].length;
......@@ -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",
STbuffer->b_data, STbuffer->buffer_size, STbuffer->sg_segs);
#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)
static void validate_options (void)
{
if (buffer_kbs > 0)
osst_buffer_size = buffer_kbs * ST_KILOBYTE;
if (max_dev > 0)
osst_max_dev = max_dev;
if (write_threshold_kbs > 0)
osst_write_threshold = write_threshold_kbs * ST_KILOBYTE;
if (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)
osst_max_sg_segs = max_sg_segs;
#if DEBUG
printk(OSST_DEB_MSG "osst :D: bufsize %d, wrt %d, max buffers %d, s/g segs %d.\n",
osst_buffer_size, osst_write_threshold, osst_max_buffers, osst_max_sg_segs);
printk(OSST_DEB_MSG "osst :D: max tapes %d, write threshold %d, s/g segs %d.\n",
osst_max_dev, osst_write_threshold, osst_max_sg_segs);
//printk(OSST_DEB_MSG "osst :D: sizeof(header) = %d (%s)\n",
// sizeof(os_header_t),sizeof(os_header_t)==OS_DATA_SIZE?"ok":"error");
#endif
......@@ -5313,8 +5331,8 @@ static void validate_options (void)
#ifndef MODULE
/* Set the boot options. Syntax: osst=xxx,yyy,...
where xxx is buffer size in 1024 byte blocks and yyy is write threshold
in 1024 byte blocks. */
where xxx is write threshold in 1024 byte blocks,
and yyy is number of s/g segments to use. */
static int __init osst_setup (char *str)
{
int i, ints[5];
......@@ -5352,14 +5370,30 @@ __setup("osst=", osst_setup);
#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 = {
.read = osst_read,
.write = osst_write,
.ioctl = osst_ioctl,
.open = os_scsi_tape_open,
.flush = os_scsi_tape_flush,
.release = os_scsi_tape_close,
.owner = THIS_MODULE,
.read = osst_read,
.write = osst_write,
.ioctl = osst_ioctl,
.open = os_scsi_tape_open,
.flush = os_scsi_tape_flush,
.release = os_scsi_tape_close,
};
static int osst_supports(Scsi_Device * SDp)
......@@ -5390,102 +5424,93 @@ static struct osst_support_data support_list[] = {
return 0;
}
/*
* osst startup / cleanup code
*/
static int osst_attach(Scsi_Device * SDp)
{
OS_Scsi_Tape * tpnt;
ST_mode * STm;
ST_partstat * STps;
int i, dev;
struct gendisk *disk;
#ifdef CONFIG_DEVFS_FS
int mode;
#endif
OSST_buffer *buffer;
struct gendisk *drive;
int i, mode, dev_num;
if (SDp->type != TYPE_TAPE || !osst_supports(SDp))
return 1;
osst_init();
disk = alloc_disk(1);
if (!disk)
return 1;
if (osst_nr_dev >= osst_dev_max) {
put_disk(disk);
return 1;
if (scsi_slave_attach(SDp)) {
printk(KERN_ERR "osst :E: Failed to attach scsi slave.\n");
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;
}
/* 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 */
for (i=0; os_scsi_tapes[i] && i<osst_dev_max; i++);
if(i >= osst_dev_max) panic ("Scsi_devices corrupt (osst)");
for (i=0; os_scsi_tapes[i] && i<osst_max_dev; i++);
if(i >= osst_max_dev) panic ("Scsi_devices corrupt (osst)");
dev_num = i;
/* allocate a OS_Scsi_Tape for this device */
tpnt = (OS_Scsi_Tape *)kmalloc(sizeof(OS_Scsi_Tape), GFP_ATOMIC);
if (tpnt == NULL) {
printk(KERN_WARNING "osst :W: Can't allocate device descriptor.\n");
put_disk(disk);
scsi_slave_detach(SDp);
return 1;
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Can't allocate device descriptor, device not attached.\n");
put_disk(drive);
scsi_slave_detach(SDp);
return 1;
}
memset(tpnt, 0, sizeof(OS_Scsi_Tape));
os_scsi_tapes[i] = tpnt;
dev = i;
tpnt->capacity = 0xfffff;
/* allocate a buffer for this device */
if (!new_tape_buffer(TRUE, TRUE))
printk(KERN_ERR "osst :W: Unable to allocate a tape buffer.\n");
#ifdef CONFIG_DEVFS_FS
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
char name[8];
static char *formats[ST_NBR_MODES] ={"", "l", "m", "a"};
/* Rewind entry */
sprintf (name, "mt%s", formats[mode]);
# if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
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
i = SDp->host->sg_tablesize;
if (osst_max_sg_segs < i)
i = osst_max_sg_segs;
buffer = new_tape_buffer(TRUE, SDp->host->unchecked_isa_dma, i);
if (buffer == NULL) {
write_unlock(&os_scsi_tapes_lock);
printk(KERN_ERR "osst :E: Unable to allocate a tape buffer, device not attached.\n");
kfree(tpnt);
put_disk(drive);
scsi_slave_detach(SDp);
return 1;
}
disk->number = devfs_register_tape(SDp->de);
#endif
os_scsi_tapes[dev_num] = tpnt;
tpnt->buffer = buffer;
tpnt->device = SDp;
disk->private_data = &tpnt->driver;
sprintf(disk->disk_name, "osst%d", i);
drive->private_data = &tpnt->driver;
sprintf(drive->disk_name, "osst%d", dev_num);
tpnt->driver = &osst_template;
tpnt->disk = disk;
tpnt->dirty = 0;
tpnt->drive = drive;
tpnt->in_use = 0;
tpnt->capacity = 0xfffff;
tpnt->dirty = 0;
tpnt->drv_buffer = 1; /* Try buffering if no mode sense */
tpnt->restr_dma = (SDp->host)->unchecked_isa_dma;
tpnt->density = 0;
......@@ -5510,7 +5535,8 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->os_fw_rev = osst_parse_firmware_rev (SDp->rev);
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->header_ok = 0;
tpnt->linux_media = 0;
......@@ -5543,9 +5569,56 @@ static int osst_attach(Scsi_Device * SDp)
tpnt->modes[0].defined = TRUE;
tpnt->modes[2].defined = TRUE;
tpnt->density_changed = tpnt->compression_changed = tpnt->blksize_changed = FALSE;
init_MUTEX(&tpnt->lock);
init_MUTEX(&tpnt->lock);
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
"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)
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)
{
OS_Scsi_Tape * tpnt;
int i;
#ifdef CONFIG_DEVFS_FS
int mode;
#endif
int i, mode;
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];
if(tpnt != NULL && tpnt->device == SDp) {
tpnt->device = NULL;
#ifdef CONFIG_DEVFS_FS
for (mode = 0; mode < ST_NBR_MODES; ++mode) {
devfs_unregister (tpnt->de_r[mode]);
tpnt->de_r[mode] = NULL;
devfs_unregister (tpnt->de_n[mode]);
tpnt->de_n[mode] = NULL;
}
devfs_unregister_tape(tpnt->disk->number);
#endif
put_disk(tpnt->disk);
kfree(tpnt);
devfs_unregister_tape(tpnt->drive->number);
put_disk(tpnt->drive);
os_scsi_tapes[i] = NULL;
scsi_slave_detach(SDp);
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;
}
}
write_unlock(&os_scsi_tapes_lock);
return;
}
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();
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)
......@@ -5651,31 +5701,23 @@ static void __exit exit_osst (void)
scsi_unregister_device(&osst_template);
unregister_chrdev(MAJOR_NR, "osst");
osst_registered--;
driver_unregister(&osst_template.scsi_driverfs_driver);
if (os_scsi_tapes) {
for (i=0; i < osst_dev_max; ++i) {
STp = os_scsi_tapes[i];
if (!STp)
continue;
for (i=0; i < osst_max_dev; ++i) {
if (!(STp = os_scsi_tapes[i])) continue;
/* This is defensive, supposed to happen during detach */
if (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(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");
}
......
......@@ -510,7 +510,7 @@ typedef struct os_header_s {
#define OS_AUX_SIZE (512)
//#define OSST_MAX_SG 2
/* The tape buffer descriptor. */
/* The OnStream tape buffer descriptor. */
typedef struct {
unsigned char in_use;
unsigned char dma; /* DMA-able buffer */
......@@ -523,14 +523,14 @@ typedef struct {
int syscall_result;
Scsi_Request *last_SRpnt;
unsigned char *b_data;
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 sg_segs; /* total number of allocated segments */
unsigned short orig_sg_segs; /* number of segments allocated at first try */
struct scatterlist sg[1]; /* MUST BE last item */
os_aux_t *aux; /* onstream AUX structure at end of each block */
unsigned short use_sg; /* zero or number of s/g segments for this adapter */
unsigned short sg_segs; /* number of segments in s/g list */
unsigned short orig_sg_segs; /* number of segments allocated at first try */
struct scatterlist sg[1]; /* MUST BE last item */
} OSST_buffer;
/* The tape drive descriptor */
/* The OnStream tape drive descriptor */
typedef struct {
struct Scsi_Device_Template *driver;
unsigned capacity;
......@@ -549,6 +549,7 @@ typedef struct {
unsigned char restr_dma;
unsigned char scsi2_logical;
unsigned char default_drvbuffer; /* 0xff = don't touch, value 3 bits */
unsigned char pos_unknown; /* after reset position unknown */
int write_threshold;
int timeout; /* timeout for normal commands */
int long_timeout; /* timeout for commands known to take long time*/
......@@ -556,10 +557,10 @@ typedef struct {
/* Mode characteristics */
ST_mode modes[ST_NBR_MODES];
int current_mode;
#ifdef CONFIG_DEVFS_FS
devfs_handle_t de_r[ST_NBR_MODES]; /* 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 */
int partition;
......@@ -628,7 +629,7 @@ typedef struct {
unsigned char last_cmnd[6];
unsigned char last_sense[16];
#endif
struct gendisk *disk;
struct gendisk *drive;
} OS_Scsi_Tape;
/* Values of write_type */
......
......@@ -169,30 +169,13 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt);
/*
* Function: scsi_initialize_queue()
*
* Purpose: Selects queue handler function for a device.
* Purpose: Sets up the block queue for a device.
*
* Arguments: SDpnt - device for which we need a handler function.
*
* Returns: Nothing
*
* Lock status: No locking assumed or required.
*
* Notes: Most devices will end up using scsi_request_fn for the
* handler function (at least as things are done now).
* The "block" feature basically ensures that only one of
* the blocked hosts is active at one time, mainly to work around
* buggy DMA chipsets where the memory gets starved.
* For this case, we have a special handler function, which
* does some checks and ultimately calls scsi_request_fn.
*
* The single_lun feature is a similar special case.
*
* We handle these things by stacking the handlers. The
* special case handlers simply check a few conditions,
* and return if they are not supposed to do anything.
* In the event that things are OK, then they call the next
* handler in the list - ultimately they call scsi_request_fn
* to do the dirty deed.
*/
void scsi_initialize_queue(Scsi_Device * SDpnt, struct Scsi_Host * SHpnt)
{
......@@ -793,7 +776,6 @@ int scsi_dispatch_cmd(Scsi_Cmnd * SCpnt)
rtn = host->hostt->queuecommand(SCpnt, scsi_done);
spin_unlock_irqrestore(host->host_lock, flags);
if (rtn != 0) {
scsi_delete_timer(SCpnt);
scsi_mlqueue_insert(SCpnt, rtn == SCSI_MLQUEUE_DEVICE_BUSY ? rtn : SCSI_MLQUEUE_HOST_BUSY);
SCSI_LOG_MLQUEUE(3,
printk("queuecommand : request rejected\n"));
......
......@@ -509,9 +509,6 @@ static inline void scsi_proc_host_rm(struct Scsi_Host *);
/*
* Prototypes for functions in scsi_scan.c
*/
extern struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *,
uint, uint, uint);
extern void scsi_free_sdev(struct scsi_device *);
extern int scsi_add_single_device(uint, uint, uint, uint);
extern int scsi_remove_single_device(uint, uint, uint, uint);
......
......@@ -7,18 +7,15 @@
* of people at Linux Expo.
*/
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/bio.h>
#include <linux/kernel.h>
#include <linux/blk.h>
#include <asm/hardirq.h>
#include <linux/smp_lock.h>
#include <linux/completion.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include "scsi.h"
#include "hosts.h"
#include <scsi/scsi_ioctl.h>
/*
* Function: scsi_insert_special_cmd()
......@@ -665,7 +662,7 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
{
struct request *req = SCpnt->request;
struct scatterlist *sgpnt;
int count, gfp_mask, ret = 0;
int count, ret = 0;
/*
* if this is a rq->data based REQ_BLOCK_PC, setup for a non-sg xfer
......@@ -685,16 +682,10 @@ static int scsi_init_io(Scsi_Cmnd *SCpnt)
*/
SCpnt->use_sg = req->nr_phys_segments;
gfp_mask = GFP_NOIO;
if (likely(in_atomic())) {
gfp_mask &= ~__GFP_WAIT;
gfp_mask |= __GFP_HIGH;
}
/*
* if sg table allocation fails, requeue request later.
*/
sgpnt = scsi_alloc_sgtable(SCpnt, gfp_mask);
sgpnt = scsi_alloc_sgtable(SCpnt, GFP_ATOMIC);
if (unlikely(!sgpnt)) {
req->flags |= REQ_SPECIAL;
ret = BLKPREP_DEFER;
......
......@@ -472,8 +472,8 @@ static void scsi_initialize_merge_fn(struct scsi_device *sd)
* Return value:
* Scsi_Device pointer, or NULL on failure.
**/
struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, uint channel,
uint id, uint lun)
static struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost,
uint channel, uint id, uint lun)
{
struct scsi_device *sdev, *device;
......@@ -542,7 +542,7 @@ struct scsi_device *scsi_alloc_sdev(struct Scsi_Host *shost, uint channel,
* Undo the actions in scsi_alloc_sdev, including removing @sdev from
* the list, and freeing @sdev.
**/
void scsi_free_sdev(struct scsi_device *sdev)
static void scsi_free_sdev(struct scsi_device *sdev)
{
list_del(&sdev->siblings);
list_del(&sdev->same_target_siblings);
......@@ -1419,6 +1419,14 @@ static int scsi_add_lun(Scsi_Device *sdevscan, Scsi_Device **sdevnew,
return SCSI_SCAN_LUN_PRESENT;
}
static int scsi_remove_lun(struct scsi_device *sdev)
{
devfs_unregister(sdev->de);
device_unregister(&sdev->sdev_driverfs_dev);
scsi_free_sdev(sdev);
}
/**
* scsi_probe_and_add_lun - probe a LUN, if a LUN is found add it
* @sdevscan: probe the LUN corresponding to this Scsi_Device
......@@ -1941,8 +1949,7 @@ int scsi_remove_single_device(uint host, uint channel, uint id, uint lun)
if (sdev->attached)
goto out;
devfs_unregister(sdev->de);
scsi_free_sdev(sdev);
scsi_remove_lun(sdev);
error = 0;
out:
......@@ -2068,3 +2075,69 @@ void scsi_scan_host(struct Scsi_Host *shost)
}
scsi_free_sdev(sdevscan);
}
void scsi_forget_host(struct Scsi_Host *shost)
{
struct list_head *le, *lh;
list_for_each_safe(le, lh, &shost->my_devices)
scsi_remove_lun(list_entry(le, struct scsi_device, siblings));
}
/*
* Function: scsi_get_host_dev()
*
* Purpose: Create a Scsi_Device that points to the host adapter itself.
*
* Arguments: SHpnt - Host that needs a Scsi_Device
*
* Lock status: None assumed.
*
* Returns: The Scsi_Device or NULL
*
* Notes:
* Attach a single Scsi_Device to the Scsi_Host - this should
* be made to look like a "pseudo-device" that points to the
* HA itself.
*
* Note - this device is not accessible from any high-level
* drivers (including generics), which is probably not
* optimal. We can add hooks later to attach
*/
struct scsi_device *scsi_get_host_dev(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
sdev = scsi_alloc_sdev(shost, 0, shost->this_id, 0);
if (sdev) {
scsi_build_commandblocks(sdev);
if (sdev->current_queue_depth == 0)
goto fail;
sdev->borken = 0;
}
return sdev;
fail:
kfree(sdev);
return NULL;
}
/*
* Function: scsi_free_host_dev()
*
* Purpose: Free a scsi_device that points to the host adapter itself.
*
* Arguments: SHpnt - Host that needs a Scsi_Device
*
* Lock status: None assumed.
*
* Returns: Nothing
*
* Notes:
*/
void scsi_free_host_dev(struct scsi_device *sdev)
{
BUG_ON(sdev->id != sdev->host->this_id);
scsi_free_sdev(sdev);
}
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