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
7bfe7426
Commit
7bfe7426
authored
Apr 30, 2002
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Manual merge for problems between Al Viro's blocksize removal and
Douglas Gilbert's SCSI cleanups
parents
7831a09f
0e46579e
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
with
694 additions
and
399 deletions
+694
-399
drivers/scsi/sd.c
drivers/scsi/sd.c
+694
-399
No files found.
drivers/scsi/sd.c
View file @
7bfe7426
...
...
@@ -5,29 +5,28 @@
* Linux scsi disk driver
* Initial versions: Drew Eckhardt
* Subsequent revisions: Eric Youngdale
* Modification history:
* - Drew Eckhardt <drew@colorado.edu> original
* - Eric Youngdale <eric@andante.org> add scatter-gather, multiple
* outstanding request, and other enhancements.
* Support loadable low-level scsi drivers.
* - Jirka Hanika <geo@ff.cuni.cz> support more scsi disks using
* eight major numbers.
* - Richard Gooch <rgooch@atnf.csiro.au> support devfs.
* - Torben Mathiasen <tmm@image.dk> Resource allocation fixes in
* sd_init and cleanups.
* - Alex Davis <letmein@erols.com> Fix problem where partition info
* not being read in sd_open. Fix problem where removable media
* could be ejected after sd_open.
* - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5 series
*
* <drew@colorado.edu>
*
* Modified by Eric Youngdale ericy@andante.org to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
* Modified by Eric Youngdale eric@andante.org to support loadable
* low-level scsi drivers.
*
* Modified by Jirka Hanika geo@ff.cuni.cz to support more
* scsi disks using eight major numbers.
*
* Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs.
*
* Modified by Torben Mathiasen tmm@image.dk
* Resource allocation fixes in sd_init and cleanups.
*
* Modified by Alex Davis <letmein@erols.com>
* Fix problem where partition info not being read in sd_open.
*
* Modified by Alex Davis <letmein@erols.com>
* Fix problem where removable media could be ejected after sd_open.
* Logging policy (needs CONFIG_SCSI_LOGGING defined):
* - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2
* - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1
* - entering sd_ioctl: SCSI_LOG_IOCTL level 1
* - entering other commands: SCSI_LOG_HLQUEUE level 3
* Note: when the logging level is set by the user, it must be greater
* than the level indicated above to trigger output.
*/
#include <linux/config.h>
...
...
@@ -50,6 +49,7 @@
#include <asm/io.h>
#define MAJOR_NR SCSI_DISK0_MAJOR
#define LOCAL_END_REQUEST
#include <linux/blk.h>
#include <linux/blkpg.h>
#include "scsi.h"
...
...
@@ -61,6 +61,8 @@
#include <linux/genhd.h>
static
char
sd_version_str
[]
=
"Version: 2.0.3 (20020417)"
;
#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))
#define SCSI_DISKS_PER_MAJOR 16
...
...
@@ -79,16 +81,21 @@
#define SD_TIMEOUT (30 * HZ)
#define SD_MOD_TIMEOUT (75 * HZ)
#define SD_DSK_ARR_LUMP 6
/* amount to over allocate sd_dsk_arr by */
struct
hd_struct
*
sd
;
static
Scsi_Disk
*
rscsi_disks
;
static
Scsi_Disk
**
sd_dsk_arr
;
static
rwlock_t
sd_dsk_arr_lock
=
RW_LOCK_UNLOCKED
;
static
int
*
sd_sizes
;
static
int
*
sd_max_sectors
;
static
int
check_scsidisk_media_change
(
kdev_t
);
static
int
fop_revalidate_scsidisk
(
kdev_t
);
static
int
sd_init_onedisk
(
int
);
static
int
sd_init_onedisk
(
Scsi_Disk
*
sdkp
,
int
dsk_nr
);
static
int
sd_init
(
void
);
static
void
sd_finish
(
void
);
...
...
@@ -117,36 +124,81 @@ static struct Scsi_Device_Template sd_template = {
init_command:
sd_init_command
,
};
static
void
rw_intr
(
Scsi_Cmnd
*
SCpnt
);
static
void
sd_rw_intr
(
Scsi_Cmnd
*
SCpnt
);
static
Scsi_Disk
*
sd_get_sdisk
(
int
index
);
#if defined(CONFIG_PPC)
/*
* Moved from arch/ppc/pmac_setup.c. This is where it really belongs.
*/
/**
* sd_find_target - find kdev_t of first scsi disk that matches
* given host and scsi_id.
* @host: Scsi_Host object pointer that owns scsi device of interest
* @scsi_id: scsi (target) id number of device of interest
*
* Returns kdev_t of first scsi device that matches arguments or
* NODEV of no match.
*
* Notes: Looks like a hack, should scan for <host,channel,id,lin>
* tuple.
* [Architectural dependency: ppc only.] Moved here from
* arch/ppc/pmac_setup.c.
**/
kdev_t
__init
sd_find_target
(
void
*
h
ost
,
int
tgt
)
sd_find_target
(
void
*
h
p
,
int
scsi_id
)
{
Scsi_Disk
*
dp
;
int
i
;
for
(
dp
=
rscsi_disks
,
i
=
0
;
i
<
sd_template
.
dev_max
;
++
i
,
++
dp
)
if
(
dp
->
device
!=
NULL
&&
dp
->
device
->
host
==
host
&&
dp
->
device
->
id
==
tgt
)
return
MKDEV_SD
(
i
);
return
NODEV
;
Scsi_Disk
*
sdkp
;
Scsi_Device
*
sdp
;
Scsi_Host
*
shp
=
hp
;
int
dsk_nr
;
unsigned
long
iflags
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_find_target: host_nr=%d, "
"scsi_id=%d
\n
"
,
shp
->
host_no
,
scsi_id
));
read_lock_irqsave
(
&
sd_dsk_arr_lock
,
iflags
);
for
(
dsk_nr
=
0
;
dsk_nr
<
sd_template
.
dev_max
;
++
dsk_nr
)
{
if
(
NULL
==
(
sdkp
=
sd_dsk_arr
[
dsk_nr
]))
continue
;
sdp
=
sdkp
->
device
;
if
(
sdp
&&
(
sdp
->
host
==
shp
)
&&
(
sdp
->
id
==
scsi_id
))
{
read_unlock_irqrestore
(
&
sd_dsk_arr_lock
,
iflags
);
return
MKDEV_SD
(
k
);
}
}
read_unlock_irqrestore
(
&
sd_dsk_arr_lock
,
iflags
);
return
NODEV
;
}
#endif
static
int
sd_ioctl
(
struct
inode
*
inode
,
struct
file
*
file
,
unsigned
int
cmd
,
unsigned
long
arg
)
/**
* sd_ioctl - process an ioctl
* @inode: only i_rdev member may be used
* @filp: only f_mode and f_flags may be used
* @cmd: ioctl command number
* @arg: this is third argument given to ioctl(2) system call.
* Often contains a pointer.
*
* Returns 0 if successful (some ioctls return postive numbers on
* success as well). Returns a negated errno value in case of error.
*
* Note: most ioctls are forward onto the block subsystem or further
* down in the scsi subsytem.
**/
static
int
sd_ioctl
(
struct
inode
*
inode
,
struct
file
*
filp
,
unsigned
int
cmd
,
unsigned
long
arg
)
{
kdev_t
dev
=
inode
->
i_rdev
;
Scsi_Disk
*
sdkp
;
struct
Scsi_Host
*
host
;
Scsi_Device
*
SDev
;
Scsi_Device
*
sdp
;
int
diskinfo
[
4
];
int
dsk_nr
=
DEVICE_NR
(
dev
);
SDev
=
rscsi_disks
[
DEVICE_NR
(
dev
)].
device
;
if
(
!
SDev
)
SCSI_LOG_IOCTL
(
1
,
printk
(
"sd_ioctl: dsk_nr=%d, cmd=0x%x
\n
"
,
dsk_nr
,
cmd
));
sdkp
=
sd_get_sdisk
(
dsk_nr
);
if
((
NULL
==
sdkp
)
||
(
NULL
==
(
sdp
=
sdkp
->
device
)))
return
-
ENODEV
;
/*
* If we are in the middle of error recovery, don't let anyone
* else try and use this device. Also, if error recovery fails, it
...
...
@@ -154,10 +206,8 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
* access to the device is prohibited.
*/
if
(
!
scsi_block_when_processing_errors
(
SDev
)
)
{
if
(
!
scsi_block_when_processing_errors
(
sdp
)
)
return
-
ENODEV
;
}
switch
(
cmd
)
{
...
...
@@ -167,58 +217,59 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
if
(
!
loc
)
return
-
EINVAL
;
host
=
rscsi_disks
[
DEVICE_NR
(
dev
)].
device
->
host
;
host
=
sdp
->
host
;
/* default to most commonly used values */
diskinfo
[
0
]
=
0x40
;
diskinfo
[
1
]
=
0x20
;
diskinfo
[
2
]
=
rscsi_disks
[
DEVICE_NR
(
dev
)].
capacity
>>
11
;
diskinfo
[
2
]
=
sdkp
->
capacity
>>
11
;
/* override with calculated, extended default, or driver values */
/* override with calculated, extended default,
or driver values */
if
(
host
->
hostt
->
bios_param
!=
NULL
)
host
->
hostt
->
bios_param
(
&
rscsi_disks
[
DEVICE_NR
(
dev
)],
dev
,
&
diskinfo
[
0
]);
else
scsicam_bios_param
(
&
rscsi_disks
[
DEVICE_NR
(
dev
)],
dev
,
&
diskinfo
[
0
]);
host
->
hostt
->
bios_param
(
sdkp
,
dev
,
&
diskinfo
[
0
]);
else
scsicam_bios_param
(
sdkp
,
dev
,
&
diskinfo
[
0
]);
if
(
put_user
(
diskinfo
[
0
],
&
loc
->
heads
)
||
put_user
(
diskinfo
[
1
],
&
loc
->
sectors
)
||
put_user
(
diskinfo
[
2
],
&
loc
->
cylinders
)
||
put_user
((
unsigned
)
get_start_sect
(
inode
->
i_rdev
),
put_user
((
unsigned
)
get_start_sect
(
inode
->
i_rdev
),
(
unsigned
long
*
)
&
loc
->
start
))
return
-
EFAULT
;
return
0
;
}
case
HDIO_GETGEO_BIG
:
{
struct
hd_big_geometry
*
loc
=
(
struct
hd_big_geometry
*
)
arg
;
struct
hd_big_geometry
*
loc
=
(
struct
hd_big_geometry
*
)
arg
;
if
(
!
loc
)
return
-
EINVAL
;
host
=
rscsi_disks
[
DEVICE_NR
(
dev
)].
device
->
host
;
host
=
sdp
->
host
;
/* default to most commonly used values */
diskinfo
[
0
]
=
0x40
;
diskinfo
[
1
]
=
0x20
;
diskinfo
[
2
]
=
rscsi_disks
[
DEVICE_NR
(
dev
)].
capacity
>>
11
;
diskinfo
[
2
]
=
sdkp
->
capacity
>>
11
;
/* override with calculated, extended default, or driver values */
if
(
host
->
hostt
->
bios_param
!=
NULL
)
host
->
hostt
->
bios_param
(
&
rscsi_disks
[
DEVICE_NR
(
dev
)],
dev
,
&
diskinfo
[
0
]);
else
scsicam_bios_param
(
&
rscsi_disks
[
DEVICE_NR
(
dev
)],
dev
,
&
diskinfo
[
0
]);
/* override with calculated, extended default,
or driver values */
if
(
host
->
hostt
->
bios_param
!=
NULL
)
host
->
hostt
->
bios_param
(
sdkp
,
dev
,
&
diskinfo
[
0
]);
else
scsicam_bios_param
(
sdkp
,
dev
,
&
diskinfo
[
0
]);
if
(
put_user
(
diskinfo
[
0
],
&
loc
->
heads
)
||
put_user
(
diskinfo
[
1
],
&
loc
->
sectors
)
||
put_user
(
diskinfo
[
2
],
(
unsigned
int
*
)
&
loc
->
cylinders
)
||
put_user
((
unsigned
)
get_start_sect
(
inode
->
i_rdev
),
put_user
(
diskinfo
[
2
],
(
unsigned
int
*
)
&
loc
->
cylinders
)
||
put_user
((
unsigned
)
get_start_sect
(
inode
->
i_rdev
),
(
unsigned
long
*
)
&
loc
->
start
))
return
-
EFAULT
;
return
0
;
...
...
@@ -242,15 +293,14 @@ static int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd,
return
revalidate_scsidisk
(
dev
,
1
);
default:
return
scsi_ioctl
(
rscsi_disks
[
DEVICE_NR
(
dev
)].
device
,
cmd
,
(
void
*
)
arg
);
return
scsi_ioctl
(
sdp
,
cmd
,
(
void
*
)
arg
);
}
}
static
void
sd_d
evname
(
unsigned
int
disknum
,
char
*
buffer
)
static
void
sd_d
skname
(
unsigned
int
dsk_nr
,
char
*
buffer
)
{
if
(
d
isknum
<
26
)
sprintf
(
buffer
,
"sd%c"
,
'a'
+
d
isknum
);
if
(
d
sk_nr
<
26
)
sprintf
(
buffer
,
"sd%c"
,
'a'
+
d
sk_nr
);
else
{
unsigned
int
min1
;
unsigned
int
min2
;
...
...
@@ -258,67 +308,88 @@ static void sd_devname(unsigned int disknum, char *buffer)
* For larger numbers of disks, we need to go to a new
* naming scheme.
*/
min1
=
d
isknum
/
26
;
min2
=
d
isknum
%
26
;
min1
=
d
sk_nr
/
26
;
min2
=
d
sk_nr
%
26
;
sprintf
(
buffer
,
"sd%c%c"
,
'a'
+
min1
-
1
,
'a'
+
min2
);
}
}
/**
* sd_find_queue - yields queue associated with device
* @dev: kernel device descriptor (kdev_t)
*
* Returns NULL if no match, otherwise returns pointer to associated
* request queue.
*
* Note: this function is invoked (often) from the block subsystem
* and should not wait on anything (sd_get_sdisk() does have a read
* spinlock).
**/
static
request_queue_t
*
sd_find_queue
(
kdev_t
dev
)
{
Scsi_Disk
*
dpnt
;
int
target
;
target
=
DEVICE_NR
(
dev
);
Scsi_Disk
*
sdkp
;
int
dsk_nr
=
DEVICE_NR
(
dev
);
dpnt
=
&
rscsi_disks
[
target
];
if
(
!
dpnt
)
sdkp
=
sd_get_sdisk
(
dsk_nr
);
if
(
sdkp
&&
sdkp
->
device
)
return
&
sdkp
->
device
->
request_queue
;
else
return
NULL
;
/* No such device */
return
&
dpnt
->
device
->
request_queue
;
}
/**
* sd_init_command - build a scsi (read or write) command from
* information in the request structure.
* @SCpnt: pointer to mid-level's per scsi command structure that
* contains request and into which the scsi command is written
*
* Returns 1 if successful and 0 if error (or cannot be done now).
**/
static
int
sd_init_command
(
Scsi_Cmnd
*
SCpnt
)
{
int
d
ev
,
devm
,
block
,
this_count
;
Scsi_D
isk
*
dpnt
;
int
d
sk_nr
,
part_nr
,
block
,
this_count
;
Scsi_D
evice
*
sdp
;
#if CONFIG_SCSI_LOGGING
char
nbuff
[
6
];
#endif
/*
* don't support specials for nwo
*/
if
(
!
(
SCpnt
->
request
.
flags
&
REQ_CMD
))
return
0
;
devm
=
SD_PARTITION
(
SCpnt
->
request
.
rq_dev
);
d
ev
=
DEVICE_NR
(
SCpnt
->
request
.
rq_dev
);
part_nr
=
SD_PARTITION
(
SCpnt
->
request
.
rq_dev
);
d
sk_nr
=
DEVICE_NR
(
SCpnt
->
request
.
rq_dev
);
block
=
SCpnt
->
request
.
sector
;
this_count
=
SCpnt
->
request_bufflen
>>
9
;
SCSI_LOG_HLQUEUE
(
1
,
printk
(
"Doing sd request, dev = %d, block = %d
\n
"
,
devm
,
block
));
dpnt
=
&
rscsi_disks
[
dev
];
if
(
devm
>=
(
sd_template
.
dev_max
<<
4
)
||
(
devm
&
0xf
)
||
!
dpnt
||
!
dpnt
->
device
->
online
||
block
+
SCpnt
->
request
.
nr_sectors
>
sd
[
devm
].
nr_sects
)
{
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"Finishing %ld sectors
\n
"
,
SCpnt
->
request
.
nr_sectors
));
SCSI_LOG_HLQUEUE
(
1
,
printk
(
"sd_command_init: dsk_nr=%d, block=%d, "
"count=%d
\n
"
,
dsk_nr
,
block
,
this_count
));
sdp
=
SCpnt
->
device
;
/* >>>>> the "(part_nr & 0xf)" excludes 15th partition, why?? */
/* >>>>> this change is not in the lk 2.5 series */
if
(
part_nr
>=
(
sd_template
.
dev_max
<<
4
)
||
(
part_nr
&
0xf
)
||
!
sdp
||
!
sdp
->
online
||
block
+
SCpnt
->
request
.
nr_sectors
>
sd
[
part_nr
].
nr_sects
)
{
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"Finishing %ld sectors
\n
"
,
SCpnt
->
request
.
nr_sectors
));
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"Retry with 0x%p
\n
"
,
SCpnt
));
return
0
;
}
if
(
dpnt
->
device
->
changed
)
{
if
(
sdp
->
changed
)
{
/*
* quietly refuse to do anything to a changed disc until
the changed
* bit has been reset
* quietly refuse to do anything to a changed disc until
*
the changed
bit has been reset
*/
/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
return
0
;
}
SCSI_LOG_HLQUEUE
(
2
,
sd_d
evname
(
devm
,
nbuff
));
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"%s :
real dev = /dev/%d, block =
%d
\n
"
,
nbuff
,
dev
,
block
));
SCSI_LOG_HLQUEUE
(
2
,
sd_d
skname
(
dsk_nr
,
nbuff
));
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"%s :
[part_nr=%d], block=
%d
\n
"
,
nbuff
,
part_nr
,
block
));
/*
* If we have a 1K hardware sectorsize, prevent access to single
...
...
@@ -331,27 +402,27 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
* and not force the scsi disk driver to use bounce buffers
* for this.
*/
if
(
dpnt
->
device
->
sector_size
==
1024
)
{
if
(
sdp
->
sector_size
==
1024
)
{
if
((
block
&
1
)
||
(
SCpnt
->
request
.
nr_sectors
&
1
))
{
printk
(
"sd.c:
Bad block number requested"
);
printk
(
KERN_ERR
"sd:
Bad block number requested"
);
return
0
;
}
else
{
block
=
block
>>
1
;
this_count
=
this_count
>>
1
;
}
}
if
(
dpnt
->
device
->
sector_size
==
2048
)
{
if
(
sdp
->
sector_size
==
2048
)
{
if
((
block
&
3
)
||
(
SCpnt
->
request
.
nr_sectors
&
3
))
{
printk
(
"sd.c:
Bad block number requested"
);
printk
(
KERN_ERR
"sd:
Bad block number requested"
);
return
0
;
}
else
{
block
=
block
>>
2
;
this_count
=
this_count
>>
2
;
}
}
if
(
dpnt
->
device
->
sector_size
==
4096
)
{
if
(
sdp
->
sector_size
==
4096
)
{
if
((
block
&
7
)
||
(
SCpnt
->
request
.
nr_sectors
&
7
))
{
printk
(
"sd.c:
Bad block number requested"
);
printk
(
KERN_ERR
"sd:
Bad block number requested"
);
return
0
;
}
else
{
block
=
block
>>
3
;
...
...
@@ -359,7 +430,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
}
}
if
(
rq_data_dir
(
&
SCpnt
->
request
)
==
WRITE
)
{
if
(
!
dpnt
->
device
->
writeable
)
{
if
(
!
sdp
->
writeable
)
{
return
0
;
}
SCpnt
->
cmnd
[
0
]
=
WRITE_6
;
...
...
@@ -367,13 +438,16 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
}
else
if
(
rq_data_dir
(
&
SCpnt
->
request
)
==
READ
)
{
SCpnt
->
cmnd
[
0
]
=
READ_6
;
SCpnt
->
sc_data_direction
=
SCSI_DATA_READ
;
}
else
panic
(
"Unknown sd command %lx
\n
"
,
SCpnt
->
request
.
flags
);
}
else
{
printk
(
KERN_ERR
"sd: Unknown command %lx
\n
"
,
SCpnt
->
request
.
flags
);
/* overkill panic("Unknown sd command %lx\n", SCpnt->request.flags); */
return
0
;
}
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"%s : %s %d/%ld 512 byte blocks.
\n
"
,
nbuff
,
(
rq_data_dir
(
&
SCpnt
->
request
)
==
WRITE
)
?
"writing"
:
"reading"
,
this_count
,
SCpnt
->
request
.
nr_sectors
));
SCSI_LOG_HLQUEUE
(
2
,
printk
(
"%s : %s %d/%ld 512 byte blocks.
\n
"
,
nbuff
,
(
rq_data_dir
(
&
SCpnt
->
request
)
==
WRITE
)
?
"writing"
:
"reading"
,
this_count
,
SCpnt
->
request
.
nr_sectors
));
SCpnt
->
cmnd
[
1
]
=
(
SCpnt
->
device
->
scsi_level
<=
SCSI_2
)
?
((
SCpnt
->
lun
<<
5
)
&
0xe0
)
:
0
;
...
...
@@ -406,7 +480,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
* host adapter, it's safe to assume that we can at least transfer
* this many bytes between each connect / disconnect.
*/
SCpnt
->
transfersize
=
dpnt
->
device
->
sector_size
;
SCpnt
->
transfersize
=
sdp
->
sector_size
;
SCpnt
->
underflow
=
this_count
<<
9
;
SCpnt
->
allowed
=
MAX_RETRIES
;
...
...
@@ -417,7 +491,7 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
* This is the completion routine we use. This is matched in terms
* of capability to this function.
*/
SCpnt
->
done
=
rw_intr
;
SCpnt
->
done
=
sd_
rw_intr
;
/*
* This indicates that the command is ready from our end to be
...
...
@@ -426,31 +500,46 @@ static int sd_init_command(Scsi_Cmnd * SCpnt)
return
1
;
}
/**
* sd_open - open a scsi disk device
* @inode: only i_rdev member may be used
* @filp: only f_mode and f_flags may be used
*
* Returns 0 if successful. Returns a negated errno value in case
* of error.
*
* Note: This can be called from a user context (e.g. fsck(1) )
* or from within the kernel (e.g. as a result of a mount(1) ).
* In the latter case @inode and @filp carry an abridged amount
* of information as noted above.
**/
static
int
sd_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
int
target
,
retval
=
-
ENXIO
;
Scsi_Device
*
SDev
;
target
=
DEVICE_NR
(
inode
->
i_rdev
);
int
retval
=
-
ENXIO
;
Scsi_Device
*
sdp
;
Scsi_Disk
*
sdkp
;
int
dsk_nr
=
DEVICE_NR
(
inode
->
i_rdev
);
SCSI_LOG_HLQUEUE
(
1
,
printk
(
"target=%d, max=%d
\n
"
,
target
,
sd_template
.
dev_max
));
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_open: dsk_nr=%d, part_nr=%d
\n
"
,
dsk_nr
,
SD_PARTITION
(
inode
->
i_rdev
)));
if
(
target
>=
sd_template
.
dev_max
||
!
rscsi_disks
[
target
].
device
)
sdkp
=
sd_get_sdisk
(
dsk_nr
);
if
((
NULL
==
sdkp
)
||
(
NULL
==
(
sdp
=
sdkp
->
device
)))
return
-
ENXIO
;
/* No such device */
/*
* If the device is in error recovery, wait until it is done.
* If the device is offline, then disallow any access to it.
*/
if
(
!
scsi_block_when_processing_errors
(
rscsi_disks
[
target
].
device
))
{
if
(
!
scsi_block_when_processing_errors
(
sdp
))
return
-
ENXIO
;
}
/*
* Make sure that only one process can do a check_change_disk at
one time.
*
This is also used to lock out further access when the partition table
* is being re-read.
* Make sure that only one process can do a check_change_disk at
*
one time. This is also used to lock out further access when
*
the partition table
is being re-read.
*/
while
(
rscsi_disks
[
target
].
device
->
busy
)
{
while
(
sdp
->
busy
)
{
barrier
();
cpu_relax
();
}
...
...
@@ -458,22 +547,21 @@ static int sd_open(struct inode *inode, struct file *filp)
* The following code can sleep.
* Module unloading must be prevented
*/
SDev
=
rscsi_disks
[
target
].
device
;
if
(
SDev
->
host
->
hostt
->
module
)
__MOD_INC_USE_COUNT
(
SDev
->
host
->
hostt
->
module
);
if
(
sdp
->
host
->
hostt
->
module
)
__MOD_INC_USE_COUNT
(
sdp
->
host
->
hostt
->
module
);
if
(
sd_template
.
module
)
__MOD_INC_USE_COUNT
(
sd_template
.
module
);
SDev
->
access_count
++
;
sdp
->
access_count
++
;
if
(
rscsi_disks
[
target
].
device
->
removable
)
{
SDev
->
allow_revalidate
=
1
;
if
(
sdp
->
removable
)
{
sdp
->
allow_revalidate
=
1
;
check_disk_change
(
inode
->
i_rdev
);
SDev
->
allow_revalidate
=
0
;
sdp
->
allow_revalidate
=
0
;
/*
* If the drive is empty, just let the open fail.
*/
if
((
!
rscsi_disks
[
target
].
ready
)
&&
!
(
filp
->
f_flags
&
O_NDELAY
))
{
if
((
!
sdkp
->
ready
)
&&
!
(
filp
->
f_flags
&
O_NDELAY
))
{
retval
=
-
ENOMEDIUM
;
goto
error_out
;
}
...
...
@@ -483,7 +571,7 @@ static int sd_open(struct inode *inode, struct file *filp)
* have the open fail if the user expects to be able to write
* to the thing.
*/
if
((
rscsi_disks
[
target
].
write_prot
)
&&
(
filp
->
f_mode
&
2
))
{
if
((
sdkp
->
write_prot
)
&&
(
filp
->
f_mode
&
FMODE_WRITE
))
{
retval
=
-
EROFS
;
goto
error_out
;
}
...
...
@@ -494,7 +582,7 @@ static int sd_open(struct inode *inode, struct file *filp)
* and don't pretend that
* the open actually succeeded.
*/
if
(
!
SDev
->
online
)
{
if
(
!
sdp
->
online
)
{
goto
error_out
;
}
/*
...
...
@@ -505,42 +593,57 @@ static int sd_open(struct inode *inode, struct file *filp)
goto
error_out
;
}
if
(
SDev
->
removable
)
if
(
SDev
->
access_count
==
1
)
if
(
scsi_block_when_processing_errors
(
SDev
))
scsi_ioctl
(
SDev
,
SCSI_IOCTL_DOORLOCK
,
NULL
);
if
(
sdp
->
removable
)
if
(
sdp
->
access_count
==
1
)
if
(
scsi_block_when_processing_errors
(
sdp
))
scsi_ioctl
(
sdp
,
SCSI_IOCTL_DOORLOCK
,
NULL
);
return
0
;
error_out:
SDev
->
access_count
--
;
if
(
SDev
->
host
->
hostt
->
module
)
__MOD_DEC_USE_COUNT
(
SDev
->
host
->
hostt
->
module
);
sdp
->
access_count
--
;
if
(
sdp
->
host
->
hostt
->
module
)
__MOD_DEC_USE_COUNT
(
sdp
->
host
->
hostt
->
module
);
if
(
sd_template
.
module
)
__MOD_DEC_USE_COUNT
(
sd_template
.
module
);
return
retval
;
}
static
int
sd_release
(
struct
inode
*
inode
,
struct
file
*
file
)
/**
* sd_release - invoked when the (last) close(2) is called on this
* scsi disk.
* @inode: only i_rdev member may be used
* @filp: only f_mode and f_flags may be used
*
* Returns 0.
*
* Note: may block (uninterruptible) if error recovery is underway
* on this disk.
**/
static
int
sd_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
int
target
;
Scsi_Device
*
SDev
;
Scsi_Disk
*
sdkp
;
int
dsk_nr
=
DEVICE_NR
(
inode
->
i_rdev
);
Scsi_Device
*
sdp
;
target
=
DEVICE_NR
(
inode
->
i_rdev
);
SDev
=
rscsi_disks
[
target
].
device
;
if
(
!
SDev
)
return
-
ENODEV
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_release: dsk_nr=%d, part_nr=%d
\n
"
,
dsk_nr
,
SD_PARTITION
(
inode
->
i_rdev
)));
sdkp
=
sd_get_sdisk
(
dsk_nr
);
if
((
NULL
==
sdkp
)
||
(
NULL
==
(
sdp
=
sdkp
->
device
)))
return
-
ENODEV
;
/* open uses ENXIO ?? */
/* ... and what if there are packets in flight and this close()
* is followed by a "rmmod sd_mod" */
SDev
->
access_count
--
;
sdp
->
access_count
--
;
if
(
SDev
->
removable
)
{
if
(
!
SDev
->
access_count
)
if
(
scsi_block_when_processing_errors
(
SDev
))
scsi_ioctl
(
SDev
,
SCSI_IOCTL_DOORUNLOCK
,
NULL
);
if
(
sdp
->
removable
)
{
if
(
!
sdp
->
access_count
)
if
(
scsi_block_when_processing_errors
(
sdp
))
scsi_ioctl
(
sdp
,
SCSI_IOCTL_DOORUNLOCK
,
NULL
);
}
if
(
SDev
->
host
->
hostt
->
module
)
__MOD_DEC_USE_COUNT
(
SDev
->
host
->
hostt
->
module
);
if
(
sdp
->
host
->
hostt
->
module
)
__MOD_DEC_USE_COUNT
(
sdp
->
host
->
hostt
->
module
);
if
(
sd_template
.
module
)
__MOD_DEC_USE_COUNT
(
sd_template
.
module
);
return
0
;
...
...
@@ -558,7 +661,7 @@ static struct block_device_operations sd_fops =
/*
* If we need more than one SCSI disk major (i.e. more than
* 16 SCSI disks), we'll have to
k
malloc() more gendisks later.
* 16 SCSI disks), we'll have to
v
malloc() more gendisks later.
*/
static
struct
gendisk
sd_gendisk
=
...
...
@@ -573,30 +676,34 @@ static struct gendisk *sd_gendisks = &sd_gendisk;
#define SD_GENDISK(i) sd_gendisks[(i) / SCSI_DISKS_PER_MAJOR]
/*
* rw_intr is the interrupt routine for the device driver.
* It will be notified on the end of a SCSI read / write, and
* will take one of several actions based on success or failure.
*/
static
void
rw_intr
(
Scsi_Cmnd
*
SCpnt
)
/**
* sd_rw_intr - bottom half handler: called when the lower level
* driver has completed (successfully or otherwise) a scsi command.
* @SCpnt: mid-level's per command structure.
*
* Note: potentially run from within an ISR. Must not block.
**/
static
void
sd_rw_intr
(
Scsi_Cmnd
*
SCpnt
)
{
int
result
=
SCpnt
->
result
;
#if CONFIG_SCSI_LOGGING
char
nbuff
[
6
];
#endif
int
this_count
=
SCpnt
->
bufflen
>>
9
;
int
good_sectors
=
(
result
==
0
?
this_count
:
0
);
int
block_sectors
=
1
;
long
error_sector
;
#if CONFIG_SCSI_LOGGING
char
nbuff
[
6
];
SCSI_LOG_HLCOMPLETE
(
1
,
sd_devname
(
DEVICE_NR
(
SCpnt
->
request
.
rq_dev
),
nbuff
));
SCSI_LOG_HLCOMPLETE
(
1
,
printk
(
"%s : rw_intr(%d, %x [%x %x])
\n
"
,
nbuff
,
SCpnt
->
host
->
host_no
,
result
,
SCpnt
->
sense_buffer
[
0
],
SCpnt
->
sense_buffer
[
2
]));
SCSI_LOG_HLCOMPLETE
(
1
,
sd_dskname
(
DEVICE_NR
(
SCpnt
->
request
.
rq_dev
),
nbuff
));
SCSI_LOG_HLCOMPLETE
(
1
,
printk
(
"sd_rw_intr: %s: res=0x%x
\n
"
,
nbuff
,
result
));
if
(
0
!=
result
)
{
SCSI_LOG_HLCOMPLETE
(
1
,
printk
(
"sd_rw_intr: sb[0,2,asc,ascq]"
"=%x,%x,%x,%x
\n
"
,
SCpnt
->
sense_buffer
[
0
],
SCpnt
->
sense_buffer
[
2
],
SCpnt
->
sense_buffer
[
12
],
SCpnt
->
sense_buffer
[
13
]));
}
#endif
/*
Handle MEDIUM ERRORs that indicate partial success. Since this is a
relatively rare error condition, no care is taken to avoid
...
...
@@ -604,10 +711,11 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
*/
/* An error occurred */
if
(
driver_byte
(
result
)
!=
0
)
{
/* Sense data is valid */
if
(
SCpnt
->
sense_buffer
[
0
]
==
0xF0
&&
SCpnt
->
sense_buffer
[
2
]
==
MEDIUM_ERROR
)
{
long
error_sector
=
(
SCpnt
->
sense_buffer
[
3
]
<<
24
)
|
if
(
driver_byte
(
result
)
!=
0
&&
/* An error occured */
SCpnt
->
sense_buffer
[
0
]
!=
0xF0
)
{
/* Sense data is valid */
switch
(
SCpnt
->
sense_buffer
[
2
])
{
case
MEDIUM_ERROR
:
error_sector
=
(
SCpnt
->
sense_buffer
[
3
]
<<
24
)
|
(
SCpnt
->
sense_buffer
[
4
]
<<
16
)
|
(
SCpnt
->
sense_buffer
[
5
]
<<
8
)
|
SCpnt
->
sense_buffer
[
6
];
...
...
@@ -640,13 +748,30 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
good_sectors
=
error_sector
-
SCpnt
->
request
.
sector
;
if
(
good_sectors
<
0
||
good_sectors
>=
this_count
)
good_sectors
=
0
;
}
if
(
SCpnt
->
sense_buffer
[
2
]
==
ILLEGAL_REQUEST
)
{
break
;
case
RECOVERED_ERROR
:
/*
* An error occured, but it recovered. Inform the
* user, but make sure that it's not treated as a
* hard error.
*/
print_sense
(
"sd"
,
SCpnt
);
result
=
0
;
SCpnt
->
sense_buffer
[
0
]
=
0x0
;
good_sectors
=
this_count
;
break
;
case
ILLEGAL_REQUEST
:
if
(
SCpnt
->
device
->
ten
==
1
)
{
if
(
SCpnt
->
cmnd
[
0
]
==
READ_10
||
SCpnt
->
cmnd
[
0
]
==
WRITE_10
)
SCpnt
->
device
->
ten
=
0
;
}
break
;
default:
break
;
}
}
/*
...
...
@@ -656,28 +781,33 @@ static void rw_intr(Scsi_Cmnd * SCpnt)
*/
scsi_io_completion
(
SCpnt
,
good_sectors
,
block_sectors
);
}
/*
* requeue_sd_request() is the request handler function for the sd driver.
* Its function in life is to take block device requests, and translate
* them to SCSI commands.
*/
/**
* check_scsidisk_media_change - self descriptive
* @full_dev: kernel device descriptor (kdev_t)
*
* Returns 0 if not applicable or no change; 1 if change
*
* Note: this function is invoked from the block subsystem.
**/
static
int
check_scsidisk_media_change
(
kdev_t
full_dev
)
{
int
retval
;
int
target
;
int
flag
=
0
;
Scsi_Device
*
SDev
;
target
=
DEVICE_NR
(
full_dev
);
SDev
=
rscsi_disks
[
target
].
device
;
if
(
target
>=
sd_template
.
dev_max
||
!
SDev
)
{
printk
(
"SCSI disk request error: invalid device.
\n
"
);
int
flag
=
0
;
/* <<<< what is this for?? */
Scsi_Disk
*
sdkp
;
Scsi_Device
*
sdp
;
int
dsk_nr
=
DEVICE_NR
(
full_dev
);
sdkp
=
sd_get_sdisk
(
dsk_nr
);
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"check_scsidisk_media_change: "
"dsk_nr=%d
\n
"
,
dsk_nr
));
if
((
NULL
==
sdkp
)
||
(
NULL
==
(
sdp
=
sdkp
->
device
)))
{
printk
(
KERN_ERR
"check_scsidisk_media_change: dsk_nr=%d, "
"invalid device
\n
"
,
dsk_nr
);
return
0
;
}
if
(
!
SDev
->
removable
)
if
(
!
sdp
->
removable
)
return
0
;
/*
...
...
@@ -686,9 +816,9 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* can deal with it then. It is only because of unrecoverable errors
* that we would ever take a device offline in the first place.
*/
if
(
SDev
->
online
==
FALSE
)
{
rscsi_disks
[
target
].
ready
=
0
;
SDev
->
changed
=
1
;
if
(
sdp
->
online
==
FALSE
)
{
sdkp
->
ready
=
0
;
sdp
->
changed
=
1
;
return
1
;
/* This will force a flush, if called from
* check_disk_change */
}
...
...
@@ -700,8 +830,8 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* as this will spin up the drive.
*/
retval
=
-
ENODEV
;
if
(
scsi_block_when_processing_errors
(
SDev
))
retval
=
scsi_ioctl
(
SDev
,
SCSI_IOCTL_START_UNIT
,
NULL
);
if
(
scsi_block_when_processing_errors
(
sdp
))
retval
=
scsi_ioctl
(
sdp
,
SCSI_IOCTL_START_UNIT
,
NULL
);
if
(
retval
)
{
/* Unable to test, unit probably not ready.
* This usually means there is no disc in the
...
...
@@ -709,8 +839,8 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* it out later once the drive is available
* again. */
rscsi_disks
[
target
].
ready
=
0
;
SDev
->
changed
=
1
;
sdkp
->
ready
=
0
;
sdp
->
changed
=
1
;
return
1
;
/* This will force a flush, if called from
* check_disk_change */
}
...
...
@@ -720,15 +850,26 @@ static int check_scsidisk_media_change(kdev_t full_dev)
* struct and tested at open ! Daniel Roche ( dan@lectra.fr )
*/
rscsi_disks
[
target
].
ready
=
1
;
/* FLOPTICAL */
sdkp
->
ready
=
1
;
/* FLOPTICAL */
retval
=
SDev
->
changed
;
retval
=
sdp
->
changed
;
if
(
!
flag
)
SDev
->
changed
=
0
;
sdp
->
changed
=
0
;
return
retval
;
}
static
int
sd_init_onedisk
(
int
i
)
/**
* sd_init_onedisk - called the first time a new disk is seen,
* performs read_capacity, disk spin up (as required), etc.
* @sdkp: pointer to associated Scsi_Disk object
* @dsk_nr: disk number within this driver (e.g. 0->/dev/sda,
* 1->/dev/sdb, etc)
*
* Returns dsk_nr (pointless)
*
* Note: this function is local to this driver.
**/
static
int
sd_init_onedisk
(
Scsi_Disk
*
sdkp
,
int
dsk_nr
)
{
unsigned
char
cmd
[
10
];
char
nbuff
[
6
];
...
...
@@ -736,19 +877,23 @@ static int sd_init_onedisk(int i)
unsigned
long
spintime_value
=
0
;
int
the_result
,
retries
,
spintime
;
int
sector_size
;
Scsi_Device
*
sdp
;
Scsi_Request
*
SRpnt
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_init_onedisk: dsk_nr=%d
\n
"
,
dsk_nr
));
/*
* Get the name of the disk, in case we need to log it somewhere.
*/
sd_d
evname
(
i
,
nbuff
);
sd_d
skname
(
dsk_nr
,
nbuff
);
/*
* If the device is offline, don't try and read capacity or any
* of the other niceties.
*/
if
(
rscsi_disks
[
i
].
device
->
online
==
FALSE
)
return
i
;
sdp
=
sdkp
->
device
;
if
(
sdp
->
online
==
FALSE
)
return
dsk_nr
;
/*
* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
...
...
@@ -756,17 +901,19 @@ static int sd_init_onedisk(int i)
* just after a scsi bus reset.
*/
SRpnt
=
scsi_allocate_request
(
rscsi_disks
[
i
].
device
);
SRpnt
=
scsi_allocate_request
(
sdp
);
if
(
!
SRpnt
)
{
printk
(
KERN_WARNING
"(sd_init_onedisk:) Request allocation failure.
\n
"
);
return
i
;
printk
(
KERN_WARNING
"(sd_init_onedisk:) Request allocation "
"failure.
\n
"
);
return
dsk_nr
;
}
buffer
=
kmalloc
(
512
,
GFP_DMA
);
if
(
!
buffer
)
{
printk
(
KERN_WARNING
"(sd_init_onedisk:) Memory allocation failure.
\n
"
);
printk
(
KERN_WARNING
"(sd_init_onedisk:) Memory allocation "
"failure.
\n
"
);
scsi_release_request
(
SRpnt
);
return
i
;
return
dsk_nr
;
}
spintime
=
0
;
...
...
@@ -778,8 +925,8 @@ static int sd_init_onedisk(int i)
while
(
retries
<
3
)
{
cmd
[
0
]
=
TEST_UNIT_READY
;
cmd
[
1
]
=
(
rscsi_disks
[
i
].
device
->
scsi_level
<=
SCSI_2
)
?
((
rscsi_disks
[
i
].
device
->
lun
<<
5
)
&
0xe0
)
:
0
;
cmd
[
1
]
=
(
sdp
->
scsi_level
<=
SCSI_2
)
?
((
sdp
->
lun
<<
5
)
&
0xe0
)
:
0
;
memset
((
void
*
)
&
cmd
[
2
],
0
,
8
);
SRpnt
->
sr_cmd_len
=
0
;
SRpnt
->
sr_sense_buffer
[
0
]
=
0
;
...
...
@@ -805,23 +952,24 @@ static int sd_init_onedisk(int i)
&&
((
driver_byte
(
the_result
)
&
DRIVER_SENSE
)
!=
0
)
&&
SRpnt
->
sr_sense_buffer
[
2
]
==
UNIT_ATTENTION
&&
SRpnt
->
sr_sense_buffer
[
12
]
==
0x3A
)
{
rscsi_disks
[
i
].
capacity
=
0x1fffff
;
sdkp
->
capacity
=
0x1fffff
;
sector_size
=
512
;
rscsi_disks
[
i
].
device
->
changed
=
1
;
rscsi_disks
[
i
].
ready
=
0
;
sdp
->
changed
=
1
;
sdkp
->
ready
=
0
;
break
;
}
/* Look for non-removable devices that return NOT_READY.
* Issue command to spin up drive for these cases. */
if
(
the_result
&&
!
rscsi_disks
[
i
].
device
->
removable
&&
if
(
the_result
&&
!
sdp
->
removable
&&
SRpnt
->
sr_sense_buffer
[
2
]
==
NOT_READY
)
{
unsigned
long
time1
;
if
(
!
spintime
)
{
printk
(
"%s: Spinning up disk..."
,
nbuff
);
printk
(
KERN_NOTICE
"%s: Spinning up disk..."
,
nbuff
);
cmd
[
0
]
=
START_STOP
;
cmd
[
1
]
=
(
rscsi_disks
[
i
].
device
->
scsi_level
<=
SCSI_2
)
?
((
rscsi_disks
[
i
].
device
->
lun
<<
5
)
&
0xe0
)
:
0
;
cmd
[
1
]
=
(
sdp
->
scsi_level
<=
SCSI_2
)
?
((
sdp
->
lun
<<
5
)
&
0xe0
)
:
0
;
cmd
[
1
]
|=
1
;
/* Return immediately */
memset
((
void
*
)
&
cmd
[
2
],
0
,
8
);
cmd
[
4
]
=
1
;
/* Start spin cycle */
...
...
@@ -830,8 +978,9 @@ static int sd_init_onedisk(int i)
SRpnt
->
sr_sense_buffer
[
2
]
=
0
;
SRpnt
->
sr_data_direction
=
SCSI_DATA_READ
;
scsi_wait_req
(
SRpnt
,
(
void
*
)
cmd
,
(
void
*
)
buffer
,
0
/*512*/
,
SD_TIMEOUT
,
MAX_RETRIES
);
scsi_wait_req
(
SRpnt
,
(
void
*
)
cmd
,
(
void
*
)
buffer
,
0
/*512*/
,
SD_TIMEOUT
,
MAX_RETRIES
);
spintime_value
=
jiffies
;
}
spintime
=
1
;
...
...
@@ -854,8 +1003,8 @@ static int sd_init_onedisk(int i)
retries
=
3
;
do
{
cmd
[
0
]
=
READ_CAPACITY
;
cmd
[
1
]
=
(
rscsi_disks
[
i
].
device
->
scsi_level
<=
SCSI_2
)
?
((
rscsi_disks
[
i
].
device
->
lun
<<
5
)
&
0xe0
)
:
0
;
cmd
[
1
]
=
(
sdp
->
scsi_level
<=
SCSI_2
)
?
((
sdp
->
lun
<<
5
)
&
0xe0
)
:
0
;
memset
((
void
*
)
&
cmd
[
2
],
0
,
8
);
memset
((
void
*
)
buffer
,
0
,
8
);
SRpnt
->
sr_cmd_len
=
0
;
...
...
@@ -887,8 +1036,8 @@ static int sd_init_onedisk(int i)
*/
if
(
the_result
)
{
printk
(
"%s : READ CAPACITY failed.
\n
"
"%s : status
= %x, message = %02x, host = %d, driver =
%02x
\n
"
,
printk
(
KERN_NOTICE
"%s : READ CAPACITY failed.
\n
"
"%s : status
=%x, message=%02x, host=%d, driver=
%02x
\n
"
,
nbuff
,
nbuff
,
status_byte
(
the_result
),
msg_byte
(
the_result
),
...
...
@@ -900,50 +1049,50 @@ static int sd_init_onedisk(int i)
else
printk
(
"%s : sense not available.
\n
"
,
nbuff
);
printk
(
"%s : block size assumed to be 512 bytes, disk size 1GB.
\n
"
,
nbuff
);
rscsi_disks
[
i
].
capacity
=
0x1fffff
;
printk
(
KERN_NOTICE
"%s : block size assumed to be 512 "
"bytes, disk size 1GB.
\n
"
,
nbuff
);
sdkp
->
capacity
=
0x1fffff
;
sector_size
=
512
;
/* Set dirty bit for removable devices if not ready -
* sometimes drives will not report this properly. */
if
(
rscsi_disks
[
i
].
device
->
removable
&&
if
(
sdp
->
removable
&&
SRpnt
->
sr_sense_buffer
[
2
]
==
NOT_READY
)
rscsi_disks
[
i
].
device
->
changed
=
1
;
sdp
->
changed
=
1
;
}
else
{
/*
* FLOPTICAL, if read_capa is ok, drive is assumed to be ready
*/
rscsi_disks
[
i
].
ready
=
1
;
sdkp
->
ready
=
1
;
rscsi_disks
[
i
].
capacity
=
1
+
((
buffer
[
0
]
<<
24
)
|
(
buffer
[
1
]
<<
16
)
|
(
buffer
[
2
]
<<
8
)
|
buffer
[
3
]);
sdkp
->
capacity
=
1
+
((
buffer
[
0
]
<<
24
)
|
(
buffer
[
1
]
<<
16
)
|
(
buffer
[
2
]
<<
8
)
|
buffer
[
3
]);
sector_size
=
(
buffer
[
4
]
<<
24
)
|
(
buffer
[
5
]
<<
16
)
|
(
buffer
[
6
]
<<
8
)
|
buffer
[
7
];
if
(
sector_size
==
0
)
{
sector_size
=
512
;
printk
(
"%s : sector size 0 reported, assuming 512.
\n
"
,
nbuff
);
printk
(
KERN_NOTICE
"%s : sector size 0 reported, "
"assuming 512.
\n
"
,
nbuff
);
}
if
(
sector_size
!=
512
&&
sector_size
!=
1024
&&
sector_size
!=
2048
&&
sector_size
!=
4096
&&
sector_size
!=
256
)
{
printk
(
"%s : unsupported sector size %d.
\n
"
,
nbuff
,
sector_size
);
printk
(
KERN_NOTICE
"%s : unsupported sector size "
"%d.
\n
"
,
nbuff
,
sector_size
);
/*
* The user might want to re-format the drive with
* a supported sectorsize. Once this happens, it
* would be relatively trivial to set the thing up.
* For this reason, we leave the thing in the table.
*/
rscsi_disks
[
i
].
capacity
=
0
;
sdkp
->
capacity
=
0
;
}
{
/*
...
...
@@ -952,33 +1101,33 @@ static int sd_init_onedisk(int i)
* Jacques Gelinas (Jacques@solucorp.qc.ca)
*/
int
hard_sector
=
sector_size
;
int
sz
=
rscsi_disks
[
i
].
capacity
*
(
hard_sector
/
256
);
request_queue_t
*
queue
=
&
rscsi_disks
[
i
].
device
->
request_queue
;
int
sz
=
sdkp
->
capacity
*
(
hard_sector
/
256
);
request_queue_t
*
queue
=
&
sdp
->
request_queue
;
blk_queue_hardsect_size
(
queue
,
hard_sector
);
printk
(
"SCSI device %s: "
printk
(
KERN_NOTICE
"SCSI device %s: "
"%d %d-byte hdwr sectors (%d MB)
\n
"
,
nbuff
,
rscsi_disks
[
i
].
capacity
,
nbuff
,
sdkp
->
capacity
,
hard_sector
,
(
sz
/
2
-
sz
/
1250
+
974
)
/
1950
);
}
/* Rescale capacity to 512-byte units */
if
(
sector_size
==
4096
)
rscsi_disks
[
i
].
capacity
<<=
3
;
sdkp
->
capacity
<<=
3
;
if
(
sector_size
==
2048
)
rscsi_disks
[
i
].
capacity
<<=
2
;
sdkp
->
capacity
<<=
2
;
if
(
sector_size
==
1024
)
rscsi_disks
[
i
].
capacity
<<=
1
;
sdkp
->
capacity
<<=
1
;
if
(
sector_size
==
256
)
rscsi_disks
[
i
].
capacity
>>=
1
;
sdkp
->
capacity
>>=
1
;
}
/*
* Unless otherwise specified, this is not write protected.
*/
rscsi_disks
[
i
].
write_prot
=
0
;
if
(
rscsi_disks
[
i
].
device
->
removable
&&
rscsi_disks
[
i
].
ready
)
{
sdkp
->
write_prot
=
0
;
if
(
sdp
->
removable
&&
sdkp
->
ready
)
{
/* FLOPTICAL */
/*
...
...
@@ -996,8 +1145,8 @@ static int sd_init_onedisk(int i)
memset
((
void
*
)
&
cmd
[
0
],
0
,
8
);
cmd
[
0
]
=
MODE_SENSE
;
cmd
[
1
]
=
(
rscsi_disks
[
i
].
device
->
scsi_level
<=
SCSI_2
)
?
((
rscsi_disks
[
i
].
device
->
lun
<<
5
)
&
0xe0
)
:
0
;
cmd
[
1
]
=
(
sdp
->
scsi_level
<=
SCSI_2
)
?
((
sdp
->
lun
<<
5
)
&
0xe0
)
:
0
;
cmd
[
2
]
=
0x3f
;
/* Get all pages */
cmd
[
4
]
=
255
;
/* Ask for 255 bytes, even tho we want just the first 8 */
SRpnt
->
sr_cmd_len
=
0
;
...
...
@@ -1012,11 +1161,12 @@ static int sd_init_onedisk(int i)
the_result
=
SRpnt
->
sr_result
;
if
(
the_result
)
{
printk
(
"%s: test WP failed, assume Write Enabled
\n
"
,
nbuff
);
printk
(
KERN_NOTICE
"%s: test WP failed, assume "
"Write Enabled
\n
"
,
nbuff
);
}
else
{
rscsi_disks
[
i
].
write_prot
=
((
buffer
[
2
]
&
0x80
)
!=
0
);
printk
(
"%s: Write Protect is %s
\n
"
,
nbuff
,
rscsi_disks
[
i
].
write_prot
?
"on"
:
"off"
);
sdkp
->
write_prot
=
((
buffer
[
2
]
&
0x80
)
!=
0
);
printk
(
KERN_NOTICE
"%s: Write Protect is %s
\n
"
,
nbuff
,
sdkp
->
write_prot
?
"on"
:
"off"
);
}
}
/* check for write protect */
...
...
@@ -1028,7 +1178,7 @@ static int sd_init_onedisk(int i)
SRpnt
=
NULL
;
kfree
(
buffer
);
return
i
;
return
dsk_nr
;
}
/*
...
...
@@ -1038,14 +1188,25 @@ static int sd_init_onedisk(int i)
static
int
sd_registered
;
/**
* sd_init- called during driver initialization (after
* sd_detect() is called for each scsi device present).
*
* Returns 0 is successful (or already called); 1 if error
*
* Note: this function is invoked from the scsi mid-level.
**/
static
int
sd_init
()
{
int
i
,
maxparts
;
int
k
,
maxparts
;
Scsi_Disk
*
sdkp
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_init: dev_noticed=%d
\n
"
,
sd_template
.
dev_noticed
));
if
(
sd_template
.
dev_noticed
==
0
)
return
0
;
if
(
!
rscsi_disks
)
if
(
NULL
==
sd_dsk_arr
)
sd_template
.
dev_max
=
sd_template
.
dev_noticed
+
SD_EXTRA_DEVS
;
if
(
sd_template
.
dev_max
>
N_SD_MAJORS
*
SCSI_DISKS_PER_MAJOR
)
...
...
@@ -1057,71 +1218,80 @@ static int sd_init()
return
0
;
if
(
!
sd_registered
)
{
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
if
(
devfs_register_blkdev
(
SD_MAJOR
(
i
),
"sd"
,
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
if
(
devfs_register_blkdev
(
SD_MAJOR
(
k
),
"sd"
,
&
sd_fops
))
{
printk
(
"Unable to get major %d for SCSI disk
\n
"
,
SD_MAJOR
(
i
));
printk
(
KERN_NOTICE
"Unable to get major %d "
"for SCSI disk
\n
"
,
SD_MAJOR
(
k
));
return
1
;
}
}
sd_registered
++
;
}
/* We do not support attaching loadable devices yet. */
if
(
rscsi_disks
)
if
(
sd_dsk_arr
)
return
0
;
/* allocate memory */
#define init_mem_lth(x,n) x =
kmalloc((n) * sizeof(*x), GFP_ATOMIC
)
#define init_mem_lth(x,n) x =
vmalloc((n) * sizeof(*x)
)
#define zero_mem_lth(x,n) memset(x, 0, (n) * sizeof(*x))
init_mem_lth
(
rscsi_disks
,
sd_template
.
dev_max
);
init_mem_lth
(
sd_dsk_arr
,
sd_template
.
dev_max
);
if
(
sd_dsk_arr
)
{
zero_mem_lth
(
sd_dsk_arr
,
sd_template
.
dev_max
);
for
(
k
=
0
;
k
<
sd_template
.
dev_max
;
++
k
)
{
sdkp
=
vmalloc
(
sizeof
(
Scsi_Disk
));
if
(
NULL
==
sdkp
)
goto
cleanup_mem
;
memset
(
sdkp
,
0
,
sizeof
(
Scsi_Disk
));
sd_dsk_arr
[
k
]
=
sdkp
;
}
}
init_mem_lth
(
sd_sizes
,
maxparts
);
init_mem_lth
(
sd
,
maxparts
);
init_mem_lth
(
sd_gendisks
,
N_USED_SD_MAJORS
);
init_mem_lth
(
sd_max_sectors
,
sd_template
.
dev_max
<<
4
);
if
(
!
rscsi_disks
||
!
sd_sizes
||
!
sd
||
!
sd_gendisks
)
if
(
!
sd_dsk_arr
||
!
sd_sizes
||
!
sd
||
!
sd_gendisks
)
goto
cleanup_mem
;
zero_mem_lth
(
rscsi_disks
,
sd_template
.
dev_max
);
zero_mem_lth
(
sd_sizes
,
maxparts
);
zero_mem_lth
(
sd
,
maxparts
);
for
(
i
=
0
;
i
<
maxparts
;
i
++
)
{
for
(
k
=
0
;
k
<
maxparts
;
k
++
)
{
/*
* Allow lowlevel device drivers to generate 512k large scsi
* commands if they know what they're doing and they ask for it
* explicitly via the SHpnt->max_sectors API.
*/
sd_max_sectors
[
i
]
=
MAX_PHYS_SEGMENTS
*
8
;
sd_max_sectors
[
k
]
=
MAX_PHYS_SEGMENTS
*
8
;
}
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
request_queue_t
*
q
=
blk_get_queue
(
mk_kdev
(
SD_MAJOR
(
i
),
0
));
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
request_queue_t
*
q
=
blk_get_queue
(
mk_kdev
(
SD_MAJOR
(
k
),
0
));
blk_queue_hardsect_size
(
q
,
512
);
}
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
int
N
=
SCSI_DISKS_PER_MAJOR
;
sd_gendisks
[
i
]
=
sd_gendisk
;
sd_gendisks
[
k
]
=
sd_gendisk
;
init_mem_lth
(
sd_gendisks
[
i
].
de_arr
,
N
);
init_mem_lth
(
sd_gendisks
[
i
].
flags
,
N
);
init_mem_lth
(
sd_gendisks
[
k
].
de_arr
,
N
);
init_mem_lth
(
sd_gendisks
[
k
].
flags
,
N
);
if
(
!
sd_gendisks
[
i
].
de_arr
||
!
sd_gendisks
[
i
].
flags
)
if
(
!
sd_gendisks
[
k
].
de_arr
||
!
sd_gendisks
[
k
].
flags
)
goto
cleanup_gendisks
;
zero_mem_lth
(
sd_gendisks
[
i
].
de_arr
,
N
);
zero_mem_lth
(
sd_gendisks
[
i
].
flags
,
N
);
zero_mem_lth
(
sd_gendisks
[
k
].
de_arr
,
N
);
zero_mem_lth
(
sd_gendisks
[
k
].
flags
,
N
);
sd_gendisks
[
i
].
major
=
SD_MAJOR
(
i
);
sd_gendisks
[
i
].
major_name
=
"sd"
;
sd_gendisks
[
i
].
minor_shift
=
4
;
sd_gendisks
[
i
].
part
=
sd
+
i
*
(
N
<<
4
);
sd_gendisks
[
i
].
sizes
=
sd_sizes
+
i
*
(
N
<<
4
);
sd_gendisks
[
i
].
nr_real
=
0
;
sd_gendisks
[
k
].
major
=
SD_MAJOR
(
k
);
sd_gendisks
[
k
].
major_name
=
"sd"
;
sd_gendisks
[
k
].
minor_shift
=
4
;
sd_gendisks
[
k
].
part
=
sd
+
k
*
(
N
<<
4
);
sd_gendisks
[
k
].
sizes
=
sd_sizes
+
k
*
(
N
<<
4
);
sd_gendisks
[
k
].
nr_real
=
0
;
}
return
0
;
...
...
@@ -1130,129 +1300,197 @@ static int sd_init()
#undef zero_mem_lth
cleanup_gendisks:
/*
k
free can handle NULL, so no test is required here */
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
kfree
(
sd_gendisks
[
i
].
de_arr
);
kfree
(
sd_gendisks
[
i
].
flags
);
/*
v
free can handle NULL, so no test is required here */
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
vfree
(
sd_gendisks
[
k
].
de_arr
);
vfree
(
sd_gendisks
[
k
].
flags
);
}
cleanup_mem:
kfree
(
sd_gendisks
);
kfree
(
sd
);
kfree
(
sd_sizes
);
kfree
(
rscsi_disks
);
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
devfs_unregister_blkdev
(
SD_MAJOR
(
i
),
"sd"
);
if
(
sd_gendisks
)
vfree
(
sd_gendisks
);
sd_gendisks
=
NULL
;
if
(
sd
)
vfree
(
sd
);
sd
=
NULL
;
sd_blocksizes
=
NULL
;
if
(
sd_sizes
)
vfree
(
sd_sizes
);
sd_sizes
=
NULL
;
if
(
sd_dsk_arr
)
{
for
(
k
=
0
;
k
<
sd_template
.
dev_max
;
++
k
)
{
sdkp
=
sd_dsk_arr
[
k
];
if
(
sdkp
)
vfree
(
sdkp
);
}
vfree
(
sd_dsk_arr
);
sd_dsk_arr
=
NULL
;
}
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
devfs_unregister_blkdev
(
SD_MAJOR
(
k
),
"sd"
);
}
sd_registered
--
;
return
1
;
}
/**
* sd_finish- called during driver initialization, after all
* the sd_attach() calls are finished.
*
* Note: this function is invoked from the scsi mid-level.
* This function is not called after driver initialization has completed.
* Specifically later device attachments invoke sd_attach() but not
* this function.
**/
static
void
sd_finish
()
{
int
i
;
int
k
;
Scsi_Disk
*
sdkp
;
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
blk_dev
[
SD_MAJOR
(
i
)].
queue
=
sd_find_queue
;
add_gendisk
(
&
(
sd_gendisks
[
i
]));
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_finish:
\n
"
));
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
blk_dev
[
SD_MAJOR
(
k
)].
queue
=
sd_find_queue
;
add_gendisk
(
&
(
sd_gendisks
[
k
]));
}
for
(
i
=
0
;
i
<
sd_template
.
dev_max
;
++
i
)
if
(
!
rscsi_disks
[
i
].
capacity
&&
rscsi_disks
[
i
].
device
)
{
sd_init_onedisk
(
i
);
if
(
!
rscsi_disks
[
i
].
has_part_table
)
{
sd_sizes
[
i
<<
4
]
=
rscsi_disks
[
i
].
capacity
;
register_disk
(
&
SD_GENDISK
(
i
),
MKDEV_SD
(
i
),
for
(
k
=
0
;
k
<
sd_template
.
dev_max
;
++
k
)
{
sdkp
=
sd_get_sdisk
(
k
);
if
(
sdkp
&&
(
0
==
sdkp
->
capacity
)
&&
sdkp
->
device
)
{
sd_init_onedisk
(
sdkp
,
k
);
if
(
!
sdkp
->
has_part_table
)
{
sd_sizes
[
k
<<
4
]
=
sdkp
->
capacity
;
register_disk
(
&
SD_GENDISK
(
k
),
MKDEV_SD
(
k
),
1
<<
4
,
&
sd_fops
,
rscsi_disks
[
i
].
capacity
);
rscsi_disks
[
i
].
has_part_table
=
1
;
sdkp
->
capacity
);
sdkp
->
has_part_table
=
1
;
}
}
}
return
;
}
static
int
sd_detect
(
Scsi_Device
*
SDp
)
/**
* sd_detect- called at the start of driver initialization, once
* for each scsi device (not just disks) present.
*
* Returns 0 if not interested in this scsi device (e.g. scanner);
* 1 if this device is of interest (e.g. a disk).
*
* Note: this function is invoked from the scsi mid-level.
* This function is called before sd_init() so very little is available.
**/
static
int
sd_detect
(
Scsi_Device
*
sdp
)
{
if
(
SDp
->
type
!=
TYPE_DISK
&&
SDp
->
type
!=
TYPE_MOD
)
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_detect: type=%d
\n
"
,
sdp
->
type
));
if
(
sdp
->
type
!=
TYPE_DISK
&&
sdp
->
type
!=
TYPE_MOD
)
return
0
;
sd_template
.
dev_noticed
++
;
return
1
;
}
static
int
sd_attach
(
Scsi_Device
*
SDp
)
/**
* sd_attach- called during driver initialization and whenever a
* new scsi device is attached to the system. It is called once
* for each scsi device (not just disks) present.
* @sdp: pointer to mid level scsi device object
*
* Returns 0 if successful (or not interested in this scsi device
* (e.g. scanner)); 1 when there is an error.
*
* Note: this function is invoked from the scsi mid-level.
* This function sets up the mapping between a given
* <host,channel,id,lun> (found in sdp) and new device name
* (e.g. /dev/sda). More precisely it is the block device major
* and minor number that is chosen here.
**/
static
int
sd_attach
(
Scsi_Device
*
sdp
)
{
unsigned
int
devnum
;
Scsi_Disk
*
dpnt
;
int
i
;
Scsi_Disk
*
sdkp
;
int
dsk_nr
;
char
nbuff
[
6
];
unsigned
long
iflags
;
if
(
SDp
->
type
!=
TYPE_DISK
&&
SDp
->
type
!=
TYPE_MOD
)
if
((
NULL
==
sdp
)
||
((
sdp
->
type
!=
TYPE_DISK
)
&&
(
sdp
->
type
!=
TYPE_MOD
)))
return
0
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_attach: scsi device: <%d,%d,%d,%d>
\n
"
,
sdp
->
host
->
host_no
,
sdp
->
channel
,
sdp
->
id
,
sdp
->
lun
));
if
(
sd_template
.
nr_dev
>=
sd_template
.
dev_max
)
{
SDp
->
attached
--
;
sdp
->
attached
--
;
printk
(
KERN_ERR
"sd_init: no more room for device
\n
"
);
return
1
;
}
for
(
dpnt
=
rscsi_disks
,
i
=
0
;
i
<
sd_template
.
dev_max
;
i
++
,
dpnt
++
)
if
(
!
dpnt
->
device
)
/* Assume sd_attach is not re-entrant (for time being) */
/* Also think about sd_attach() and sd_detach() running coincidentally. */
write_lock_irqsave
(
&
sd_dsk_arr_lock
,
iflags
);
for
(
dsk_nr
=
0
;
dsk_nr
<
sd_template
.
dev_max
;
dsk_nr
++
)
{
sdkp
=
sd_dsk_arr
[
dsk_nr
];
if
(
!
sdkp
->
device
)
{
sdkp
->
device
=
sdp
;
sdkp
->
has_part_table
=
0
;
break
;
}
}
write_unlock_irqrestore
(
&
sd_dsk_arr_lock
,
iflags
);
if
(
i
>=
sd_template
.
dev_max
)
panic
(
"scsi_devices corrupt (sd)"
);
if
(
dsk_nr
>=
sd_template
.
dev_max
)
{
/* panic("scsi_devices corrupt (sd)"); overkill */
printk
(
KERN_ERR
"sd_init: sd_dsk_arr corrupted
\n
"
);
return
1
;
}
rscsi_disks
[
i
].
device
=
SDp
;
rscsi_disks
[
i
].
has_part_table
=
0
;
sd_template
.
nr_dev
++
;
SD_GENDISK
(
i
).
nr_real
++
;
devnum
=
i
%
SCSI_DISKS_PER_MAJOR
;
SD_GENDISK
(
i
).
de_arr
[
devnum
]
=
SD
p
->
de
;
if
(
SD
p
->
removable
)
SD_GENDISK
(
i
).
flags
[
devnum
]
|=
GENHD_FL_REMOVABLE
;
sd_d
evname
(
i
,
nbuff
);
printk
(
"Attached scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d
\n
"
,
SD
p
->
removable
?
"removable "
:
""
,
nbuff
,
SDp
->
host
->
host_no
,
SDp
->
channel
,
SDp
->
id
,
SD
p
->
lun
);
SD_GENDISK
(
dsk_nr
).
nr_real
++
;
devnum
=
dsk_nr
%
SCSI_DISKS_PER_MAJOR
;
SD_GENDISK
(
dsk_nr
).
de_arr
[
devnum
]
=
sd
p
->
de
;
if
(
sd
p
->
removable
)
SD_GENDISK
(
dsk_nr
).
flags
[
devnum
]
|=
GENHD_FL_REMOVABLE
;
sd_d
skname
(
dsk_nr
,
nbuff
);
printk
(
KERN_NOTICE
"Attached scsi %sdisk %s at scsi%d, channel %d, "
"id %d, lun %d
\n
"
,
sd
p
->
removable
?
"removable "
:
""
,
nbuff
,
sdp
->
host
->
host_no
,
sdp
->
channel
,
sdp
->
id
,
sd
p
->
lun
);
return
0
;
}
#define DEVICE_BUSY rscsi_disks[target].device->busy
#define ALLOW_REVALIDATE rscsi_disks[target].device->allow_revalidate
#define USAGE rscsi_disks[target].device->access_count
#define CAPACITY rscsi_disks[target].capacity
#define MAYBE_REINIT sd_init_onedisk(target)
/* This routine is called to flush all partitions and partition tables
* for a changed scsi disk, and then re-read the new partition table.
* If we are revalidating a disk because of a media change, then we
* enter with usage == 0. If we are using an ioctl, we automatically have
* usage == 1 (we need an open channel to use an ioctl :-), so this
* is our limit.
/**
* revalidate_scsidisk- called to flush all partitions and partition
* tables for a changed scsi disk. sd_init_onedisk() is then called
* followed by re-reading the new partition table.
* @dev: kernel device descriptor (kdev_t)
* @maxusage: 0 when called from block level, 1 when called from
* sd_ioctl().
*
* Returns 0 if successful; negated errno value otherwise.
*/
int
revalidate_scsidisk
(
kdev_t
dev
,
int
maxusage
)
{
int
target
;
int
dsk_nr
=
DEVICE_NR
(
dev
)
;
int
res
;
Scsi_Disk
*
sdkp
;
Scsi_Device
*
sdp
;
target
=
DEVICE_NR
(
dev
);
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"revalidate_scsidisk: dsk_nr=%d
\n
"
,
DEVICE_NR
(
dev
)));
sdkp
=
sd_get_sdisk
(
dsk_nr
);
if
((
NULL
==
sdkp
)
||
(
NULL
==
(
sdp
=
sdkp
->
device
)))
return
-
ENODEV
;
if
(
DEVICE_BUSY
||
(
ALLOW_REVALIDATE
==
0
&&
USAGE
>
maxusage
))
{
printk
(
"Device busy for revalidation (usage=%d)
\n
"
,
USAGE
);
if
(
sdp
->
busy
||
((
sdp
->
allow_revalidate
==
0
)
&&
(
sdp
->
access_count
>
maxusage
)))
{
printk
(
KERN_WARNING
"Device busy for revalidation "
"(access_count=%d)
\n
"
,
sdp
->
access_count
);
return
-
EBUSY
;
}
DEVICE_BUSY
=
1
;
sdp
->
busy
=
1
;
res
=
wipe_partitions
(
dev
);
if
(
res
)
goto
leave
;
#ifdef MAYBE_REINIT
MAYBE_REINIT
;
#endif
sd_init_onedisk
(
sdkp
,
dsk_nr
);
grok_partitions
(
dev
,
CAPACITY
);
grok_partitions
(
dev
,
sdkp
->
capacity
);
leave:
DEVICE_BUSY
=
0
;
sdp
->
busy
=
0
;
return
res
;
}
...
...
@@ -1260,68 +1498,125 @@ static int fop_revalidate_scsidisk(kdev_t dev)
{
return
revalidate_scsidisk
(
dev
,
0
);
}
static
void
sd_detach
(
Scsi_Device
*
SDp
)
/**
* sd_detach- called whenever a scsi disk (previously recognized by
* sd_attach) is detached from the system. It is called (potentially
* multiple times) during sd module unload.
* @sdp: pointer to mid level scsi device object
*
* Note: this function is invoked from the scsi mid-level.
* This function potentially frees up a device name (e.g. /dev/sdc)
* that could be re-used by a subsequent sd_attach().
* This function is not called when the built-in sd driver is "exit-ed".
**/
static
void
sd_detach
(
Scsi_Device
*
sdp
)
{
Scsi_Disk
*
dpnt
;
Scsi_Disk
*
sdkp
=
NULL
;
kdev_t
dev
;
int
i
,
j
;
int
dsk_nr
,
j
;
int
max_p
;
int
start
;
for
(
dpnt
=
rscsi_disks
,
i
=
0
;
i
<
sd_template
.
dev_max
;
i
++
,
dpnt
++
)
if
(
dpnt
->
device
==
SDp
)
{
max_p
=
1
<<
sd_gendisk
.
minor_shift
;
start
=
i
<<
sd_gendisk
.
minor_shift
;
dev
=
MKDEV_SD_PARTITION
(
start
);
wipe_partitions
(
dev
);
for
(
j
=
max_p
-
1
;
j
>=
0
;
j
--
)
sd_sizes
[
start
+
j
]
=
0
;
devfs_register_partitions
(
&
SD_GENDISK
(
i
),
SD_MINOR_NUMBER
(
start
),
1
);
/* unregister_disk() */
dpnt
->
has_part_table
=
0
;
dpnt
->
device
=
NULL
;
dpnt
->
capacity
=
0
;
SDp
->
attached
--
;
sd_template
.
dev_noticed
--
;
sd_template
.
nr_dev
--
;
SD_GENDISK
(
i
).
nr_real
--
;
return
;
unsigned
long
iflags
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"sd_detach: <%d,%d,%d,%d>
\n
"
,
sdp
->
host
->
host_no
,
sdp
->
channel
,
sdp
->
id
,
sdp
->
lun
));
write_lock_irqsave
(
&
sd_dsk_arr_lock
,
iflags
);
for
(
dsk_nr
=
0
;
dsk_nr
<
sd_template
.
dev_max
;
dsk_nr
++
)
{
sdkp
=
sd_dsk_arr
[
dsk_nr
];
if
(
sdkp
->
device
==
sdp
)
{
sdkp
->
has_part_table
=
0
;
sdkp
->
device
=
NULL
;
sdkp
->
capacity
=
0
;
/* sdkp->detaching = 1; */
break
;
}
}
write_unlock_irqrestore
(
&
sd_dsk_arr_lock
,
iflags
);
if
(
dsk_nr
>=
sd_template
.
dev_max
)
return
;
max_p
=
1
<<
sd_gendisk
.
minor_shift
;
start
=
dsk_nr
<<
sd_gendisk
.
minor_shift
;
dev
=
MKDEV_SD_PARTITION
(
start
);
wipe_partitions
(
dev
);
for
(
j
=
max_p
-
1
;
j
>=
0
;
j
--
)
sd_sizes
[
start
+
j
]
=
0
;
devfs_register_partitions
(
&
SD_GENDISK
(
dsk_nr
),
SD_MINOR_NUMBER
(
start
),
1
);
/* unregister_disk() */
sdp
->
attached
--
;
sd_template
.
dev_noticed
--
;
sd_template
.
nr_dev
--
;
SD_GENDISK
(
dsk_nr
).
nr_real
--
;
}
/**
* init_sd- entry point for this driver (both when built in or when
* a module).
*
* Note: this function registers this driver with the scsi mid-level.
**/
static
int
__init
init_sd
(
void
)
{
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"init_sd: sd driver entry point
\n
"
));
sd_template
.
module
=
THIS_MODULE
;
return
scsi_register_device
(
&
sd_template
);
}
/**
* exit_sd- exit point for this driver (when it is a module).
*
* Note: this function unregisters this driver from the scsi mid-level.
**/
static
void
__exit
exit_sd
(
void
)
{
int
i
;
int
k
;
Scsi_Disk
*
sdkp
;
SCSI_LOG_HLQUEUE
(
3
,
printk
(
"exit_sd: exiting sd driver
\n
"
));
scsi_unregister_device
(
&
sd_template
);
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
devfs_unregister_blkdev
(
SD_MAJOR
(
i
),
"sd"
);
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
devfs_unregister_blkdev
(
SD_MAJOR
(
k
),
"sd"
);
sd_registered
--
;
if
(
rscsi_disks
!=
NULL
)
{
kfree
(
rscsi_disks
);
kfree
(
sd_sizes
);
kfree
((
char
*
)
sd
);
if
(
sd_dsk_arr
!=
NULL
)
{
for
(
k
=
0
;
k
<
sd_template
.
dev_max
;
++
k
)
{
sdkp
=
sd_dsk_arr
[
k
];
if
(
sdkp
)
vfree
(
sdkp
);
}
vfree
(
sd_dsk_arr
);
}
for
(
i
=
0
;
i
<
N_USED_SD_MAJORS
;
i
++
)
{
del_gendisk
(
&
(
sd_gendisks
[
i
]));
blk_clear
(
SD_MAJOR
(
i
));
if
(
sd_sizes
)
vfree
(
sd_sizes
);
if
(
sd
)
vfree
((
char
*
)
sd
);
for
(
k
=
0
;
k
<
N_USED_SD_MAJORS
;
k
++
)
{
blk_dev
[
SD_MAJOR
(
k
)].
queue
=
NULL
;
del_gendisk
(
&
(
sd_gendisks
[
k
]));
blk_clear
(
SD_MAJOR
(
k
));
}
sd_template
.
dev_max
=
0
;
if
(
sd_gendisks
!=
&
sd_gendisk
)
k
free
(
sd_gendisks
);
v
free
(
sd_gendisks
);
}
static
Scsi_Disk
*
sd_get_sdisk
(
int
index
)
{
Scsi_Disk
*
sdkp
=
NULL
;
unsigned
long
iflags
;
read_lock_irqsave
(
&
sd_dsk_arr_lock
,
iflags
);
if
(
sd_dsk_arr
&&
(
index
>=
0
)
&&
(
index
<
sd_template
.
dev_max
))
sdkp
=
sd_dsk_arr
[
index
];
read_unlock_irqrestore
(
&
sd_dsk_arr_lock
,
iflags
);
return
sdkp
;
}
MODULE_LICENSE
(
"GPL"
);
MODULE_AUTHOR
(
"Eric Youngdale"
);
MODULE_DESCRIPTION
(
"SCSI disk (sd) driver"
);
module_init
(
init_sd
);
module_exit
(
exit_sd
);
MODULE_LICENSE
(
"GPL"
);
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