Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1b75d964
Commit
1b75d964
authored
Nov 27, 2002
by
James Bottomley
Browse files
Options
Browse Files
Download
Plain Diff
Merge mulgrave.(none):/home/jejb/BK/scsi-misc-2.5
into mulgrave.(none):/home/jejb/BK/scsi-misc-new-2.5
parents
c9e54010
45f841b0
Changes
10
Hide whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
594 additions
and
635 deletions
+594
-635
drivers/scsi/53c700.c
drivers/scsi/53c700.c
+3
-3
drivers/scsi/NCR_D700.h
drivers/scsi/NCR_D700.h
+5
-5
drivers/scsi/hosts.c
drivers/scsi/hosts.c
+2
-131
drivers/scsi/hosts.h
drivers/scsi/hosts.h
+2
-0
drivers/scsi/osst.c
drivers/scsi/osst.c
+487
-445
drivers/scsi/osst.h
drivers/scsi/osst.h
+11
-10
drivers/scsi/scsi.c
drivers/scsi/scsi.c
+1
-19
drivers/scsi/scsi.h
drivers/scsi/scsi.h
+0
-3
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_lib.c
+5
-14
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_scan.c
+78
-5
No files found.
drivers/scsi/53c700.c
View file @
1b75d964
...
...
@@ -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
;
drivers/scsi/NCR_D700.h
View file @
1b75d964
...
...
@@ -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, \
}
...
...
drivers/scsi/hosts.c
View file @
1b75d964
...
...
@@ -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:
*/
drivers/scsi/hosts.h
View file @
1b75d964
...
...
@@ -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
{
...
...
drivers/scsi/osst.c
View file @
1b75d964
...
...
@@ -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 - 200
0 Kai Makisara
email Kai.Makisara@metla.fi
Copyright 1992 - 200
2 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.9
9.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 t
ape"
,
.
tag
=
"osst"
,
.
scsi_type
=
TYPE_TAPE
,
.
attach
=
osst_attach
,
.
detach
=
osst_detach
.
module
=
THIS_MODULE
,
.
list
=
LIST_HEAD_INIT
(
osst_template
.
list
),
.
name
=
"OnStream T
ape"
,
.
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
->
d
isk
->
disk_name
;
return
tape
->
d
rive
->
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
->
d
isk
;
SRpnt
->
sr_request
->
rq_disk
=
STp
->
d
rive
;
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_RE
AD_RE
TRIES
,
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_RE
AD_RE
TRIES
,
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_RE
AD_RE
TRIES
,
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_RE
ADY_RE
TRIES
,
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_RE
ADY_RE
TRIES
,
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_RE
ADY_RE
TRIES
,
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
,
ne
ed_dma_buffer
,
ne
w_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
;
d
isk
->
private_data
=
&
tpnt
->
driver
;
sprintf
(
d
isk
->
disk_name
,
"osst%d"
,
i
);
d
rive
->
private_data
=
&
tpnt
->
driver
;
sprintf
(
d
rive
->
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
\n
osst :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
\n
osst :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
"
);
}
...
...
drivers/scsi/osst.h
View file @
1b75d964
...
...
@@ -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 s
egments 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
*
d
isk
;
struct
gendisk
*
d
rive
;
}
OS_Scsi_Tape
;
/* Values of write_type */
...
...
drivers/scsi/scsi.c
View file @
1b75d964
...
...
@@ -169,30 +169,13 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt);
/*
* Function: scsi_initialize_queue()
*
* Purpose: Se
lects queue handler function
for a device.
* Purpose: Se
ts 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
"
));
...
...
drivers/scsi/scsi.h
View file @
1b75d964
...
...
@@ -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
);
...
...
drivers/scsi/scsi_lib.c
View file @
1b75d964
...
...
@@ -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
;
...
...
drivers/scsi/scsi_scan.c
View file @
1b75d964
...
...
@@ -472,8 +472,8 @@ static void scsi_initialize_merge_fn(struct scsi_device *sd)
* Return value:
* Scsi_Device pointer, or NULL on failure.
**/
st
ruct
scsi_device
*
scsi_alloc_sdev
(
struct
Scsi_Host
*
shost
,
uint
channel
,
uint
id
,
uint
lun
)
st
atic
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
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment