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
nexedi
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