Commit 5cf40909 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.1.81

parent 0057ae60
......@@ -7,6 +7,10 @@
Linus
----------
M: Matti Aarnio
E: mea@utu.fi
D: Dynamicized network socket allocations, LILO for AHA1542
N: Werner Almesberger
E: almesber@bernina.ethz.ch
D: dosfs, LILO, some fd features, various other hacks here and there
......
VERSION = 1
PATCHLEVEL = 1
SUBLEVEL = 80
SUBLEVEL = 81
ARCH = i386
......
......@@ -73,6 +73,7 @@ bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
......@@ -86,7 +87,7 @@ bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE
bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 n
bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
#bool 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA n
#bool 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG n
fi
......
......@@ -81,13 +81,13 @@ interface (/dev/hda) and an IDE cdrom drive on the secondary interface
ln -sf /dev/hdc /dev/cdrom
mkdir /cd
mount /dev/cdrom /cd -t iso9660 -o ro,block=2048
mount /dev/cdrom /cd -t iso9660 -o ro
Please pass on any feedback on the cdrom stuff to the author & maintainer,
Scott Snyder (snyder@fnald0.fnal.gov).
Note that present, the kernel is unable to execute demand-paged binaries
directly off of the cdrom (due to the different block size).
The kernel is now be able to execute binaries directly off of the cdrom,
provided it is mounted with the default block size of 1024.
The hdparm.c program for controlling various IDE features is now packaged
separately. Look for it on popular linux FTP sites.
......
This README belongs to release 3.0 or newer of the SoundBlaster Pro
This README belongs to release 3.1 or newer of the SoundBlaster Pro
(Matsushita, Kotobuki, Panasonic, CreativeLabs, Longshine and soon TEAC, too)
CD-ROM driver for Linux.
......@@ -28,11 +28,11 @@ Regarding CD200 and CD-55A support:
(if you are: mail!; I do not have such drives).
Please, don't drop simple questions about the new drives in the
newsgroups. Full support needs more or less time.
If you are able to set the appropriate DBG-xxx switches, you can mail me
the "SBPCD:..." messages, regarding the new drives. But I mostly will
not answer (just use) it.
If you like to help, you can mail me the "SBPCD:..." messages, regarding the
new drives. But I mostly will not answer (just use) it.
This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives.
This driver is NOT for Mitsumi or Sony or Aztech or Philips or XXX drives,
and this driver is in no way useable for any new IDE ATAPI drive.
For Aztech CDA-268 drives (and for some Wearnes, Okano and Orchid drives),
Werner Zimmermann has done a driver which currently resides at ftp.gwdg.de
under /pub/linux/cdrom/drivers/aztech/.
......@@ -50,15 +50,15 @@ work.
The interface type has to get configured in /usr/include/linux/sbpcd.h,
because the behavior of some sound card interfaces is different.
The driver respects different drive firmware releases - my old drive is a 2.11,
The driver respects all known drive firmware releases - my old drive is a 2.11,
but it should work with "old" drives <2.01 ... >3.00 and with "new" drives
(which count the releases around 0.75 or 1.00).
Up to 4 drives per interface card, and up to 4 interface cards are supported.
CR-52x ("old"), CR-56x ("new") and LCS drives can be mixed, but the CR-521
ones are hard-wired to drive ID 0. The drives have to use different drive IDs,
and each drive has to get a unique minor number (0...3), corresponding to it's
drive ID.
All supported drive families can be mixed, but the CR-521 drives are
hard-wired to drive ID 0. The drives have to use different drive IDs, and each
drive has to get a unique minor number (0...3), corresponding indirectly to
it's drive ID.
The drive IDs may be selected freely from 0 to 3 - they do not have to be in
consecutive order.
......@@ -79,24 +79,22 @@ to change old drives to any ID, too. He writes in this sense:
did not work with other values. If the values are not good,
ID 3 behaves like ID 0."
To use more than 4 drives (now that the single-speed CR-521's are as cheap as
50$), you need a second interface card and you have to "duplicate" the driver.
Just copy sbpcd.c into sbpcd2.c and so forth and change SBPCD_ISSUE (at top
of sbpcd2.c) accordingly.
To use more than 4 drives, you simply need a second controller card at a
different address and a second cable.
The driver supports reading of data from the CD and playing of audio tracks.
The audio part should run with WorkMan, xcdplayer, with the "non-X11" products
CDplayer and WorkBone - tell me if it is not compatible with other software.
With the "new" drive family CR-562 and CR-563, the reading of audio frames is
possible. This is currently implemented by an IOCTL function which reads only
up to 4 frames of 2352 bytes at once. Reading more than 1 frame at once misses
some chunks at each frame boundary. Reading the same frame a second time gives
different data; the frame data start at a different position. But all read
bytes are valid, and we always read 98 consecutive chunks (of 24 Bytes) as a
frame. This lack has to get corrected by higher level software which reads the
same frame again and tries to find and eliminate overlapping chunks
(24-byte-pieces).
With the CR-562 and CR-563 drives, the reading of audio frames is possible.
This is implemented by an IOCTL function which per default reads only up to
4 frames of 2352 bytes at once (configurable with the "READ_AUDIO" define).
Reading the same frame a second time gives different data; the frame data
start at a different position, but all read bytes are valid, and we always
read 98 consecutive chunks (of 24 Bytes) as a frame. Reading more than 1 frame
at once misses some chunks at each frame boundary.This lack has to get
corrected by external, "higher level" software which reads the same frame
again and tries to find and eliminate overlapping chunks (24-byte-pieces).
The transfer rate with reading audio (1-frame-pieces) is as slow as 32 kB/sec.
This could be better reading bigger chunks, but the "missing" chunks occur at
......@@ -104,12 +102,11 @@ the beginning of each single frame.
The software interface possibly may change a bit the day the SCSI driver
supports it too.
With the CR-562 and CR-563 drives, MultiSession is supported, "ManySession"
(not recommended, see below) alternatively.
Photo CDs work, too (the "old" drives like CR-521 can access only the first
With the CR-562 and CR-563 drives, MultiSession is supported.
Photo CDs work (the "old" drives like CR-521 can access only the first
session of a photoCD).
At ftp.gwdg.de:/pub/linux/hpcdtoppm/ is Hadmut Danisch's package to convert
photo CD image files.
At ftp.gwdg.de:/pub/linux/hpcdtoppm/ you will find Hadmut Danisch's package to
convert photo CD image files and Gerd Knorr's viewing utility.
The transfer rate will reach 150 kB/sec with "old" drives and 300 kB/sec with
double-speed drives. XA (PhotoCD) disks with "old" drives give only 50 kB/sec.
......@@ -133,6 +130,7 @@ To install:
Most "compatible" sound cards (for example "Highscreen", "SoundFX"
and "Galaxy") need "SBPRO 0".
The "no-sound" board from OmniCd needs the "SBPRO 1" setup.
All other "no-sound" boards need the "SBPRO 0" setup.
The Spea Media FX sound card needs "SBPRO 2".
sbpcd.c holds some examples in it's auto-probe list.
If you configure "SBPRO" wrong, the playing of audio CDs will work,
......@@ -149,27 +147,30 @@ To install:
This is especially useful if you install a fresh distribution.
2. "cd /usr/src/linux" and do a "make config" and select "y" for Matsushita
CD-ROM support and for ISO9660 FileSystem support. If you do not have a
second, third, or fourth controller and/or did not prepare sbpcd2 etc.,
do not say "y" to the secondary Matsushita CD-ROM questions.
second, third, or fourth controller installed, do not say "y" to the
secondary Matsushita CD-ROM questions.
SCSI and/or SCSI CD-ROM support is not needed.
3. Then do a "make dep", then make the kernel image ("make zlilo" or else).
4. Make the device file(s). The driver uses definitely and exclusive the
MAJOR 25, so do
mknod /dev/sbpcd b 25 0 (if you have only drive #0)
mknod /dev/sbpcd b 25 0 (if you have only one drive)
and/or
mknod /dev/sbpcd0 b 25 0
mknod /dev/sbpcd1 b 25 1
mknod /dev/sbpcd2 b 25 2
mknod /dev/sbpcd3 b 25 3
to make the node(s).
Take care that you create a node with the same MINOR as your drive ID is.
So, if the DOS driver tells you have drive id #3, you have to
mknod /dev/<any_name> b 25 3
The driver no longer uses the "AT bus style" device numbering; the SCSI
scheme is used now; that means, the "first found" drive gets MINOR 0
(regardless to it's jumpered ID), the "next found" (at the same cable)
gets MINOR 1, ...
For a second interface board, you have to make nodes like
mknod /dev/sbpcd4 b 26 0
mknod /dev/sbpcd5 b 26 1
and so on. Use the MAJORs 26, 27, 28.
If you further make a link like
......@@ -198,19 +199,9 @@ I/O port 0x0230 first. If this is not appropriate, sbpcd.h should get changed
No DMA and no IRQ is used, so the IRQ line stays free for the SB Pro sound
drivers.
To reduce or increase the amount of kernel messages, edit sbpcd.c and change
the initialization of the variable "sbpcd_debug". This is the way to get rid
of the initial warning message block, too.
With "#define MANY_SESSION 1" (sbpcd.c), the driver can use "many-session" CDs.
This will work only with "new" drives like CR-562 or CR-563. That is NOT
multisession - it is a CD with multiple independent sessions, each containing
block addresses as if it were the only session. With this feature enabled, the
driver will read the LAST session. Without it, the FIRST session gets read.
If you would like the support of reading "in-between" sessions, drop me a mail
and some food for the soul. :-)
Those "many-session" CDs can get made by CDROM writers like Philips CDD 521.
If you enable this feature, it is impossible to read true multisession CDs.
To reduce or increase the amount of kernel messages, edit sbpcd.c and play
with the "DBG_xxx" switches (initialization of the variable "sbpcd_debug").
This is the way to get rid of the initial warning message block, too.
The driver uses the "variable BLOCK_SIZE" feature. To use it, you have to
specify "block=2048" as a mount option. Doing this will disable the direct
......@@ -272,6 +263,8 @@ main(int argc, char *argv[])
}
/*===================== end program ========================================*/
Jeff Tranter's "eject" utility can do this, too (and more) for you.
There is a new ioctl CDROMMULTISESSION to obtain with a user program if
the CD is an XA disk and - if it is - where the last session starts. The
following example illustrates how to call it:
......@@ -341,12 +334,15 @@ main(int argc, char *argv[])
Auto-probing at boot time:
--------------------------
The driver does auto-probing at many well-known interface card addresses. The
idea to do that came from Adam J. Richter (YGGDRASIL). Some well-known
addresses are excluded from auto-probing because they can cause a hang if an
ethernet card gets touched.
The driver does auto-probing at many well-known interface card addresses,
but not all:
Some probings can cause a hang if an NE2000 ethernet card gets touched, because
SBPCD's auto-probing happens before the initialization of the net drivers.
Those "hazardous" addresses are excluded from auto-probing; the "kernel
command line" feature has to be used during installation if you have your
drive at those addresses.
This auto-probing looks first at the configured address resp. the address
The auto-probing looks first at the configured address resp. the address
submitted by the kernel command line. With this, it is possible to use this
driver within installation boot floppies, and for any non-standard address,
too.
......@@ -357,9 +353,6 @@ o.k., but you will get I/O errors during mount). In that case, use the "kernel
command line" feature and specify address & type at boot time to find out the
right setup.
SBPCD's auto-probing happens before the initialization of the net drivers. That
makes a hang possible if an ethernet card gets touched.
For every-day use, address and type should get configured within sbpcd.h. That
will stop the auto-probing due to success with the first try.
......@@ -367,10 +360,9 @@ will stop the auto-probing due to success with the first try.
Setting up address and interface type:
--------------------------------------
If your I/O port address is not 0x0230 or if you use a "no-sound" interface
other than OmniCD, you have to look for the #defines near the beginning of
sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and change CDROM_PORT to
the address of your CDROM I/O port.
If your I/O port address is not 0x340, you have to look for the #defines near
the beginning of sbpcd.h and configure them: set SBPRO to 0 or 1 or 2, and
change CDROM_PORT to the address of your CDROM I/O port.
Most of the "SoundBlaster compatible" cards behave like the no-sound
interfaces!
......@@ -384,19 +376,19 @@ you can set SOUND_BASE (in sbpcd.h) to get it done with your card, too...
Using audio CDs:
----------------
Workman, WorkBone, xcdplayer and cdplayer should work good now, even with the
double-speed drives.
Workman, WorkBone, xcdplayer, cdplayer and the nice little tool "cdplay" (see
README.aztcd from the Aztech driver package) should work.
The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer wants
"/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate links for using
them without the need of supplying parameters.
"/dev/rsr0", workman loves "/dev/sr0" or "/dev/cdrom" - so, do the appropriate
links for using them without the need of supplying parameters.
Copying audio tracks:
---------------------
The following little program will copy track 2 of an audio CD into the file
"track02":
The following program will copy track 1 (or a piece of it) from an audio CD
into the file "track01":
/*=================== begin program ========================================*/
/*
......@@ -419,13 +411,14 @@ The following little program will copy track 2 of an audio CD into the file
* This is only an example of the low-level access routine. The read data are
* pure 16-bit CDDA values; they have to get converted to make sound out of
* them.
* It is no fun to listen to it without prior overlap/underlap correction!
*/
#include <stdio.h>
#include <sys/ioctl.h>
#include <linux/cdrom.h>
static struct cdrom_tochdr hdr;
static struct cdrom_tocentry entry[100];
static struct cdrom_tocentry entry[101];
static struct cdrom_read_audio arg;
static u_char buffer[CD_FRAMESIZE_RAW];
static int datafile, drive;
......@@ -484,10 +477,9 @@ main(int argc, char *argv[])
/*
* ask for track number (not implemented here)
*/
track=2;
#if 0 /* just read a little piece */
entry[track].cdte_addr.lba=170;
entry[track+1].cdte_addr.lba=190;
track=1;
#if 0 /* just read a little piece (4 seconds) */
entry[track+1].cdte_addr.lba=entry[track].cdte_addr.lba+300;
#endif
/*
* read track into file
......@@ -504,20 +496,19 @@ entry[track+1].cdte_addr.lba=190;
arg.nframes=1;
arg.buf=&buffer[0];
limit=entry[track+1].cdte_addr.lba;
for (i=arg.addr.lba;i<limit;i++)
for (;arg.addr.lba<limit;arg.addr.lba++)
{
err=ioctl(drive, CDROMREADAUDIO, &arg);
if (err!=0)
{
fprintf(stderr, "can't read frame #%d (error %d).\n",
i-entry[track].cdte_addr.lba+1, err);
exit (-1);
fprintf(stderr, "can't read abs. frame #%d (error %d).\n",
arg.addr.lba, err);
}
j=write(datafile, &buffer[0], CD_FRAMESIZE_RAW);
if (j!=CD_FRAMESIZE_RAW)
{
fprintf(stderr,"I/O error (datafile) at frame %d\n",
i-entry[track].cdte_addr.lba+1);
fprintf(stderr,"I/O error (datafile) at rel. frame %d\n",
arg.addr.lba-entry[track].cdte_addr.lba);
}
arg.addr.lba++;
}
......
/*
* linux/drivers/block/ide-cd.c (ALPHA)
* linux/drivers/block/ide-cd.c (BETA)
*
* 1.00 Oct 31, 1994 -- Initial version.
* 1.01 Nov 2, 1994 -- Fixed problem with starting request in
......@@ -17,15 +17,22 @@
* Try to use LBA instead of track or MSF addressing
* when possible.
* Don't wait for READY_STAT.
* 2.03 Jan 10, 1995 -- Rewrite block read routines to handle block sizes
* other than 2k and to move multiple sectors in a
* single transaction.
*
* ATAPI cd-rom driver. To be used with ide.c.
*
* Copyright (C) 1994 scott snyder <snyder@fnald0.fnal.gov>
* Copyright (C) 1994, 1995 scott snyder <snyder@fnald0.fnal.gov>
*/
#include <linux/cdrom.h>
#define BLOCKS_PER_FRAME (CD_FRAMESIZE / 512)
#define SECTOR_SIZE 512
#define SECTOR_BITS 9
#define SECTORS_PER_FRAME (CD_FRAMESIZE / SECTOR_SIZE)
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define OUT_WORDS(b,n) outsw (IDE_PORT (HD_DATA, dev->hwif), (b), (n))
#define IN_WORDS(b,n) insw (IDE_PORT (HD_DATA, dev->hwif), (b), (n))
......@@ -107,11 +114,34 @@ struct atapi_toc_entry {
struct atapi_toc {
struct atapi_toc_header hdr;
struct atapi_toc_entry ent[MAX_TRACKS+1];
struct atapi_toc_entry ent[MAX_TRACKS+1]; /* One extra for the leadout. */
};
#define SECTOR_BUFFER_SIZE CD_FRAMESIZE
/* Extra per-device info for cdrom drives. */
struct cdrom_info {
/* Buffer for table of contents. NULL if we haven't allocated
a TOC buffer for this device yet. */
struct atapi_toc *toc;
/* Sector buffer. If a read request wants only the first part of a cdrom
block, we cache the rest of the block here, in the expectation that that
data is going to be wanted soon. SECTOR_BUFFERED is the number of the
first buffered sector, and NSECTORS_BUFFERED is the number of sectors
in the buffer. Before the buffer is allocated, we should have
SECTOR_BUFFER == NULL and NSECTORS_BUFFERED == 0. */
unsigned long sector_buffered;
unsigned long nsectors_buffered;
char *sector_buffer;
};
static struct atapi_toc *cdrom_toc[2][MAX_DRIVES];
static struct cdrom_info cdrom_info[2][MAX_DRIVES];
......@@ -119,6 +149,34 @@ static struct atapi_toc *cdrom_toc[2][MAX_DRIVES];
* Generic packet command support routines.
*/
static void cdrom_end_request (int uptodate, ide_dev_t *dev)
{
struct request *rq = ide_cur_rq[dev->hwif];
/* The code in blk.h can screw us up on error recovery if the block
size is larger than 1k. Fix that up here. */
if (!uptodate && rq->bh != 0)
{
int adj = rq->current_nr_sectors - 1;
rq->current_nr_sectors -= adj;
rq->sector += adj;
}
end_request (uptodate, dev->hwif);
}
/* Mark that we've seen a media change, and invalidate our internal
buffers. */
static void cdrom_saw_media_change (ide_dev_t *dev)
{
CDROM_FLAGS (dev)->media_changed = 1;
CDROM_FLAGS (dev)->toc_valid = 0;
cdrom_info[dev->hwif][dev->select.b.drive].nsectors_buffered = 0;
}
/* Returns 0 if the request should be continued.
Returns 1 if the request was ended. */
static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
......@@ -140,14 +198,13 @@ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
if ((err & 0xf0) == 0x20)
{
struct packet_command *pc;
CDROM_FLAGS (dev)->media_changed = 1;
CDROM_FLAGS (dev)->toc_valid = 0;
cdrom_saw_media_change (dev);
/* Fail the request if this is a read command. */
if (rq->cmd == READ)
{
printk ("%s : tray open\n", dev->name);
end_request (0, dev->hwif);
cdrom_end_request (0, dev);
}
else
......@@ -164,22 +221,21 @@ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
/* Set the error flag and complete the request. */
pc->stat = 1;
end_request (1, dev->hwif);
cdrom_end_request (1, dev);
}
}
/* Check for media change. */
else if ((err & 0xf0) == 0x60)
{
CDROM_FLAGS (dev)->media_changed = 1;
CDROM_FLAGS (dev)->toc_valid = 0;
cdrom_saw_media_change (dev);
printk ("%s: media changed\n", dev->name);
/* We're going to retry this command.
But be sure to give up if we've retried too many times. */
if ((++rq->errors > ERROR_MAX))
{
end_request (0, dev->hwif);
cdrom_end_request (0, dev);
}
}
......@@ -189,19 +245,19 @@ static int cdrom_decode_status (ide_dev_t *dev, int good_stat, int *stat_ret)
struct packet_command *pc = (struct packet_command *)rq->buffer;
dump_status (dev->hwif, "packet command error", stat);
pc->stat = 1; /* signal error */
end_request (1, dev->hwif);
cdrom_end_request (1, dev);
}
/* If there were other errors, go to the default handler. */
else if ((err & ~ABRT_ERR) != 0)
{
ide_error (dev, "cdrom_read_intr", stat);
ide_error (dev, "cdrom_decode_status", stat);
}
/* Else, abort if we've racked up too many retries. */
else if ((++rq->errors > ERROR_MAX))
{
end_request (0, dev->hwif);
cdrom_end_request (0, dev);
}
/* Retry, or handle the next request. */
......@@ -266,36 +322,95 @@ static int cdrom_transfer_packet_command (ide_dev_t *dev,
* Block read functions.
*/
static int cdrom_start_read (ide_dev_t *dev, unsigned int block);
/*
* Interrupt routine to read the final status from a transfer.
* Buffer up to SECTORS_TO_TRANSFER sectors from the drive in our sector
* buffer. SECTOR is the number of the first sector to be buffered.
*/
static void cdrom_read_intr_2 (ide_dev_t *dev)
static void cdrom_buffer_sectors (ide_dev_t *dev, unsigned long sector,
int sectors_to_transfer)
{
int stat;
struct request *rq = ide_cur_rq[dev->hwif];
struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive];
stat = GET_STAT (dev->hwif);
/* Number of sectors to read into the buffer. */
int sectors_to_buffer = MIN (sectors_to_transfer,
(SECTOR_BUFFER_SIZE >> SECTOR_BITS));
char *dest;
if (OK_STAT (stat, 0, BAD_STAT))
/* If we don't yet have a sector buffer, try to allocate one.
If we can't get one atomically, it's not fatal -- we'll just throw
the data away rather than caching it. */
if (info->sector_buffer == NULL)
{
if (rq->current_nr_sectors <= 0)
info->sector_buffer = (char *) kmalloc (SECTOR_BUFFER_SIZE, GFP_ATOMIC);
/* If we couldn't get a buffer, don't try to buffer anything... */
if (info->sector_buffer == NULL)
sectors_to_buffer = 0;
}
/* Remember the sector number and the number of sectors we're storing. */
info->sector_buffered = sector;
info->nsectors_buffered = sectors_to_buffer;
/* Read the data into the buffer. */
dest = info->sector_buffer;
while (sectors_to_buffer > 0)
{
end_request (1, dev->hwif);
IN_WORDS (dest, SECTOR_SIZE / 2);
--sectors_to_buffer;
--sectors_to_transfer;
dest += SECTOR_SIZE;
}
if (rq->current_nr_sectors > 0)
/* Throw away any remaining data. */
while (sectors_to_transfer > 0)
{
cdrom_start_read (dev, rq->sector);
return;
char dum[SECTOR_SIZE];
IN_WORDS (dest, sizeof (dum) / 2);
--sectors_to_transfer;
}
}
/*
* Check the contents of the interrupt reason register from the cdrom
* and attempt to recover if there are problems. Returns 0 if everything's
* ok; nonzero if the request has been terminated.
*/
static inline
int cdrom_read_check_ireason (ide_dev_t *dev, int len, int ireason)
{
ireason &= 3;
if (ireason == 2) return 0;
if (ireason == 0)
{
/* Whoops... The drive is expecting to receive data from us! */
printk ("%s: cdrom_read_intr: "
"Drive wants to transfer data the wrong way!\n",
dev->name);
/* Throw some data at the drive so it doesn't hang
and quit this request. */
while (len > 0)
{
short dum = 0;
OUT_WORDS (&dum, 1);
len -= 2;
}
}
else
ide_error (dev, "cdrom_read_intr_2", stat);
{
/* Drive wants a command packet, or invalid ireason... */
printk ("%s: cdrom_read_intr: bad interrupt reason %d\n",
dev->name, ireason);
}
cdrom_end_request (0, dev);
DO_REQUEST;
return -1;
}
......@@ -304,34 +419,175 @@ static void cdrom_read_intr_2 (ide_dev_t *dev)
*/
static void cdrom_read_intr (ide_dev_t *dev)
{
int stat_dum, len;
int stat;
int ireason, len, sectors_to_transfer, nskip;
struct request *rq = ide_cur_rq[dev->hwif];
/* Check for errors. */
if (cdrom_decode_status (dev, DRQ_STAT, &stat_dum)) return;
if (cdrom_decode_status (dev, 0, &stat)) return;
/* Error bit not set.
Read the device registers to see how much data is waiting. */
/* Read the interrupt reason and the transfer length. */
ireason = IN_BYTE (HD_NSECTOR, dev->hwif);
len = IN_BYTE (HD_LCYL, dev->hwif) + 256 * IN_BYTE (HD_HCYL, dev->hwif);
if (len != CD_FRAMESIZE)
/* If DRQ is clear, the command has completed. */
if ((stat & DRQ_STAT) == 0)
{
printk ("cdrom_read_intr: funny value for read length %d\n", len);
if (len > CD_FRAMESIZE) len = CD_FRAMESIZE;
/* If we're not done filling the current buffer, complain.
Otherwise, complete the command normally. */
if (rq->current_nr_sectors > 0)
{
printk ("%s: cdrom_read_intr: data underrun (%ld blocks)\n",
dev->name, rq->current_nr_sectors);
cdrom_end_request (0, dev);
}
else
cdrom_end_request (1, dev);
IN_WORDS (rq->buffer, len/2);
DO_REQUEST;
return;
}
/* Check that the drive is expecting to do the same thing that we are. */
if (cdrom_read_check_ireason (dev, len, ireason)) return;
/* Assume that the drive will always provide data in multiples of at least
SECTOR_SIZE, as it gets hairy to keep track of the transfers otherwise. */
if ((len % SECTOR_SIZE) != 0)
{
printk ("%s: cdrom_read_intr: Bad transfer size %d\n",
dev->name, len);
printk (" This drive is not supported by this version of the driver\n");
cdrom_end_request (0, dev);
DO_REQUEST;
return;
}
/* The number of sectors we need to read from the drive. */
sectors_to_transfer = len / SECTOR_SIZE;
rq->current_nr_sectors -= BLOCKS_PER_FRAME;
rq->nr_sectors -= BLOCKS_PER_FRAME;
rq->sector += BLOCKS_PER_FRAME;
rq->buffer += CD_FRAMESIZE;
/* First, figure out if we need to bit-bucket any of the leading sectors. */
nskip = MIN ((int)(rq->current_nr_sectors - (rq->bh->b_size >> SECTOR_BITS)),
sectors_to_transfer);
while (nskip > 0)
{
/* We need to throw away a sector. */
char dum[SECTOR_SIZE];
IN_WORDS (dum, sizeof (dum) / 2);
--rq->current_nr_sectors;
--nskip;
--sectors_to_transfer;
}
/* Now loop while we still have data to read from the drive. */
while (sectors_to_transfer > 0)
{
int this_transfer;
/* If we've filled the present buffer but there's another chained
buffer after it, move on. */
if (rq->current_nr_sectors == 0 &&
rq->nr_sectors > 0)
cdrom_end_request (1, dev);
/* If the buffers are full, cache the rest of the data in our
internal buffer. */
if (rq->current_nr_sectors == 0)
{
cdrom_buffer_sectors (dev, rq->sector, sectors_to_transfer);
sectors_to_transfer = 0;
}
else
{
/* Transfer data to the buffers.
Figure out how many sectors we can transfer
to the current buffer. */
this_transfer = MIN (sectors_to_transfer,
rq->current_nr_sectors);
/* Read this_transfer sectors into the current buffer. */
while (this_transfer > 0)
{
IN_WORDS (rq->buffer, SECTOR_SIZE / 2);
rq->buffer += SECTOR_SIZE;
--rq->nr_sectors;
--rq->current_nr_sectors;
++rq->sector;
--this_transfer;
--sectors_to_transfer;
}
}
}
/* Wait for another interrupt with the final status. */
ide_handler[dev->hwif] = cdrom_read_intr_2;
/* Done moving data!
Wait for another interrupt. */
ide_handler[dev->hwif] = cdrom_read_intr;
}
/*
* Try to satisfy some of the current read request from our cached data.
* Returns nonzero if the request has been completed, zero otherwise.
*/
static int cdrom_read_from_buffer (ide_dev_t *dev)
{
struct cdrom_info *info = &cdrom_info[dev->hwif][dev->select.b.drive];
struct request *rq = ide_cur_rq[dev->hwif];
/* Can't do anything if there's no buffer. */
if (info->sector_buffer == NULL) return 0;
/* Loop while this request needs data and the next block is present
in our cache. */
while (rq->nr_sectors > 0 &&
rq->sector >= info->sector_buffered &&
rq->sector < info->sector_buffered + info->nsectors_buffered)
{
if (rq->current_nr_sectors == 0)
cdrom_end_request (1, dev);
memcpy (rq->buffer,
info->sector_buffer +
(rq->sector - info->sector_buffered) * SECTOR_SIZE,
SECTOR_SIZE);
rq->buffer += SECTOR_SIZE;
--rq->current_nr_sectors;
--rq->nr_sectors;
++rq->sector;
}
/* If we've statisfied the current request, terminate it successfully. */
if (rq->nr_sectors == 0)
{
cdrom_end_request (1, dev);
return -1;
}
/* Move on to the next buffer if needed. */
if (rq->current_nr_sectors == 0)
cdrom_end_request (1, dev);
/* If this condition does not hold, then the kluge i use to
represent the number of sectors to skip at the start of a transfer
will fail. I think that this will never happen, but let's be
paranoid and check. */
if (rq->current_nr_sectors < (rq->bh->b_size >> SECTOR_BITS) &&
(rq->sector % SECTORS_PER_FRAME) != 0)
{
printk ("%s: cdrom_read_from_buffer: buffer botch (%ld)\n",
dev->name, rq->sector);
cdrom_end_request (0, dev);
return -1;
}
return 0;
}
/*
* Routine to send a read packet command to the drive.
* This is usually called directly from cdrom_start_read.
......@@ -343,10 +599,51 @@ static int cdrom_start_read_continuation (ide_dev_t *dev)
struct packet_command pc;
struct request *rq = ide_cur_rq[dev->hwif];
int nsect, sector, nframes, frame, nskip;
/* Number of sectors to transfer. */
nsect = rq->nr_sectors;
/* Starting sector. */
sector = rq->sector;
/* If the requested sector doesn't start on a cdrom block boundary,
we must adjust the start of the transfer so that it does,
and remember to skip the first few sectors. If the CURRENT_NR_SECTORS
field is larger than the size of the buffer, it will mean that
we're to skip a number of sectors equal to the amount by which
CURRENT_NR_SECTORS is larger than the buffer size. */
nskip = (sector % SECTORS_PER_FRAME);
if (nskip > 0)
{
/* Sanity check... */
if (rq->current_nr_sectors != (rq->bh->b_size >> SECTOR_BITS))
{
printk ("%s: cdrom_start_read_continuation: buffer botch (%ld)\n",
dev->name, rq->current_nr_sectors);
cdrom_end_request (0, dev);
DO_REQUEST;
return 1;
}
sector -= nskip;
nsect += nskip;
rq->current_nr_sectors += nskip;
}
/* Convert from sectors to cdrom blocks, rounding up the transfer
length if needed. */
nframes = (nsect + SECTORS_PER_FRAME-1) / SECTORS_PER_FRAME;
frame = sector / SECTORS_PER_FRAME;
/* Largest number of frames was can transfer at once is 64k-1. */
nframes = MIN (nframes, 65535);
/* Set up the command */
memset (&pc.c, 0, sizeof (pc.c));
pc.c[0] = READ_10;
pc.c[8] = 1; /* lsb of transfer length */
pc.c[7] = (nframes >> 8);
pc.c[8] = (nframes & 0xff);
/* Write the sector address into the command image. */
{
......@@ -354,7 +651,7 @@ static int cdrom_start_read_continuation (ide_dev_t *dev)
struct {unsigned char b0, b1, b2, b3;} b;
struct {unsigned long l0;} l;
} conv;
conv.l.l0 = rq->sector / BLOCKS_PER_FRAME;
conv.l.l0 = frame;
pc.c[2] = conv.b.b3;
pc.c[3] = conv.b.b2;
pc.c[4] = conv.b.b1;
......@@ -381,17 +678,25 @@ static int cdrom_start_read (ide_dev_t *dev, unsigned int block)
{
struct request *rq = ide_cur_rq[dev->hwif];
if (rq->cmd == READ &&
(rq->current_nr_sectors != BLOCKS_PER_FRAME ||
(rq->sector & (BLOCKS_PER_FRAME-1)) != 0))
/* We may be retrying this request after an error.
Fix up any weirdness which might be present in the request packet. */
if (rq->buffer != rq->bh->b_data)
{
printk ("cdrom_start_read: funny request 0x%lx 0x%lx\n",
rq->current_nr_sectors, rq->sector);
end_request (0, dev->hwif);
return 1;
int n = (rq->buffer - rq->bh->b_data) / SECTOR_SIZE;
rq->buffer = rq->bh->b_data;
rq->nr_sectors += n;
rq->current_nr_sectors += n;
rq->sector -= n;
}
if (cdrom_start_packet_command (dev, CD_FRAMESIZE))
if (rq->current_nr_sectors > (rq->bh->b_size >> SECTOR_BITS))
rq->current_nr_sectors = rq->bh->b_size;
/* Satisfy whatever we can of this request from our cached sector. */
if (cdrom_read_from_buffer (dev))
return 1;
if (cdrom_start_packet_command (dev, 32768))
return 1;
if (CDROM_FLAGS (dev)->drq_interrupt)
......@@ -406,6 +711,7 @@ static int cdrom_start_read (ide_dev_t *dev, unsigned int block)
}
/****************************************************************************
* Execute all other packet commands.
......@@ -429,13 +735,13 @@ static void cdrom_pc_intr (ide_dev_t *dev)
if ((stat & DRQ_STAT) == 0)
{
if (pc->buflen == 0)
end_request (1, dev->hwif);
cdrom_end_request (1, dev);
else
{
printk ("%s: cdrom_pc_intr: data underrun %d\n",
dev->name, pc->buflen);
pc->stat = 1;
end_request (1, dev->hwif);
cdrom_end_request (1, dev);
}
DO_REQUEST;
return;
......@@ -616,23 +922,10 @@ static int do_rw_cdrom (ide_dev_t *dev, unsigned long block)
if (rq -> cmd != READ)
{
printk ("ide-cd: bad cmd %d\n", rq -> cmd);
end_request (0, dev->hwif);
cdrom_end_request (0, dev);
return 1;
}
if (rq->cmd == READ)
{
/* This can happen if there was an I/O error on the previous
buffer in this request. */
if ((rq->nr_sectors & (BLOCKS_PER_FRAME-1)) == BLOCKS_PER_FRAME-1 &&
(rq->sector & (BLOCKS_PER_FRAME-1)) == 1 &&
(rq->current_nr_sectors & (BLOCKS_PER_FRAME-1)) == 0)
{
rq->nr_sectors &= (BLOCKS_PER_FRAME-1);
rq->sector = (rq->sector+BLOCKS_PER_FRAME) & (BLOCKS_PER_FRAME-1);
}
}
return cdrom_start_read (dev, block);
}
......@@ -802,14 +1095,14 @@ static int
cdrom_read_toc (ide_dev_t *dev)
{
int stat, ntracks, i;
struct atapi_toc *toc = cdrom_toc[dev->hwif][dev->select.b.drive];
struct atapi_toc *toc = cdrom_info[dev->hwif][dev->select.b.drive].toc;
if (toc == NULL)
{
/* Try to allocate space. */
toc = (struct atapi_toc *) kmalloc (sizeof (struct atapi_toc),
GFP_KERNEL);
cdrom_toc[dev->hwif][dev->select.b.drive] = toc;
cdrom_info[dev->hwif][dev->select.b.drive].toc = toc;
}
if (toc == NULL)
......@@ -1002,7 +1295,7 @@ int cdrom_get_toc_entry (ide_dev_t *dev, int track,
stat = cdrom_read_toc (dev);
if (stat) return stat;
toc = cdrom_toc[dev->hwif][dev->select.b.drive];
toc = cdrom_info[dev->hwif][dev->select.b.drive].toc;
/* Check validity of requested track number. */
ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
......@@ -1098,7 +1391,7 @@ static int ide_cdrom_ioctl (ide_dev_t *dev, struct inode *inode,
stat = cdrom_read_toc (dev);
if (stat) return stat;
toc = cdrom_toc[dev->hwif][dev->select.b.drive];
toc = cdrom_info[dev->hwif][dev->select.b.drive].toc;
tochdr.cdth_trk0 = toc->hdr.first_track;
tochdr.cdth_trk1 = toc->hdr.last_track;
......@@ -1327,18 +1620,22 @@ static void cdrom_setup (ide_dev_t *dev)
CDROM_FLAGS (dev)->no_playaudio12 = 0;
CDROM_FLAGS (dev)->drq_interrupt = ((dev->id->config & 0x0060) == 0x20);
cdrom_toc[dev->hwif][dev->select.b.drive] = NULL;
cdrom_info[dev->hwif][dev->select.b.drive].toc = NULL;
cdrom_info[dev->hwif][dev->select.b.drive].sector_buffer = NULL;
cdrom_info[dev->hwif][dev->select.b.drive].sector_buffered = 0;
cdrom_info[dev->hwif][dev->select.b.drive].nsectors_buffered = 0;
}
#undef MIN
#undef SECTOR_SIZE
#undef SECTOR_BITS
/*
* TODO:
* Retrieve and interpret extended ATAPI error codes.
* Transfer multiple sectors at once.
* Read actual disk capacity.
* Support demand-paged executables (1k block sizes?).
* Multisession support.
* Direct reading of audio data.
* Eject-on-dismount.
......
/*
* linux/drivers/block/ide.c Version 3.6 January 5, 1994
* linux/drivers/block/ide.c Version 3.8 January 12, 1995
*
* Copyright (C) 1994 Linus Torvalds & authors (see below)
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
/*
......@@ -92,6 +92,10 @@
* increase DRQ_WAIT to eliminate nuisance messages
* wait for DRQ_STAT instead of DATA_READY during probing
* (courtesy of Gary Thomas gary@efland.UU.NET)
* Version 3.8 fixed byte-swapping for confused Mitsumi cdrom drives
* update of ide-cd.c from Scott, allows blocksize=1024
* cdrom probe fixes, inspired by jprang@uni-duisburg.de
*
* To do:
* - special 32-bit controller-type detection & support
* - figure out why two WD drives on one i/f sometimes don't identify
......@@ -460,7 +464,7 @@ static void do_ide_reset (ide_dev_t *dev)
printk("%s: do_ide_reset: ", ide_name[DEV_HWIF]);
/* ATAPI devices usually do *not* assert READY after a reset */
if (!OK_STAT(tmp=GET_STAT(DEV_HWIF), 0, BUSY_STAT)) {
printk("timed out, status=0x%02x\n", tmp);
printk("timed-out, status=0x%02x\n", tmp);
} else {
if ((tmp = GET_ERR(DEV_HWIF)) == 1)
printk("success\n");
......@@ -1596,19 +1600,23 @@ static void do_identify (ide_dev_t *dev)
sti();
/*
* Everything except ATAPI seems to use big-endian string ordering,
* whereas the NEC and Vertos ATAPI drives both use little-endian.
* Latest reports indicate that some Mitsumi ATAPI use big-endian.
* Non-ATAPI drives seem to always use big-endian string ordering.
* Most ATAPI cdrom drives, such as the NEC, Vertos, and some Mitsumi
* models, use little-endian. But otherMitsumi models appear to use
* big-endian, confusing the issue. We try to take all of this into
* consideration, "knowing" that Mitsumi drive names begin with "FX".
*/
bswap = (id->config & 0x8000) ? 0 : 1;
if (bswap && id->model[0] == 'F' && id->model[1] == 'X')
bswap = 1;
if (id->model[0] != 'X' || id->model[1] != 'F') {
if ((id->model[0] == 'F' && id->model[1] == 'X') || (id->config & 0x8000))
bswap = 0;
fixstring (id->serial_no, sizeof(id->serial_no), bswap);
fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
}
fixstring (id->model, sizeof(id->model), bswap);
fixstring (id->fw_rev, sizeof(id->fw_rev), bswap);
fixstring (id->serial_no, sizeof(id->serial_no), bswap);
/*
* Check for ATAPI device (such as an NEC-260 IDE cdrom drive)
* Check for an ATAPI device
*/
if (id->config & 0x8000) {
#ifdef CONFIG_BLK_DEV_IDECD
......@@ -1715,9 +1723,14 @@ static void delay_10ms (void)
static int try_to_identify (ide_dev_t *dev, byte cmd)
/*
* Returns: 0 device was identified
* 1 device timed-out (no response to identify request)
* 2 device aborted the command (refused to identify itself)
*/
{
int rc;
unsigned long timer, timeout;
unsigned long timeout;
#if PROBE_FOR_IRQS
int irqs = 0;
static byte irq_probed[2] = {0,0};
......@@ -1733,58 +1746,61 @@ static int try_to_identify (ide_dev_t *dev, byte cmd)
delay_10ms(); /* take a deep breath */
OUT_BYTE(cmd,HD_COMMAND); /* ask drive for ID */
delay_10ms(); /* wait for BUSY_STAT */
timeout = (cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY;
for (timer = jiffies + (timeout / 2); timer > jiffies;) {
if ((IN_BYTE(HD_ALTSTATUS,DEV_HWIF) & BUSY_STAT) == 0) {
delay_10ms(); /* wait for IRQ & DATA_READY */
if (OK_STAT(GET_STAT(DEV_HWIF),DRQ_STAT,BAD_RW_STAT)){
cli(); /* some sys need this */
timeout = ((cmd == WIN_IDENTIFY) ? WAIT_WORSTCASE : WAIT_PIDENTIFY) / 2;
for (timeout += jiffies; IN_BYTE(HD_ALTSTATUS,DEV_HWIF) & BUSY_STAT;) {
if (timeout < jiffies) {
#if PROBE_FOR_IRQS
if (!irq_probed[DEV_HWIF])
(void) probe_irq_off(irqs);
#endif /* PROBE_FOR_IRQS */
return 1; /* drive timed-out */
}
}
delay_10ms(); /* wait for IRQ and DRQ_STAT */
if (OK_STAT(GET_STAT(DEV_HWIF),DRQ_STAT,BAD_RW_STAT)) {
cli(); /* some systems need this */
do_identify(dev); /* drive returned ID */
rc = 0;
rc = 0; /* success */
} else
rc = 1; /* drive refused ID */
rc = 2; /* drive refused ID */
#if PROBE_FOR_IRQS
if (!irq_probed[DEV_HWIF]) {
irqs = probe_irq_off(irqs); /* end probe */
irqs = probe_irq_off(irqs); /* get irq number */
if (irqs > 0) {
irq_probed[DEV_HWIF] = 1;
ide_irq[DEV_HWIF] = irqs;
} else
} else /* Mmmm.. multiple IRQs */
printk("%s: IRQ probe failed (%d)\n", dev->name, irqs);
}
#endif /* PROBE_FOR_IRQS */
goto done_try;
}
}
rc = 2; /* it ain't responding */
#if PROBE_FOR_IRQS
if (!irq_probed[DEV_HWIF])
(void) probe_irq_off(irqs); /* end probing */
#endif /* PROBE_FOR_IRQS */
done_try:
OUT_BYTE(dev->ctl|2,HD_CMD); /* disable device irq */
return rc;
}
/*
* This routine has the difficult job of finding a drive if it exists,
* without getting hung up if it doesn't exist, and without leaving any IRQs
* dangling to haunt us later. The last point actually occurred in v2.3, and
* is the reason for the slightly complex exit sequence. If a drive is "known"
* to exist (from CMOS or kernel parameters), but does not respond right away,
* the probe will "hang in there" for the maximum wait time (about 30 seconds).
* Otherwise, it will exit much more quickly.
* without getting hung up if it doesn't exist, without trampling on
* ethernet cards, and without leaving any IRQs dangling to haunt us later.
*
* Returns 1 if device present but not identified. Returns 0 otherwise.
* If a drive is "known" to exist (from CMOS or kernel parameters),
* but does not respond right away, the probe will "hang in there"
* for the maximum wait time (about 30 seconds), otherwise it will
* exit much more quickly.
*/
static int do_probe (ide_dev_t *dev, byte cmd)
/*
* Returns: 0 device was identified
* 1 device timed-out (no response to identify request)
* 2 device aborted the command (refused to identify itself)
* 3 bad status from device (possible for ATAPI drives)
* 4 probe was not attempted
*/
{
int rc;
#ifdef CONFIG_BLK_DEV_IDECD
if (dev->present) { /* avoid waiting for inappropriate probes */
if ((dev->type == disk) ^ (cmd == WIN_IDENTIFY))
return 1;
return 4;
}
#endif /* CONFIG_BLK_DEV_IDECD */
#if DEBUG
......@@ -1794,21 +1810,23 @@ static int do_probe (ide_dev_t *dev, byte cmd)
#endif
OUT_BYTE(dev->select.all,HD_CURRENT); /* select target drive */
delay_10ms(); /* wait for BUSY_STAT */
if (IN_BYTE(HD_CURRENT,DEV_HWIF) != dev->select.all && !dev->present)
return 0; /* no i/f present: avoid killing ethernet cards */
if (IN_BYTE(HD_CURRENT,DEV_HWIF) != dev->select.all && !dev->present) {
OUT_BYTE(0xa0,HD_CURRENT); /* exit with drive0 selected */
return 3; /* no i/f present: avoid killing ethernet cards */
}
if (OK_STAT(GET_STAT(DEV_HWIF),READY_STAT,BUSY_STAT)
|| dev->present || cmd == WIN_PIDENTIFY)
{
if ((rc = try_to_identify(dev, cmd))) /* send cmd and wait */
rc = try_to_identify(dev, cmd); /* try again */
if (rc)
printk("%s: identification %s\n", dev->name,
(rc == 1) ? "refused" : "timed-out");
rc = try_to_identify(dev, cmd); /* failed: try again */
if (rc == 1)
printk("%s: no response\n", dev->name);
OUT_BYTE(dev->ctl|2,HD_CMD); /* disable device irq */
delay_10ms();
(void) GET_STAT(DEV_HWIF); /* ensure drive irq is clear */
} else {
rc = 2; /* drive not present */
rc = 3; /* not present or maybe ATAPI */
}
if (dev->select.b.drive == 1) {
OUT_BYTE(0xa0,HD_CURRENT); /* exit with drive0 selected */
......@@ -1821,16 +1839,20 @@ static int do_probe (ide_dev_t *dev, byte cmd)
}
static byte probe_for_drive (ide_dev_t *dev)
/*
* Returns: 0 no device was found
* 1 device was found (note: dev->present might still be 0)
*/
{
if (dev->dont_probe) /* skip probing? */
return dev->present;
if (do_probe(dev, WIN_IDENTIFY) == 1) { /* 1 = drive aborted the cmd */
if (do_probe(dev, WIN_IDENTIFY) >= 2) { /* if !(success || timed-out) */
#ifdef CONFIG_BLK_DEV_IDECD
(void) do_probe(dev, WIN_PIDENTIFY);
(void) do_probe(dev, WIN_PIDENTIFY); /* look for ATAPI device */
#endif /* CONFIG_BLK_DEV_IDECD */
}
if (!dev->present)
return 0; /* drive not present */
return 0; /* drive not found */
if (dev->id == NULL) { /* identification failed? */
if (dev->type == disk) {
printk ("%s: non-IDE device, CHS=%d/%d/%d\n",
......@@ -1843,7 +1865,7 @@ static byte probe_for_drive (ide_dev_t *dev)
#endif /* CONFIG_BLK_DEV_IDECD */
else {
dev->present = 0; /* nuke it */
return 0; /* drive not present */
return 1; /* drive was found */
}
}
#ifdef CONFIG_BLK_DEV_IDECD
......@@ -1857,7 +1879,7 @@ static byte probe_for_drive (ide_dev_t *dev)
dev->present = 0;
}
}
return 1; /* drive present */
return 1; /* drive was found */
}
static void probe_for_drives (byte hwif)
......@@ -1877,15 +1899,15 @@ static void probe_for_drives (byte hwif)
save_flags(flags);
sti(); /* needed for jiffies and irq probing */
/* second drive can only exist if first drive was present */
/* second drive should only exist if first drive was found */
if (probe_for_drive(&devs[0]) || devs[1].present)
(void) probe_for_drive(&devs[1]);
#if PROBE_FOR_IRQS
(void) probe_irq_off(probe_irq_on()); /* clear dangling irqs */
#endif /* PROBE_FOR_IRQS */
if (devs[0].present || devs[1].present) {
request_region(IDE_PORT(HD_DATA,HWIF),8,"ide");
request_region(IDE_PORT(HD_CMD,HWIF),1,"ide");
request_region(IDE_PORT(HD_DATA,HWIF),8,ide_name[HWIF]);
request_region(IDE_PORT(HD_CMD,HWIF),1,ide_name[HWIF]);
}
restore_flags(flags);
}
......
......@@ -9,7 +9,7 @@
* Not for the TEAC CD-55A drive (yet).
* Not for the CreativeLabs CD200 drive (yet).
*
* NOTE: This is release 3.0.
* NOTE: This is release 3.1.
* It works with my SbPro & drive CR-521 V2.11 from 2/92
* and with the new CR-562-B V0.75 on a "naked" Panasonic
* CI-101P interface. And vice versa.
......@@ -169,6 +169,13 @@
* Started CD200 support. Drive detection should work, but nothing
* more.
*
* 3.1 Working to support the CD200 and the Teac CD-55A drives.
* AT-BUS style device numbering no longer used: use SCSI style now.
* So, the first "found" device has MINOR 0, regardless of the
* jumpered drive ID. This implies modifications to the /dev/sbpcd*
* entries for some people, but will help the DAU (german TLA, english:
* "newbie", maybe ;-) to install his "first" system from a CD.
*
* TODO
*
* disk change detection
......@@ -209,7 +216,9 @@
*
*/
#define SBPCD_ISSUE 1 /* change to 2, 3, 4 for multiple interface boards */
#ifndef SBPCD_ISSUE
#define SBPCD_ISSUE 1
#endif SBPCD_ISSUE
#include <linux/config.h>
#include <linux/errno.h>
......@@ -244,13 +253,13 @@
#include "blk.h"
#define VERSION "3.0 Eberhard Moenkeberg <emoenke@gwdg.de>"
#define VERSION "3.1 Eberhard Moenkeberg <emoenke@gwdg.de>"
/*
* still testing around...
*/
#define MULTISESSION_BY_DRIVER 1 /* if set to 0 here, we need a counterpart in
* linux/fs/isofs/inode.c
#define MULTISESSION_BY_DRIVER 0 /* if set to 0 here, we need the counterpart
* in linux/fs/isofs/inode.c
*/
#define READ_AUDIO 4 /* max. number of audio frames to read with one */
/* request (allocates n* 2352 bytes kernel memory!) */
......@@ -272,6 +281,8 @@
#define PRINTK_BUG 0
#define TEST_STI 0
#define DISTRIBUTION 1
#if 0
#define INLINE
#else
......@@ -329,7 +340,8 @@
* send mail to emoenke@gwdg.de if your interface card is not FULLY
* represented here.
*/
static int autoprobe[] =
#if !(SBPCD_ISSUE-1)
static int sbpcd_probe[] =
{
CDROM_PORT, SBPRO, /* probe with user's setup first */
0x230, 1, /* Soundblaster Pro and 16 (default) */
......@@ -348,23 +360,29 @@ static int autoprobe[] =
0x330, 2, /* SPEA Media FX (default) */
0x320, 2, /* SPEA Media FX */
0x340, 2, /* SPEA Media FX */
0x350, 2, /* SPEA Media FX */
0x634, 0, /* some newer sound cards */
0x638, 0, /* some newer sound cards */
/* due to incomplete address decoding of the SbPro card, these must be last */
0x630, 0, /* "sound card #9" (default) */
0x650, 0, /* "sound card #9" */
#if 0
/* some "hazardous" locations
/*
* some "hazardous" locations
* (will stop the bus if a NE2000 ethernet card resides at offset -0x10)
*/
#if 0
0x330, 0, /* Lasermate, CI-101P, WDH-7001C */
0x350, 0, /* Lasermate, CI-101P */
0x350, 2, /* SPEA Media FX */
0x370, 0, /* Lasermate, CI-101P */
0x290, 1, /* Soundblaster 16 */
0x310, 0, /* Lasermate, CI-101P, WDH-7001C */
#endif
};
#else
static int sbpcd_probe[] = {CDROM_PORT, SBPRO}; /* probe with user's setup only */
#endif
#define NUM_AUTOPROBE (sizeof(autoprobe) / sizeof(int))
#define NUM_PROBE (sizeof(sbpcd_probe) / sizeof(int))
/*==========================================================================*/
......@@ -392,7 +410,7 @@ static void sbp_read_cmd(void);
static int sbp_data(void);
static int cmd_out(void);
static int DiskInfo(void);
static int check_media_change(dev_t);
static int sbpcd_chk_disk_change(dev_t);
/*==========================================================================*/
......@@ -430,7 +448,7 @@ static int check_media_change(dev_t);
* (1<<DBG_CD2) MKE CD200 debugging trace
* (1<<DBG_000) unnecessary information
*/
#if 1
#if DISTRIBUTION
static int sbpcd_debug = (1<<DBG_INF) |
(1<<DBG_WRN) |
(1<<DBG_MUL);
......@@ -444,9 +462,9 @@ static int sbpcd_debug = (1<<DBG_INF) |
(1<<DBG_ID) |
(1<<DBG_UPC);
#endif
static unsigned char setup_done = 0;
static int sbpcd_ioaddr = CDROM_PORT; /* default I/O base address */
static int sbpro_type = SBPRO;
static unsigned char setup_done = 0;
static int CDo_command, CDo_reset;
static int CDo_sel_i_d, CDo_enable;
static int CDi_info, CDi_status, CDi_data;
......@@ -515,7 +533,11 @@ static u_int maxtim_data= 9000;
#else
static u_int maxtim_data= 3000;
#endif LONG_TIMING
#if DISTRIBUTION
static int n_retries=3;
#else
static int n_retries=1;
#endif
/*==========================================================================*/
static int ndrives=0;
......@@ -529,7 +551,8 @@ static int sbpcd_blocksizes[NR_SBPCD] = {0, };
static int d=0; /* DriveStruct index: drive number */
static struct {
char drv_minor; /* minor number or -1 */
char drv_id; /* "jumpered" drive ID or -1 */
char drv_sel; /* drive select lines bits */
char drive_model[9];
char firmware_version[4];
......@@ -665,9 +688,11 @@ static int sbpcd_dbg_ioctl(unsigned long arg, int level)
*/
static INLINE void sbp_sleep(u_int jifs)
{
sti();
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + jifs;
schedule();
sti();
}
/*==========================================================================*/
......@@ -2266,6 +2291,18 @@ static int yy_ReadError(int fam)
#endif CD200
/*==========================================================================*/
static void ask_mail(void)
{
int i;
printk("SBPCD: please mail the following lines to emoenke@gwdg.de:\n");
printk("SBPCD: infobuf = \"");
for (i=0;i<12;i++) printk("%02X ",infobuf[i]);
printk("\"\nSBPCD: infobuf = \"");
for (i=0;i<12;i++) printk("%c",infobuf[i]);
printk("\"\n");
}
/*==========================================================================*/
static int check_version(void)
{
int i, j;
......@@ -2287,7 +2324,7 @@ static int check_version(void)
#if 0
OUT(CDo_reset,0);
sbp_sleep(600);
OUT(CDo_enable,d);
OUT(CDo_enable,DriveStruct[d].drv_sel);
#endif
drvcmd[0]=CMD2_READ_VER;
response_count=12;
......@@ -2304,8 +2341,8 @@ static int check_version(void)
for (i=0;i<12;i++) DPRINTF((DBG_ID,"%c",infobuf[i]));
DPRINTF((DBG_ID,"\"\n"));
}
}
else
{
for (i=0;i<5;i++) if (infobuf[i]!=family2[i]) break;
if (i==5)
{
......@@ -2321,6 +2358,7 @@ static int check_version(void)
}
else
{
printk("\n\nSBPCD: possibly CD-55A present.\n");
for (i=0;i<5;i++) if (infobuf[i]!=familyT[i]) break;
if (i==5)
{
......@@ -2333,18 +2371,12 @@ static int check_version(void)
DriveStruct[d].drive_model[6]=infobuf[i++];
DriveStruct[d].drive_model[7]=infobuf[i++];
DriveStruct[d].drive_model[8]=0;
}
DriveStruct[d].drv_type=drv_famT;
}
}
#if 1
if (DriveStruct[d].drv_type)
{
printk("\n\nSBPCD: new drive CD200 or CD-55A successfully detected.\n");
printk("SBPCD: support is not fulfilled yet - drive gets ignored.\n");
printk("SBPCD: just wait some days - don't mail, please.\n\n");
DriveStruct[d].drv_type=0;
}
#endif
if (!DriveStruct[d].drv_type)
{
/* check for CR-52x, CR-56x and LCS-7260 */
......@@ -2425,7 +2457,15 @@ static int check_version(void)
(DriveStruct[d].firmware_version[1]!='4') ||
(DriveStruct[d].firmware_version[2]!='F') ||
(DriveStruct[d].firmware_version[3]!='4'))
printk("SBPCD: please mail me your LCS-7260 DOS driver.\n");
ask_mail();
}
else if (famT_drive)
{
printk("\n\nSBPCD: possibly TEAC CD-55A present.\n");
printk("SBPCD: support is not fulfilled yet - drive gets ignored.\n");
ask_mail();
DriveStruct[d].drv_type=0;
return (-1);
}
else
{
......@@ -2446,8 +2486,16 @@ static int check_version(void)
if (j<100) DriveStruct[d].drv_type=drv_099;
else DriveStruct[d].drv_type=drv_100;
}
else /* CD200, CD-55A */
else if (fam2_drive)
{
printk("\n\nSBPCD: new drive CD200 (%s)detected.\n", DriveStruct[d].firmware_version);
printk("SBPCD: support is not fulfilled yet - drive gets ignored.\n");
if (j!=101) /* only 1.01 known at time */
ask_mail();
else
printk("SBPCD: just wait some days...\n\n");
DriveStruct[d].drv_type=0;
return (-1);
}
}
DPRINTF((DBG_LCS,"SBPCD: drive type %02X\n",DriveStruct[d].drv_type));
......@@ -2455,17 +2503,16 @@ static int check_version(void)
return (0);
}
/*==========================================================================*/
static int switch_drive(int num)
static int switch_drive(int i)
{
int i;
d=num;
i=num;
if (sbpro_type==1) i=(i&0x01)<<1|(i&0x02)>>1;
OUT(CDo_enable,i);
DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DriveStruct[d].drv_minor));
d=i;
if (DriveStruct[d].drv_id!=-1)
{
OUT(CDo_enable,DriveStruct[d].drv_sel);
DPRINTF((DBG_DID,"SBPCD: drive %d (ID=%d) activated.\n", i, DriveStruct[d].drv_id));
return (0);
}
else return (-1);
}
/*==========================================================================*/
/*
......@@ -2481,26 +2528,27 @@ static int check_drives(void)
ndrives=0;
for (j=0;j<NR_SBPCD;j++)
{
DriveStruct[j].drv_minor=j;
switch_drive(j);
DPRINTF((DBG_ID,"SBPCD: check_drives: drive %d activated.\n",j));
DriveStruct[ndrives].drv_id=j;
if (sbpro_type==1) DriveStruct[ndrives].drv_sel=(j&0x01)<<1|(j&0x02)>>1;
else DriveStruct[ndrives].drv_sel=j;
switch_drive(ndrives);
DPRINTF((DBG_INI,"SBPCD: check_drives: drive %d (ID=%d) activated.\n",ndrives,j));
i=check_version();
DPRINTF((DBG_ID,"SBPCD: check_version returns %d.\n",i));
if (i>=0)
if (i<0) DPRINTF((DBG_INI,"SBPCD: check_version returns %d.\n",i));
else
{
ndrives++;
DriveStruct[d].drv_options=drv_pattern[j];
if (fam0L_drive)
DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
printk("%sDrive %d: %.9s (%.4s)\n", printk_header,
DriveStruct[d].drv_minor,
if (fam0L_drive) DriveStruct[d].drv_options&=~(speed_auto|speed_300|speed_150);
printk("%sDrive %d (ID=%d): %.9s (%.4s)\n", printk_header, d,
DriveStruct[d].drv_id,
DriveStruct[d].drive_model,
DriveStruct[d].firmware_version);
printk_header=" - ";
ndrives++;
}
else DriveStruct[d].drv_minor=-1;
}
for (j=ndrives;j<NR_SBPCD;j++) DriveStruct[j].drv_id=-1;
if (ndrives==0) return (-1);
return (0);
}
......@@ -2933,16 +2981,15 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
u_long arg)
{
int i, st;
unsigned int *p_lba;
DPRINTF((DBG_IO2,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n",
MINOR(inode->i_rdev), cmd, arg));
if (!inode) return (-EINVAL);
i=MINOR(inode->i_rdev);
if ( (i<0) || (i>=NR_SBPCD) )
if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
{
printk("SBPCD: ioctl: bad device: %d\n", i);
return (-ENODEV); /* no such drive */
printk("SBPCD: ioctl: bad device: %04X\n", inode->i_rdev);
return (-ENXIO); /* no such drive */
}
switch_drive(i);
......@@ -3339,6 +3386,8 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
DPRINTF((DBG_AUD,"SBPCD: read_audio: read aborted by drive\n"));
#if 0000
i=DriveReset(); /* ugly fix to prevent a hang */
#else
i=xx_ReadError();
#endif 0000
continue;
}
......@@ -3424,13 +3473,12 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd,
case CDROMMULTISESSION_SYS: /* tell start-of-last-session to kernel */
DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMMULTISESSION_SYS entered.\n"));
if(!suser()) return -EACCES;
p_lba=(unsigned int *) arg;
if (DriveStruct[d].f_multisession)
*p_lba=DriveStruct[d].lba_multi;
*((unsigned int *) arg)=DriveStruct[d].lba_multi;
else
*p_lba=0;
*((unsigned int *) arg)=0;
DPRINTF((DBG_MUL,"SBPCD: ioctl: CDROMMULTISESSION_SYS done (%d).\n",
p_lba[0]));
((unsigned int *) arg)[0]));
return (0);
case BLKRASET:
......@@ -3471,7 +3519,6 @@ static void sbp_transfer(void)
static void DO_SBPCD_REQUEST(void)
{
u_int block;
int dev;
u_int nsect;
int i, status_tries, data_tries;
......@@ -3482,13 +3529,13 @@ static void DO_SBPCD_REQUEST(void)
if ((CURRENT==NULL)||(CURRENT->dev<0)) goto done;
if (CURRENT -> sector == -1) goto done;
dev = MINOR(CURRENT->dev);
if ( (dev<0) || (dev>=NR_SBPCD) )
i = MINOR(CURRENT->dev);
if ( (i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
{
printk("SBPCD: do_request: bad device: %d\n", dev);
printk("SBPCD: do_request: bad device: %04X\n", CURRENT->dev);
goto done;
}
switch_drive(dev);
switch_drive(i);
INIT_REQUEST;
block = CURRENT->sector; /* always numbered as 512-byte-pieces */
......@@ -3530,13 +3577,14 @@ static void DO_SBPCD_REQUEST(void)
}
#endif XA_TEST1
for (data_tries=3; data_tries > 0; data_tries--)
for (data_tries=n_retries; data_tries > 0; data_tries--)
{
for (status_tries=3; status_tries > 0; status_tries--)
{
flags_cmd_out |= f_respo3;
xx_ReadStatus();
if (sbp_status() != 0) break;
if (st_check) xx_ReadError();
sbp_sleep(1); /* wait a bit, try again */
}
if (status_tries == 0)
......@@ -3761,7 +3809,11 @@ static int sbp_data(void)
if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */
{
DPRINTF((DBG_INF,"SBPCD: read aborted by drive\n"));
#if 0
i=DriveReset(); /* ugly fix to prevent a hang */
#else
i=xx_ReadError();
#endif
return (0);
}
......@@ -3824,17 +3876,15 @@ static int sbpcd_open(struct inode *ip, struct file *fp)
{
int i;
if (ndrives==0) return (-ENXIO); /* no hardware */
if (fp->f_mode & 2)
return -EROFS;
i = MINOR(ip->i_rdev);
if ( (i<0) || (i>=NR_SBPCD) )
if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
{
printk("SBPCD: open: bad device: %d\n", i);
return (-ENODEV); /* no such drive */
printk("SBPCD: open: bad device: %04X\n", ip->i_rdev);
return (-ENXIO); /* no such drive */
}
if (fp->f_mode & 2)
return -EROFS;
switch_drive(i);
flags_cmd_out |= f_respo2;
......@@ -3898,9 +3948,9 @@ static void sbpcd_release(struct inode * ip, struct file * file)
int i;
i = MINOR(ip->i_rdev);
if ( (i<0) || (i>=NR_SBPCD) )
if ((i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1))
{
printk("SBPCD: release: bad device: %d\n", i);
printk("SBPCD: release: bad device: %04X\n", ip->i_rdev);
return;
}
switch_drive(i);
......@@ -3908,7 +3958,6 @@ static void sbpcd_release(struct inode * ip, struct file * file)
DriveStruct[d].sbp_first_frame=DriveStruct[d].sbp_last_frame=-1;
sync_dev(ip->i_rdev); /* nonsense if read only device? */
invalidate_buffers(ip->i_rdev);
DriveStruct[d].diskstate_flags &= ~cd_size_bit;
/*
* try to keep an "open" counter here and unlock the door if 1->0.
......@@ -3923,6 +3972,7 @@ static void sbpcd_release(struct inode * ip, struct file * file)
i=yy_LockDoor(0);
while (i!=0);
if (DriveStruct[d].f_eject) yy_SpinDown();
DriveStruct[d].diskstate_flags &= ~cd_size_bit;
}
}
}
......@@ -3943,7 +3993,7 @@ static struct file_operations sbpcd_fops =
sbpcd_release, /* release */
NULL, /* fsync */
NULL, /* fasync */
check_media_change, /* media_change */
sbpcd_chk_disk_change, /* media_change */
NULL /* revalidate */
};
/*==========================================================================*/
......@@ -4080,24 +4130,24 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n"));
DPRINTF((DBG_WRN,"SBPCD: \n"));
}
autoprobe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
autoprobe[1]=sbpro_type; /* possibly changed by kernel command line */
sbpcd_probe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */
sbpcd_probe[1]=sbpro_type; /* possibly changed by kernel command line */
for (port_index=0;port_index<NUM_AUTOPROBE;port_index+=2)
for (port_index=0;port_index<NUM_PROBE;port_index+=2)
{
addr[1]=autoprobe[port_index];
addr[1]=sbpcd_probe[port_index];
if (check_region(addr[1],4))
{
DPRINTF((DBG_INI,"SBPCD: check_region: %03X is not free.\n",addr[1]));
continue;
}
if (autoprobe[port_index+1]==0) type=str_lm;
else if (autoprobe[port_index+1]==1) type=str_sb;
if (sbpcd_probe[port_index+1]==0) type=str_lm;
else if (sbpcd_probe[port_index+1]==1) type=str_sb;
else type=str_sp;
sbpcd_setup(type, addr);
DPRINTF((DBG_INF,"SBPCD: Trying to detect a %s CD-ROM drive at 0x%X.\n", type, CDo_command));
DPRINTF((DBG_INF,"SBPCD: - "));
if (autoprobe[port_index+1]==2)
if (sbpcd_probe[port_index+1]==2)
{
i=config_spea();
if (i<0)
......@@ -4153,7 +4203,7 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
for (j=0;j<NR_SBPCD;j++)
{
if (DriveStruct[j].drv_minor==-1) continue;
if (DriveStruct[j].drv_id==-1) continue;
switch_drive(j);
if (!famL_drive) xy_DriveReset();
if (!st_spinning) xx_SpinUp();
......@@ -4228,17 +4278,18 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
read_ahead[MAJOR_NR] = SBP_BUFFER_FRAMES * (CD_FRAMESIZE / 512);
request_region(CDo_command,4,"sbpcd");
request_region(CDo_command,4,major_name);
for (j=0;j<NR_SBPCD;j++)
{
if (DriveStruct[j].drv_minor==-1) continue;
if (DriveStruct[j].drv_id==-1) continue;
switch_drive(j);
/*
* allocate memory for the frame buffers
*/
DriveStruct[j].sbp_buf=(u_char *)mem_start;
mem_start += SBP_BUFFER_FRAMES*CD_FRAMESIZE;
if (fam1_drive)
if ((fam1_drive) && (SBP_BUFFER_AUDIO_FRAMES>0))
{
DriveStruct[j].aud_buf=(u_char *)mem_start;
mem_start += SBP_BUFFER_AUDIO_FRAMES*CD_FRAMESIZE_RAW;
......@@ -4274,20 +4325,21 @@ unsigned long SBPCD_INIT(u_long mem_start, u_long mem_end)
* used externally (isofs/inode.c, fs/buffer.c)
* Currently disabled (has to get "synchronized").
*/
static int check_media_change(dev_t full_dev)
static int sbpcd_chk_disk_change(dev_t full_dev)
{
int st;
int i, st;
DPRINTF((DBG_CHK,"SBPCD: media_check (%d) called\n", MINOR(full_dev)));
return (0); /* "busy" test necessary before we really can check */
if ((MAJOR(full_dev)!=MAJOR_NR)||(MINOR(full_dev)>=NR_SBPCD))
i=MINOR(full_dev);
if ( (i<0) || (i>=NR_SBPCD) || (DriveStruct[i].drv_id==-1) )
{
printk("SBPCD: media_check: invalid device %04X.\n", full_dev);
return (-1);
}
switch_drive(MINOR(full_dev));
switch_drive(i);
xx_ReadStatus(); /* command: give 1-byte status */
st=ResponseStatus();
......
/*
* duplication of sbpcd.c for multiple interfaces
*/
#define SBPCD_ISSUE 2
#include "sbpcd.c"
/*
* duplication of sbpcd.c for multiple interfaces
*/
#define SBPCD_ISSUE 3
#include "sbpcd.c"
/*
* duplication of sbpcd.c for multiple interfaces
*/
#define SBPCD_ISSUE 4
#include "sbpcd.c"
......@@ -99,11 +99,12 @@ static char *version =
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/errno.h>
#include <asm/system.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
#include <errno.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
......
Tue Jan 10 10:09:58 1995 Eric Youngdale (eric@andante)
* Linux 1.1.79 released.
Patch from some undetermined individual who needs to get a life :-).
* sr.c: Attacked by spelling bee...
Patches from Gerd Knorr:
* sr.c: make printk messages for photoCD a little more informative.
* sr_ioctl.c: Fix CDROMMULTISESSION_SYS ioctl.
Mon Jan 9 10:01:37 1995 Eric Youngdale (eric@andante)
* Linux 1.1.78 released.
* Makefile: Add empty modules: target.
* Wheee. Now change register_iomem to request_region.
* in2000.c: Bugfix - apparently this is the fix that we have
all been waiting for. It fixes a problem whereby the driver
is not stable under heavy load. Race condition and all that.
Patch from Peter Lu.
Wed Jan 4 21:17:40 1995 Eric Youngdale (eric@andante)
* Linux 1.1.77 released.
* 53c7,8xx.c: Fix from Linus - emulate splx.
Throughout:
Change "snarf_region" with "register_iomem".
* scsi_module.c: New file. Contains support for low-level loadable
scsi drivers. [ERY].
* sd.c: More s/int/long/ changes.
* seagate.c: Explicitly include linux/config.h
* sg.c: Increment/decrement module usage count on open/close.
* sg.c: Be a bit more careful about the user not supplying enough
information for a valid command. Pass correct size down to
scsi_do_cmd.
* sr.c: More changes for Photo-CD. This apparently breaks NEC drives.
* sr_ioctl.c: Support CDROMMULTISESSION ioctl.
Sun Jan 1 19:55:21 1995 Eric Youngdale (eric@andante)
* Linux 1.1.76 released.
* constants.c: Add type cast in switch statement.
* scsi.c (scsi_free): Change datatype of "offset" to long.
(scsi_malloc): Change a few more variables to long. Who
did this and why was it important? 64 bit machines?
Lots of changes to use save_state/restore_state instead of cli/sti.
Files changed include:
* aha1542.c:
* aha1740.c:
* buslogic.c:
* in2000.c:
* scsi.c:
* scsi_debug.c:
* sd.c:
* sr.c:
* st.c:
Wed Dec 28 16:38:29 1994 Eric Youngdale (eric@andante)
* Linux 1.1.75 released.
* buslogic.c: Spelling fix.
* scsi.c: Add HP C1790A and C2500A scanjet to blacklist.
* scsi.c: Spelling fixup.
* sd.c: Add support for sd_hardsizes (hard sector sizes).
* ultrastor.c: Use save_flags/restore_flags instead of cli/sti.
Fri Dec 23 13:36:25 1994 Eric Youngdale (eric@andante)
* Linux 1.1.74 released.
* README.st: Update from Kai Makisara.
* eata.c: New version from Dario - version 1.11.
use scsicam bios_param routine. Add support for 2011
and 2021 boards.
* hosts.c: Add support for blocking. Linked list automatically
generated when shpnt->block is set.
* scsi.c: Add sankyo & HP scanjet to blacklist. Add support for
kicking things loose when we deadlock.
* scsi.c: Recognize scanners and processors in scan_scsis.
* scsi_ioctl.h: Increase timeout to 9 seconds.
* st.c: New version from Kai - add better support for backspace.
* u14-34f.c: New version from Dario. Supports blocking.
Wed Dec 14 14:46:30 1994 Eric Youngdale (eric@andante)
* Linux 1.1.73 released.
* buslogic.c: Update from Dave Gentzel. Version 1.14.
Add module related stuff. More fault tolerant if out of
DMA memory.
* fdomain.c: New version from Rik Faith - version 5.22. Add support
for ISA-200S SCSI adapter.
* hosts.c: Spelling.
* qlogic.c: Update to version 0.38a. Add more support for PCMIA.
* scsi.c: Mask device type with 0x1f during scan_scsis.
Add support for deadlocking, err, make that getting out of
deadlock situations that are created when we allow the user
to limit requests to one host adapter at a time.
* scsi.c: Bugfix - pass pid, not SCpnt as second arg to
scsi_times_out.
* scsi.c: Restore interrupt state to previous value instead of using
cli/sti pairs.
* scsi.c: Add a bunch of module stuff (all commented out for now).
* scsi.c: Clean up scsi_dump_status.
Tue Dec 6 12:34:20 1994 Eric Youngdale (eric@andante)
* Linux 1.1.72 released.
......
......@@ -25,6 +25,7 @@ endif
SCSI_OBJS =
SCSI_SRCS =
SCSI_MODULE_OBJS =
ifdef CONFIG_SCSI
......@@ -61,9 +62,11 @@ SCSI_OBJS := $(SCSI_OBJS) aha152x.o
SCSI_SRCS := $(SCSI_SRCS) aha152x.c
endif
SCSI_SRCS := $(SCSI_SRCS) aha1542.c
ifdef CONFIG_SCSI_AHA1542
SCSI_OBJS := $(SCSI_OBJS) aha1542.o
SCSI_SRCS := $(SCSI_SRCS) aha1542.c
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1542.o
endif
ifdef CONFIG_SCSI_AHA1740
......@@ -81,14 +84,21 @@ SCSI_OBJS := $(SCSI_OBJS) buslogic.o
SCSI_SRCS := $(SCSI_SRCS) buslogic.c
endif
ifdef CONFIG_SCSI_EATA_DMA
SCSI_OBJS := $(SCSI_OBJS) eata_dma.o
SCSI_SRCS := $(SCSI_SRCS) eata_dma.c
endif
ifdef CONFIG_SCSI_U14_34F
SCSI_OBJS := $(SCSI_OBJS) u14-34f.o
SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
endif
SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
ifdef CONFIG_SCSI_DEBUG
SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_debug.o
endif
ifdef CONFIG_SCSI_FUTURE_DOMAIN
......@@ -96,9 +106,11 @@ SCSI_OBJS := $(SCSI_OBJS) fdomain.o
SCSI_SRCS := $(SCSI_SRCS) fdomain.c
endif
SCSI_SRCS := $(SCSI_SRCS) in2000.c
ifdef CONFIG_SCSI_IN2000
SCSI_OBJS := $(SCSI_OBJS) in2000.o
SCSI_SRCS := $(SCSI_SRCS) in2000.c
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) in2000.o
endif
ifdef CONFIG_SCSI_GENERIC_NCR5380
......@@ -175,6 +187,10 @@ seagate.o: seagate.c
mv scriptu.h 53c8xx_u.h
rm fake.c
modules: $(SCSI_MODULE_OBJS)
echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
(cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
dep:
$(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
......@@ -189,8 +205,6 @@ dep:
endif
modules:
#
# include a dependency file if one exists
#
......
This file contains brief information about the SCSI tape driver.
Last modified: Sat Dec 17 13:38:43 1994 by root@kai.home
Last modified: Tue Jan 10 21:32:35 1995 by root@kai.home
BASICS
......@@ -107,7 +107,8 @@ MTSETDRVBUFFER
Sets the buffering options. The bits are the new states
(enabled/disabled) of the write buffering (MT_ST_BUFFER_WRITES),
asynchronous writes (MT_ST_ASYNC_WRITES), read ahead
(MT_ST_READ_AHEAD), writing of two filemark (ST_TWO_FM), and
(MT_ST_READ_AHEAD), writing of two filemark (ST_TWO_FM),
using the SCSI spacing to EOD (MT_ST_FAST_EOM), and
debugging (MT_ST_DEBUGGING ; debugging must be compiled into the
driver).
MT_ST_WRITE_THRESHOLD
......@@ -142,6 +143,12 @@ is defined.
Immediate return from tape positioning SCSI commands can be enabled by
defining ST_NOWAIT.
The MTEOM command is by default implemented as spacing over 32767
filemarks. With this method the file number in the status is
correct. The user can request using direct spacing to EOD by setting
ST_FAST_EOM 1 (or using the MTSTOPTIONS ioctl). In this case the file
number will be invalid.
When using read ahead or buffered writes the position within the file
may not be correct after the file is closed (correct position may
require backspacing over more than one record). The correct position
......
/************************************************************
* *
* Linux EATA SCSI driver *
* *
* based on the CAM document CAM/89-004 rev. 2.0c, *
* DPT's driver kit, some internal documents and source, *
* and several other Linux scsi drivers and kernel docs. *
* *
* The driver currently: *
* -supports all ISA based EATA-DMA boards *
* -supports all EISA based EATA-DMA boards *
* -supports all PCI based EATA-DMA boards *
* -supports multiple HBAs with & without IRQ sharing *
* -supports all SCSI channels on multi channel boards *
* *
* (c)1993,94,95 Michael Neuffer *
* neuffer@goofy.zdv.uni-mainz.de *
* *
* This program is free software; you can redistribute it *
* and/or modify it under the terms of the GNU General *
* Public License as published by the Free Software *
* Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be *
* useful, but WITHOUT ANY WARRANTY; without even the *
* implied warranty of MERCHANTABILITY or FITNESS FOR A *
* PARTICULAR PURPOSE. See the GNU General Public License *
* for more details. *
* *
* You should have received a copy of the GNU General *
* Public License along with this kernel; if not, write to *
* the Free Software Foundation, Inc., 675 Mass Ave, *
* Cambridge, MA 02139, USA. *
* *
* I have to thank DPT for their excellent support. I took *
* me almost a year and a stopover at their HQ, on my first *
* trip to the USA, to get it, but since then they've been *
* very helpful and tried to give me all the infos and *
* support I need. *
* *
* Thanks also to Greg Hosler who did a lot of testing and *
* found quite a number of bugs during the devellopment. *
************************************************************
* last change: 95/01/08 *
************************************************************/
/* Look in eata_dma.h for configuration information */
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/in.h>
#include <linux/bios32.h>
#include <linux/pci.h>
#include <asm/io.h>
#include <asm/dma.h>
#include "eata_dma.h"
#include "scsi.h"
#include "sd.h"
static uint ISAbases[] =
{0x1F0, 0x170, 0x330, 0x230};
static unchar EISAbases[] =
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
static uint registered_HBAs = 0;
static struct Scsi_Host *last_HBA = NULL;
static unchar reg_IRQ[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static unchar reg_IRQL[] =
{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
static struct eata_sp status[MAXIRQ]; /* Statuspacket array */
static struct geom_emul geometry; /* Drive 1 & 2 geometry */
#if DEBUG
static ulong int_counter = 0;
static ulong queue_counter = 0;
#endif
const char *eata_info(struct Scsi_Host *host)
{
static char *information = "EATA SCSI HBA Driver\n";
return information;
}
void eata_int_handler(int irq)
{
uint i, result;
uint hba_stat, scsi_stat, eata_stat;
Scsi_Cmnd *cmd;
struct eata_ccb *cp;
struct eata_sp *sp;
uint base;
ulong flags;
uint x;
struct Scsi_Host *sh;
save_flags(flags);
cli();
for (x = 1, sh = last_HBA; x <= registered_HBAs; x++, sh = SD(sh)->next) {
if (sh->irq != irq)
continue;
if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
continue;
DBG(DEBUG, int_counter++);
sp=&SD(sh)->sp;
cp = sp->ccb;
cmd = cp->cmd;
base = (uint) cmd->host->base;
hba_stat = sp->hba_stat;
scsi_stat = (sp->scsi_stat >> 1) && 0x1f;
if (sp->EOC == FALSE) {
eata_stat = inb(base + HA_RSTATUS);
printk("eata_dma: int_handler, board: %x cmd %lx returned "
"unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx spadrirq "
"%lx, irq%d\n", base, (long)cp, eata_stat, hba_stat,
scsi_stat,(long)&status, (long)&status[irq], irq);
DBG(DBG_DELAY,DEL2(800));
restore_flags(flags);
return;
}
if (cp->status == LOCKED) {
cp->status = FREE;
eata_stat = inb(base + HA_RSTATUS);
printk("eata_dma: int_handler, freeing locked queueslot\n");
DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
restore_flags(flags);
return;
}
eata_stat = inb(base + HA_RSTATUS);
DBG(DBG_INTR, printk("IRQ %d received, base 0x%04x, pid %lx, target: %x, "
"lun: %x, ea_s: 0x%02x, hba_s: 0x%02x \n",
irq, base, cmd->pid, cmd->target, cmd->lun,
eata_stat, hba_stat));
switch (hba_stat) {
case 0x00: /* status OK */
if (scsi_stat == INTERMEDIATE_GOOD && cmd->device->type != TYPE_TAPE)
result = DID_ERROR << 16;
/* If there was a bus reset, redo operation on each target */
else if (scsi_stat == CONDITION_GOOD
&& cmd->device->type == TYPE_DISK
&& (HD(cmd)->t_state[cmd->target] == RESET))
result = DID_BUS_BUSY << 16;
else
result = DID_OK << 16;
if (scsi_stat == 0)
HD(cmd)->t_state[cmd->target] = FALSE;
HD(cmd)->t_timeout[cmd->target] = 0;
break;
case 0x01: /* Selection Timeout */
result = DID_BAD_TARGET << 16; /* These two lines are new */
break;
case 0x02: /* Command Timeout */
if (HD(cmd)->t_timeout[cmd->target] > 1)
result = DID_ERROR << 16;
else {
result = DID_TIME_OUT << 16;
HD(cmd)->t_timeout[cmd->target]++;
}
break;
case 0x03: /* SCSI Bus Reset Received */
if (cmd->device->type != TYPE_TAPE)
result = DID_BUS_BUSY << 16;
else
result = DID_ERROR << 16;
for (i = 0; i < MAXTARGET; i++)
HD(cmd)->t_state[i] = RESET;
break;
case 0x07: /* Bus Parity Error */
case 0x0c: /* Controller Ram Parity */
case 0x04: /* Initial Controller Power-up */
case 0x05: /* Unexpected Bus Phase */
case 0x06: /* Unexpected Bus Free */
case 0x08: /* SCSI Hung */
case 0x09: /* Unexpected Message Reject */
case 0x0a: /* SCSI Bus Reset Stuck */
case 0x0b: /* Auto Request-Sense Failed */
default:
result = DID_ERROR << 16;
break;
}
cmd->result = result | scsi_stat;
if (scsi_stat == CHECK_CONDITION) {
cmd->result |= (DRIVER_SENSE << 24);
}
DBG(DBG_INTR,printk("scsi_stat: 0x%02x, result: 0x%08x\n",
scsi_stat, result));
DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
cp->status = FREE; /* now we can release the slot */
restore_flags(flags);
DBG(DBG_INTR,printk("Calling scsi_done(%lx)\n",(long)cmd));
cmd->scsi_done(cmd);
DBG(DBG_INTR,printk("returned from scsi_done(%lx)\n",(long)cmd));
save_flags(flags);
cli();
}
restore_flags(flags);
return;
}
inline uint eata_send_command(ulong addr, uint base, unchar command)
{
uint loop = R_LIMIT;
while (inb(base + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0)
return(TRUE);
outb(addr & 0x000000ff, base + HA_WDMAADDR);
outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
outb(command, base + HA_WCOMMAND);
return(FALSE);
}
int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
{
uint i, x, y;
long flags;
hostdata *hd;
struct Scsi_Host *sh;
struct eata_ccb *cp;
struct scatterlist *sl;
save_flags(flags);
cli();
DBG(DEBUG,queue_counter++);
hd = HD(cmd);
sh = cmd->host;
/* check for free slot */
for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
if (y >= sh->can_queue)
y = 0;
if (hd->ccb[y].status == FREE)
break;
}
hd->last_ccb = y;
if (x == sh->can_queue) {
DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
#if DEBUG
panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n",
queue_counter, int_counter);
#else
panic("eata_dma: run out of queue slots....\n");
#endif
}
cp = &hd->ccb[y];
memset(cp, 0, sizeof(struct eata_ccb));
cp->status = USED; /* claim free slot */
DBG(DBG_QUEUE, printk("eata_queue pid %lx, target: %x, lun: %x, y %d\n",
cmd->pid, cmd->target, cmd->lun, y));
DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
cmd->scsi_done = (void *)done;
if (cmd->cmnd[0] == WRITE_6 || cmd->cmnd[0] == WRITE_10)
cp->DataOut = TRUE; /* Output mode */
else
cp->DataIn = TRUE; /* Input mode */
if (cmd->use_sg) {
cp->scatter = TRUE; /* SG mode */
cp->cp_dataDMA = htonl((long)&cp->sg_list);
cp->cp_datalen = htonl(cmd->use_sg*8);
sl=(struct scatterlist *)cmd->request_buffer;
for(i = 0; i < cmd->use_sg; i++, sl++){
cp->sg_list[i].data = htonl((ulong) sl->address);
cp->sg_list[i].len = htonl((ulong) sl->length);
}
} else {
cp->scatter = FALSE;
cp->cp_datalen = htonl(cmd->request_bufflen);
cp->cp_dataDMA = htonl((int)cmd->request_buffer);
}
cp->Auto_Req_Sen = TRUE;
cp->cp_reqDMA = htonl((ulong) cmd->sense_buffer);
cp->reqlen = sizeof(cmd->sense_buffer);
cp->cp_id = cmd->target;
cp->cp_lun = cmd->lun;
cp->cp_dispri = TRUE;
cp->cp_identify = TRUE;
memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
cp->cp_statDMA = htonl((ulong) &(hd->sp));
cp->cp_viraddr = cp;
cp->cmd = cmd;
cmd->host_scribble = (char *)&hd->ccb[y];
if(eata_send_command((ulong) cp, (uint) sh->base, EATA_CMD_DMA_SEND_CP)) {
cmd->result = DID_ERROR << 16;
printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
cmd->target, cmd->pid);
restore_flags(flags);
done(cmd);
return (0);
}
DBG(DBG_QUEUE,printk("Queued base 0x%04lx pid: %lx target: %x lun: %x slot %d irq %d\n",
(long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
restore_flags(flags);
return (0);
}
static volatile int internal_done_flag = 0;
static volatile int internal_done_errcode = 0;
static void internal_done(Scsi_Cmnd * cmd)
{
internal_done_errcode = cmd->result;
++internal_done_flag;
}
int eata_command(Scsi_Cmnd * cmd)
{
DBG(DBG_COM, printk("eata_command: calling eata_queue\n"));
eata_queue(cmd, (void *)internal_done);
while (!internal_done_flag);
internal_done_flag = 0;
return (internal_done_errcode);
}
int eata_abort(Scsi_Cmnd * cmd)
{
ulong flags;
uint loop = R_LIMIT;
save_flags(flags);
cli();
DBG(DBG_ABNORM, printk("eata_abort called pid: %lx target: %x lun: %x reason %x\n",
cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
printk("eata_dma: abort, timeout error.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == FREE) {
DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n"));
restore_flags(flags);
return (SCSI_ABORT_NOT_RUNNING);
}
if (CD(cmd)->status == USED) {
DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
restore_flags(flags);
return (SCSI_ABORT_BUSY); /* SNOOZE */
}
if (CD(cmd)->status == RESET) {
restore_flags(flags);
printk("eata_dma: abort, command reset error.\n");
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == LOCKED) {
restore_flags(flags);
DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_ABORT_NOT_RUNNING);
} else
panic("eata_dma: abort: invalid slot status\n");
}
int eata_reset(Scsi_Cmnd * cmd)
{
uint x, z, time, limit = 0;
uint loop = R_LIMIT;
ulong flags;
unchar success = FALSE;
Scsi_Cmnd *sp;
save_flags(flags);
cli();
DBG(DBG_ABNORM, printk("eata_reset called pid:%lx target: %x lun: %x reason %x\n",
cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
if (HD(cmd)->state == RESET) {
printk("eata_dma: reset, exit, already in reset.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_RESET_ERROR);
}
while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
if (--loop == 0) {
printk("eata_dma: reset, exit, timeout error.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_RESET_ERROR);
}
for (z = 0; z < MAXTARGET; z++)
HD(cmd)->t_state[z] = RESET;
for (x = 0; x < cmd->host->can_queue; x++) {
if (HD(cmd)->ccb[x].status == FREE)
continue;
if (HD(cmd)->ccb[x].status == LOCKED) {
HD(cmd)->ccb[x].status = FREE;
printk("eata_dma: reset, locked slot %d forced free.\n", x);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
continue;
}
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
printk("eata_dma: reset, slot %d in reset, pid %ld.\n", x, sp->pid);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
if (sp == NULL)
panic("eata_dma: reset, slot %d, sp==NULL.\n", x);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
if (sp == cmd)
success = TRUE;
}
/* hard reset the HBA */
inb((uint) (cmd->host->base) + HA_RSTATUS); /* This might cause trouble */
eata_send_command(0, (uint) cmd->host->base, EATA_CMD_RESET);
DBG(DBG_ABNORM, printk("eata_dma: reset, board reset done, enabling interrupts.\n"));
HD(cmd)->state = RESET;
restore_flags(flags);
time = jiffies;
while (jiffies < (time + 300) && limit++ < 10000000);
save_flags(flags);
cli();
DBG(DBG_ABNORM, printk("eata_dma: reset, interrupts disabled, loops %d.\n",
limit));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
for (x = 0; x < cmd->host->can_queue; x++) {
/* Skip slots already set free by interrupt */
if (HD(cmd)->ccb[x].status != RESET)
continue;
sp = HD(cmd)->ccb[x].cmd;
sp->result = DID_RESET << 16;
/* This mailbox is still waiting for its interrupt */
HD(cmd)->ccb[x].status = LOCKED;
printk("eata_dma, reset, slot %d locked, DID_RESET, pid %ld done.\n",
x, sp->pid);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
restore_flags(flags);
sp->scsi_done(sp);
cli();
}
HD(cmd)->state = FALSE;
restore_flags(flags);
if (success) {
DBG(DBG_ABNORM, printk("eata_dma: reset, exit, success.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_RESET_SUCCESS);
} else {
DBG(DBG_ABNORM, printk("eata_dma: reset, exit, wakeup.\n"));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_RESET_PUNT);
}
}
int check_blink_state(long base)
{
uint ret = 0;
uint loops = 10;
ulong blinkindicator = 0x42445054;
ulong state = 0x12345678;
ulong oldstate = 0;
while ((loops--) && (state != oldstate)) {
oldstate = state;
state = inl((uint) base + 1);
}
if ((state == oldstate) && (state == blinkindicator))
ret = 1;
DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n", ret));
return (ret);
}
int get_conf_PIO(struct eata_register *base, struct get_conf *buf)
{
ulong loop = R_LIMIT;
ushort *p;
if(check_region((uint)base, 9))
return (FALSE);
memset(buf, 0, sizeof(struct get_conf));
while (inb((uint) base + HA_RSTATUS) & HA_SBUSY)
if (--loop == 0)
return (FALSE);
DBG(DBG_PIO && DBG_PROBE, printk("Issuing PIO READ CONFIG to HBA at %lx\n",
(long)base));
eata_send_command(0, (uint) base, EATA_CMD_PIO_READ_CONFIG);
loop = R_LIMIT;
for (p = (ushort *) buf;
(long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
while (!(inb((uint) base + HA_RSTATUS) & HA_SDRQ))
if (--loop == 0)
return (FALSE);
loop = R_LIMIT;
*p = inw((uint) base + HA_RDATA);
}
if (!(inb((uint) base + HA_RSTATUS) & HA_SERROR)) { /* Error ? */
DBG(DBG_PIO&&DBG_PROBE, printk("\nSignature: %c%c%c%c\n",
(char)buf->sig[0], (char)buf->sig[1],
(char)buf->sig[2], (char)buf->sig[3]));
if ((buf->sig[0] == 'E') && (buf->sig[1] == 'A')
&& (buf->sig[2] == 'T') && (buf->sig[3] == 'A')) {
DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %x "
"EATA Level: %x\n", (uint) base, (uint) (buf->version)));
while (inb((uint) base + HA_RSTATUS) & HA_SDRQ)
inw((uint) base + HA_RDATA);
return (TRUE);
}
} else {
printk("eata_dma: get_conf_PIO, error during transfer for HBA at %lx",
(long)base);
}
return (FALSE);
}
void print_config(struct get_conf *gc)
{
printk("Please check values: (read config data)\n");
printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
(uint) ntohl(gc->len), gc->version,
gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
gc->DMA_support);
printk("DMAV:%d HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d MCH:%d RIDQ:%d PCI:%d EISA:%d\n",
gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR,
gc->MAX_CHAN, gc->ID_qest, gc->is_PCI, gc->is_EISA);
DBG(DPT_DEBUG, DELAY(1400));
}
int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
{
ulong size = 0;
unchar dma_channel = 0;
uint i;
struct Scsi_Host *sh;
hostdata *hd;
printk("EATA compliant HBA detected. EATA Level %x\n",
(uint) (gc->version));
DBG(DBG_REGISTER, print_config(gc));
if (!gc->DMA_support) {
printk("HBA at 0x%08lx doesn't support DMA. Sorry\n",base);
return (FALSE);
}
/* if gc->DMA_valid it must be a PM2011 and we have to register it */
dma_channel = (8 - gc->DMA_channel) & 7;
if (gc->DMA_valid) {
if (request_dma(dma_channel, "DPT_PM2011")) {
printk("Unable to allocate DMA channel %d for HBA PM2011.\n",
dma_channel);
return (FALSE);
}
}
if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
if (!request_irq(gc->IRQ, eata_int_handler, SA_INTERRUPT, "EATA-DMA")){
reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
reg_IRQL[gc->IRQ] = 1; /* IRQ is edge triggered */
/* We free it again so we can do a get_conf_dma and
* allocate the interrupt again later */
free_irq(gc->IRQ);
} else {
printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
return (0);
}
} else { /* More than one HBA on this IRQ */
if (reg_IRQL[gc->IRQ]) {
printk("Can't support more than one HBA on this IRQ,\n"
" if the IRQ is edge triggered. Sorry.\n");
return (0);
} else
reg_IRQ[gc->IRQ]++;
}
request_region(base, 9, "eata_dma");
if(gc->HAA_valid == FALSE) gc->MAX_CHAN = 0;
size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
(gc->MAX_CHAN + 1));
if(ntohs(gc->queuesiz) == 0) {
gc->queuesiz = ntohs(64);
printk("Warning: Queue size had to be corrected.\n"
"This might be a PM2012 with a defective Firmware\n");
}
if (gc->MAX_CHAN) {
printk("This is a multichannel HBA. Linux doesn't support them,\n");
printk("so we'll try to register every channel as a virtual HBA.\n");
}
for (i = 0; i <= gc->MAX_CHAN; i++) {
sh = scsi_register(tpnt, size);
hd = SD(sh);
memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)) /
(gc->MAX_CHAN + 1));
sh->base = (char *) base;
sh->irq = gc->IRQ;
sh->dma_channel = dma_channel;
sh->this_id = gc->scsi_id[3 - i];
sh->can_queue = ntohs(gc->queuesiz) / (gc->MAX_CHAN + 1);
if (gc->OCS_enabled == TRUE) {
sh->cmd_per_lun = sh->can_queue/C_P_L_DIV;
} else {
sh->cmd_per_lun = 1;
}
sh->sg_tablesize = ntohs(gc->SGsiz);
if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
sh->sg_tablesize = SG_SIZE;
if (ntohs(gc->SGsiz) == 0)
printk("Warning: SG size had to be corrected.\n"
"This might be a PM2012 with a defective Firmware\n");
}
sh->loaded_as_module = 0; /* Not yet supported */
hd->channel = i;
if (gc->is_PCI)
hd->bustype = 'P';
else if (gc->is_EISA)
hd->bustype = 'E';
else
hd->bustype = 'I';
if (gc->SECOND)
hd->primary = FALSE;
else
hd->primary = TRUE;
if (hd->bustype != 'I')
sh->unchecked_isa_dma = FALSE;
else
sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */
if((hd->primary == TRUE) && (i == 0) && HARDCODED){
geometry.drv[0].heads = HEADS0;
geometry.drv[0].sectors = SECTORS0;
geometry.drv[0].cylinder = CYLINDER0;
geometry.drv[0].id = ID0;
geometry.drv[0].trans = TRUE;
geometry.drv[1].heads = HEADS1;
geometry.drv[1].sectors = SECTORS1;
geometry.drv[1].cylinder = CYLINDER1;
geometry.drv[1].id = ID1;
geometry.drv[1].trans = TRUE;
} else {
geometry.drv[0].id=-1;
geometry.drv[1].id=-1;
}
hd->next = NULL; /* build a linked list of all HBAs */
hd->prev = last_HBA;
hd->prev->next = sh;
last_HBA = sh;
registered_HBAs++;
}
return (1);
}
/* flag: -1 scan for primary HBA
* 0 scan for secondary HBA
* buf : pointer to data structure for read config command
*/
long find_EISA(struct get_conf *buf)
{
struct eata_register *base;
int i;
#if CHECKPAL
unsigned char pal1, pal2, pal3, *p;
#endif
for (i = 0; i < MAXEISA; i++) {
if (EISAbases[i] == TRUE) { /* Still a possibility ? */
base = (void *)0x1c88 + (i * 0x1000);
#if CHECKPAL
p = (char *)base;
pal1 = *(p - 8);
pal2 = *(p - 7);
pal3 = *(p - 6);
if (((pal1 == 0x12) && (pal2 == 0x14)) ||
((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
(int)pal1, (int)pal2, (int)pal3));
#endif
if (get_conf_PIO(base, buf)) {
DBG(DBG_PROBE&&DBG_EISA,print_config(buf));
if ((buf->SECOND == FALSE) && (buf->IRQ)) {
/* We just found a primary EISA, so there is no primary
* ISA HBA and we can take it from the EISA list.
*/
ISAbases[0] = 0;
EISAbases[i] = 0;
return ((long)base);
} else if ((buf->SECOND == TRUE) && (buf->IRQ)) {
/* We've found a secondary EISA, so there is no
* secondary ISA HBA */
ISAbases[1] = 0;
/* and we can take it from the list and return it */
EISAbases[i] = 0;
return ((long)base);
} else {
EISAbases[i] = 0;
printk("No vaild IRQ. HBA removed from list\n");
}
} else
/* Nothing found here so we take it from the list */
EISAbases[i] = 0;
#if CHECKPAL
}
#endif
}
}
return (0l); /* Nothing found :-( */
}
long find_ISA(struct get_conf *buf)
{
int i, l;
long ret;
ret = (long)NULL;
for (l = 0; l < MAXISA; l++) {
if (ISAbases[l]) {
i = get_conf_PIO((struct eata_register *)ISAbases[l], buf);
if (i == TRUE) {
ret = ISAbases[l];
ISAbases[l] = 0;
return (ret);
} else
ISAbases[l] = 0;
}
}
return ((long)NULL);
}
void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
#ifndef CONFIG_PCI
printk("Kernel PCI support not enabled. Skipping.\n");
#else
unchar pci_bus, pci_device_fn;
static short pci_index = 0; /* Device index to PCI BIOS calls */
ulong base = 0;
ushort com_adr;
ushort rev_device;
uint error, i, x;
if (pcibios_present()) {
for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT,
pci_index, &pci_bus, &pci_device_fn))
break;
DBG(DBG_PROBE && DBG_PCI, printk("eata_dma: HBA at bus %d, device %d,"
" function %d, index %d\n", (int)pci_bus,
(int)((pci_device_fn & 0xf8) >> 3),
(int)(pci_device_fn & 7), pci_index));
if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn,
PCI_CLASS_DEVICE, &rev_device))) {
if (rev_device == PCI_CLASS_STORAGE_SCSI) {
if (!(error = pcibios_read_config_word(pci_bus,
pci_device_fn, PCI_COMMAND,
(ushort *) & com_adr))) {
if (!((com_adr & PCI_COMMAND_IO) &&
(com_adr & PCI_COMMAND_MASTER))) {
printk("HBA has IO or BUSMASTER mode disabled\n");
continue;
}
} else
printk("error %x while reading PCI_COMMAND\n", error);
} else
printk("DEVICECLASSID %x didn't match\n", rev_device);
} else {
printk("error %x while reading PCI_CLASS_BASE\n", error);
continue;
}
if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_0, &base))) {
/* Check if the address is vaild */
if (base & 0x01) {
base &= 0xfffffffe;
/* EISA tag there ? */
if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
continue; /* Jep, it's forced, so move on */
base += 0x10; /* Now, THIS is the real address */
if (base != 0x1f8) {
/* We didn't find it in the primary search */
if (get_conf_PIO((struct eata_register *)base, buf)) {
if (buf->FORCADR) /* If the address is forced */
continue; /* we'll find it later */
/* OK. We made it till here, so we can go now
* and register it. We only have to check and
* eventually remove it from the EISA and ISA list
*/
register_HBA(base, buf, tpnt);
if (base < 0x1000) {
for (x = 0; x < MAXISA; ++x) {
if (ISAbases[x] == base) {
ISAbases[x] = 0;
break;
}
}
} else if ((base & 0x0fff) == 0x0c88) {
x = (base >> 12) & 0x0f;
EISAbases[x] = 0;
}
continue; /*break;*/
} else if (check_blink_state(base)) {
printk("HBA is in BLINK state. Consult your HBAs "
" Manual to correct this.\n");
}
}
}
} else
printk("error %x while reading PCI_BASE_ADDRESS_0\n", error);
}
} else
printk("No BIOS32 extensions present. This release still depends on it."
" Sorry.\n");
#endif /* #ifndef CONFIG_PCI */
return;
}
int eata_detect(Scsi_Host_Template * tpnt)
{
struct Scsi_Host *HBA_ptr;
struct get_conf gc;
ulong base = 0;
int i;
geometry.drv[0].trans = geometry.drv[1].trans = 0;
printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
"developed in co-operation with DPT\n"
"(c) 1993-95 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de\n",
VER_MAJOR, VER_MINOR, VER_SUB);
DBG((DBG_PROBE && DBG_DELAY)|| DPT_DEBUG,
printk("Using lots of delays to let you read the debugging output\n"));
printk("Now scanning for PCI HBAs\n");
find_PCI(&gc, tpnt);
printk("Now scanning for EISA HBAs\n");
for (i = 0; i <= MAXEISA; i++) {
base = find_EISA(&gc);
if (base)
register_HBA(base, &gc, tpnt);
}
printk("Now scanning for ISA HBAs\n");
for (i = 0; i <= MAXISA; i++) {
base = find_ISA(&gc);
if (base)
register_HBA(base, &gc, tpnt);
}
for (i = 0; i <= MAXIRQ; i++)
if (reg_IRQ[i])
request_irq(i, eata_int_handler, SA_INTERRUPT, "EATA-DMA");
HBA_ptr = last_HBA;
for (i = 1; i < registered_HBAs; i++)
HBA_ptr = SD(HBA_ptr)->prev;
printk("\nRegistered HBAs:\n");
printk(" # Type: BaseIO: IRQ: Chan: ID: Prim: QS: SG: CPL:\n");
for (i = 1; i <= registered_HBAs; i++) {
printk("%2d %c 0x%04x %2d %d %d %d %2d %2d %2d\n",
i, SD(HBA_ptr)->bustype, (uint) HBA_ptr->base, HBA_ptr->irq,
SD(HBA_ptr)->channel, HBA_ptr->this_id, SD(HBA_ptr)->primary,
HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
HBA_ptr = SD(HBA_ptr)->next;
}
DBG(DPT_DEBUG,DELAY(1200));
return (registered_HBAs);
}
/********************************************************
* Header file for eata_dma.c Linux EATA-DMA SCSI driver *
* (c) 1993,94,95 Michael Neuffer *
*********************************************************
* last change: 94/01/08 *
********************************************************/
#ifndef _EATA_DMA_H
#define _EATA_DMA_H
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include <linux/scsicam.h>
#define VER_MAJOR 2
#define VER_MINOR 1
#define VER_SUB "0f"
/************************************************************************
* Here you can configure your drives that are using a non-standard *
* geometry. *
* To enable this set HARDCODED to 1 *
* If you have only one drive that need reconfiguration, set ID1 to -1 *
************************************************************************/
#define HARDCODED 0 /* Here are drives running in emu. mode */
#define ID0 0 /* SCSI ID of "IDE" drive mapped to C:
* If you're not sure check your config
* utility that came with your controller
*/
#define HEADS0 13 /* Number of emulated heads of this drive */
#define SECTORS0 38 /* Number of emulated sectors */
#define CYLINDER0 719 /* Number of emulated cylinders */
#define ID1 1 /* SCSI ID of "IDE" drive mapped to D: */
#define HEADS1 16 /* Number of emulated heads of this drive */
#define SECTORS1 62 /* Number of emulated sectors */
#define CYLINDER1 1024 /* Number of emulated cylinders */
/************************************************************************
* Here you can switch parts of the code on and of *
************************************************************************/
#define CHECKPAL 0 /* EISA pal checking on/off */
/************************************************************************
* Debug options. *
* Enable DEBUG and whichever options you require. *
************************************************************************/
#define DEBUG 1 /* Enable debug code. */
#define DPT_DEBUG 0 /* Bobs special */
#define DBG_DELAY 0 /* Build in delays so debug messages can be
* be read before they vanish of the top of
* the screen!
*/
#define DBG_PROBE 0 /* Debug probe routines. */
#define DBG_PCI 0 /* Trace PCI routines */
#define DBG_EISA 0 /* Trace EISA routines */
#define DBG_ISA 0 /* Trace ISA routines */
#define DBG_BLINK 0 /* Trace Blink check */
#define DBG_PIO 0 /* Trace get_config_PIO */
#define DBG_COM 0 /* Trace command call */
#define DBG_QUEUE 0 /* Trace command queueing. */
#define DBG_INTR 0 /* Trace interrupt service routine. */
#define DBG_REGISTER 0 /* */
#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort)*/
#if DEBUG
#define DBG(x, y) if ((x)) {y;}
#else
#define DBG(x, y)
#endif
#define EATA_DMA { \
NULL, NULL, \
"EATA (Extended Attachment) driver\n", \
eata_detect, \
NULL, \
eata_info, \
eata_command, \
eata_queue, \
eata_abort, \
eata_reset, \
NULL, /* Slave attach */ \
scsicam_bios_param, \
0, /* Canqueue */ \
0, /* this_id */ \
0, /* sg_tablesize */ \
0, /* cmd_per_lun */ \
0, /* present */ \
0, /* True if ISA */ \
ENABLE_CLUSTERING }
int eata_detect(Scsi_Host_Template *);
const char *eata_info(struct Scsi_Host *);
int eata_command(Scsi_Cmnd *);
int eata_queue(Scsi_Cmnd *, void *(done)(Scsi_Cmnd *));
int eata_abort(Scsi_Cmnd *);
int eata_reset(Scsi_Cmnd *);
/*********************************************
* Misc. definitions *
*********************************************/
#ifndef TRUE
# define TRUE 1
#endif
#ifndef FALSE
# define FALSE 0
#endif
#define R_LIMIT 0x20000
#define MAXISA 4
#define MAXEISA 16
#define MAXPCI 16
#define MAXIRQ 16
#define MAXTARGET 8
/* PCI Bus And Device Limitations */
#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */
#define MAX_METHOD_2 16 /* Max Devices For Method 2 */
#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */
#define SG_SIZE 64
#define C_P_L_DIV 32
#define FREE 0
#define USED 1
#define TIMEOUT 2
#define RESET 4
#define LOCKED 8
#define HD(cmd) ((hostdata *)&(cmd->host->hostdata))
#define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble))
#define SD(host) ((hostdata *)&(host->hostdata))
#define DELAY(x) { int i; i = jiffies + x; while (jiffies < i); }
#define DEL2(x) { ulong i; for (i = 0; i < 0xffff*x; i++); }
/***********************************************
* EATA Command & Register definitions *
***********************************************/
#define PCI_REG_DPTconfig 0x40
#define PCI_REG_PumpModeAddress 0x44
#define PCI_REG_PumpModeData 0x48
#define PCI_REG_ConfigParam1 0x50
#define PCI_REG_ConfigParam2 0x54
#define EATA_CMD_PIO_READ_CONFIG 0xf0
#define EATA_CMD_PIO_SET_CONFIG 0xf1
#define EATA_CMD_PIO_SEND_CP 0xf2
#define EATA_CMD_PIO_RECEIVE_SP 0xf3
#define EATA_CMD_PIO_TRUNC 0xf4
#define EATA_CMD_RESET 0xf9
#define EATA_CMD_DMA_READ_CONFIG 0xfd
#define EATA_CMD_DMA_SET_CONFIG 0xfe
#define EATA_CMD_DMA_SEND_CP 0xff
#define ECS_EMULATE_SENSE 0xd4
#define HA_WCOMMAND 0x07 /* command register offset */
#define HA_WDMAADDR 0x02 /* DMA address LSB offset */
#define HA_RAUXSTAT 0x08 /* aux status register offset*/
#define HA_RSTATUS 0x07 /* status register offset */
#define HA_RDATA 0x00 /* data register (16bit) */
#define HA_ABUSY 0x01 /* aux busy bit */
#define HA_AIRQ 0x02 /* aux IRQ pending bit */
#define HA_SERROR 0x01 /* pr. command ended in error*/
#define HA_SMORE 0x02 /* more data soon to come */
#define HA_SCORR 0x04 /* data corrected */
#define HA_SDRQ 0x08 /* data request active */
#define HA_SSC 0x10 /* seek complete */
#define HA_SFAULT 0x20 /* write fault */
#define HA_SREADY 0x40 /* drive ready */
#define HA_SBUSY 0x80 /* drive busy */
#define HA_SDRDY HA_SSC+HA_SREADY+HA_SDRQ
/**********************************************
* Message definitions *
**********************************************/
struct reg_bit { /* reading this one will clear the interrupt */
unchar error:1; /* previous command ended in an error */
unchar more:1; /* more DATA comming soon, poll BSY & DRQ (PIO) */
unchar corr:1; /* data read was successfully corrected with ECC*/
unchar drq:1; /* data request aktive */
unchar sc:1; /* seek complete */
unchar fault:1; /* write fault */
unchar ready:1; /* drive ready */
unchar busy:1; /* controller busy */
};
struct reg_abit { /* reading this won't clear the interrupt */
unchar abusy:1; /* auxiliary busy */
unchar irq:1; /* set when drive interrupt is asserted */
unchar dummy:6;
};
struct eata_register { /* EATA register set */
unchar data_reg[2]; /* R, couldn't figure this one out */
unchar cp_addr[4]; /* W, CP address register */
union {
unchar command; /* W, command code: [read|set] conf, send CP*/
struct reg_bit status; /* R, see register_bit1 */
unchar statusunchar;
} ovr;
struct reg_abit aux_stat; /* R, see register_bit2 */
};
/**********************************************
* Other definitions *
**********************************************/
struct eata_sg_list
{
ulong data;
ulong len;
};
struct get_conf { /* Read Configuration Array */
ulong len; /* Should return 0x22 */
unchar sig[4]; /* Signature MUST be "EATA" */
unchar version2:4,
version:4; /* EATA Version level */
unchar OCS_enabled:1, /* Overlap Command Support enabled */
TAR_support:1, /* SCSI Target Mode supported */
TRNXFR:1, /* Truncate Transfer Cmd not necessary */
/* Only used in PIO Mode */
MORE_support:1, /* MORE supported (only PIO Mode) */
DMA_support:1, /* DMA supported Driver uses only */
/* this mode */
DMA_valid:1, /* DRQ value in Byte 30 is valid */
ATA:1, /* ATA device connected (not supported) */
HAA_valid:1; /* Hostadapter Address is valid */
ushort cppadlen; /* Number of pad unchars send after CD data */
/* set to zero for DMA commands */
unchar scsi_id[4]; /* SCSI ID of controller 2-0 Byte 0 res. */
/* if not, zero is returned */
ulong cplen; /* CP length: number of valid cp unchars */
ulong splen; /* Number of unchars returned after */
/* Receive SP command */
ushort queuesiz; /* max number of queueable CPs */
ushort dummy;
ushort SGsiz; /* max number of SG table entries */
unchar IRQ:4, /* IRQ used this HA */
IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */
SECOND:1, /* This is a secondary controller */
DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */
unchar sync; /* device at ID 7 tru 0 is running in */
/* synchronous mode, this will disappear */
unchar DSBLE:1, /* ISA i/o addressing is disabled */
FORCADR:1, /* i/o address has been forced */
:6;
unchar MAX_ID:5, /* Max number of SCSI target IDs */
MAX_CHAN:3; /* Number of SCSI busses on HBA */
unchar MAX_LUN; /* Max number of LUNs */
unchar :5,
ID_qest:1, /* Raidnum ID is questionable */
is_PCI:1, /* HBA is PCI */
is_EISA:1; /* HBA is EISA */
unchar unused[478];
};
struct eata_ccb { /* Send Command Packet structure */
unchar SCSI_Reset:1, /* Cause a SCSI Bus reset on the cmd */
HBA_Init:1, /* Cause Controller to reinitialize */
Auto_Req_Sen:1, /* Do Auto Request Sense on errors */
scatter:1, /* Data Ptr points to a SG Packet */
Resrvd:1, /* RFU */
Interpret:1, /* Interpret the SCSI cdb of own use */
DataOut:1, /* Data Out phase with command */
DataIn:1; /* Data In phase with command */
unchar reqlen; /* Request Sense Length */
/* Valid if Auto_Req_Sen=1 */
unchar unused[3];
unchar FWNEST:1, /* send cmd to phys RAID component*/
unused2:7;
unchar Phsunit:1, /* physical unit on mirrored pair */
I_AT:1, /* inhibit address translation */
I_HBA_C:1, /* HBA Inhibit caching */
unused3:5;
unchar cp_id; /* SCSI Device ID of target */
unchar cp_lun:3,
:2,
cp_luntar:1, /* CP is for target ROUTINE */
cp_dispri:1, /* Grant disconnect privilege */
cp_identify:1; /* Always TRUE */
unchar cp_msg1; /* Message bytes 0-3 */
unchar cp_msg2;
unchar cp_msg3;
unchar cp_cdb[12]; /* Command Descriptor Block */
ulong cp_datalen; /* Data Transfer Length */
/* If scatter=1 len of sg package */
void *cp_viraddr; /* address of this ccb */
ulong cp_dataDMA; /* Data Address, if scatter=1 */
/* address of scatter packet */
ulong cp_statDMA; /* address for Status Packet */
ulong cp_reqDMA; /* Request Sense Address, used if */
/* CP command ends with error */
ulong timeout;
unchar retries;
unchar status; /* status of this queueslot */
struct eata_sg_list sg_list[SG_SIZE];
Scsi_Cmnd *cmd; /* address of cmd */
};
struct eata_sp
{
unchar hba_stat:7, /* HBA status */
EOC:1; /* True if command finished */
unchar scsi_stat; /* Target SCSI status */
unchar reserved[2];
ulong residue_len; /* Number of unchars not transferred */
struct eata_ccb *ccb; /* Address set in COMMAND PACKET */
unchar msg[12];
};
typedef struct hstd{
unchar bustype; /* bustype of HBA */
unchar channel; /* no. of scsi channel */
unchar state; /* state of HBA */
unchar t_state[MAXTARGET]; /* state of Target (RESET,..) */
uint t_timeout[MAXTARGET]; /* timeouts on target */
unchar primary; /* true if primary */
uint last_ccb; /* Last used ccb */
struct Scsi_Host *next;
struct Scsi_Host *prev;
struct eata_sp sp; /* status packet */
struct eata_ccb ccb[0]; /* ccb array begins here */
}hostdata;
/* structure for max. 2 emulated drives */
struct drive_geom_emul {
unchar trans; /* translation flag 1=transl */
unchar channel; /* SCSI channel number */
unchar HBA; /* HBA number (prim/sec) */
unchar id; /* drive id */
unchar lun; /* drive lun */
uint heads; /* number of heads */
uint sectors; /* number of sectors */
uint cylinder; /* number of cylinders */
};
struct geom_emul {
int bios_drives; /* number of emulated drives */
struct drive_geom_emul drv[2]; /* drive structures */
};
#endif /* _EATA_H */
......@@ -47,6 +47,10 @@
#include "buslogic.h"
#endif
#ifdef CONFIG_SCSI_EATA_DMA
#include "eata_dma.h"
#endif
#ifdef CONFIG_SCSI_U14_34F
#include "u14-34f.h"
#endif
......@@ -178,6 +182,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_SCSI_NCR53C7xx
NCR53c7xx,
#endif
#ifdef CONFIG_SCSI_EATA_DMA
EATA_DMA,
#endif
#ifdef CONFIG_SCSI_7000FASST
WD7000,
#endif
......@@ -199,7 +206,7 @@ struct Scsi_Host * scsi_hostlist = NULL;
struct Scsi_Device_Template * scsi_devicelist;
int max_scsi_hosts = 0;
static int next_host = 0;
int next_scsi_host = 0;
void
scsi_unregister(struct Scsi_Host * sh){
......@@ -215,7 +222,7 @@ scsi_unregister(struct Scsi_Host * sh){
while(shpnt->next != sh) shpnt = shpnt->next;
shpnt->next = shpnt->next->next;
};
next_host--;
next_scsi_host--;
scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + j);
}
......@@ -225,13 +232,14 @@ scsi_unregister(struct Scsi_Host * sh){
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
struct Scsi_Host * retval, *shpnt;
retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j);
retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
(tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
retval->host_busy = 0;
retval->block = NULL;
if(j > 0xffff) panic("Too many extra bytes requested\n");
retval->extra_bytes = j;
retval->loaded_as_module = scsi_loadable_module_flag;
retval->host_no = next_host++;
retval->host_no = next_scsi_host++;
retval->host_queue = NULL;
retval->host_wait = NULL;
retval->last_reset = 0;
......@@ -241,7 +249,7 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
retval->hostt = tpnt;
retval->next = NULL;
#ifdef DEBUG
printk("Register %x %x: %d\n", retval, retval->hostt, j);
printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
#endif
/* The next four are the default values which can be overridden
......@@ -276,9 +284,10 @@ scsi_register_device(struct Scsi_Device_Template * sdpnt)
unsigned int scsi_init()
{
static int called = 0;
int i, j, count, pcount;
int i, pcount;
Scsi_Host_Template * tpnt;
count = 0;
struct Scsi_Host * shpnt;
const char * name;
if(called) return 0;
......@@ -290,14 +299,14 @@ unsigned int scsi_init()
* "inactive" - where as 0 will indicate a time out condition.
*/
pcount = next_host;
pcount = next_scsi_host;
if ((tpnt->detect) &&
(tpnt->present =
tpnt->detect(tpnt)))
{
/* The only time this should come up is when people use
some kind of patched driver of some kind or another. */
if(pcount == next_host) {
if(pcount == next_scsi_host) {
if(tpnt->present > 1)
panic("Failure to register low-level scsi driver");
/* The low-level driver failed to register a driver. We
......@@ -306,12 +315,21 @@ unsigned int scsi_init()
};
tpnt->next = scsi_hosts;
scsi_hosts = tpnt;
for(j = 0; j < tpnt->present; j++)
printk ("scsi%d : %s\n",
count++, tpnt->name);
}
}
printk ("scsi : %d hosts.\n", count);
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
{
if(shpnt->hostt->info)
name = shpnt->hostt->info(shpnt);
else
name = shpnt->hostt->name;
printk ("scsi%d : %s\n", /* And print a little message */
shpnt->host_no, name);
}
printk ("scsi : %d hosts.\n", next_scsi_host);
{
int block_count = 0, index;
......@@ -351,7 +369,7 @@ unsigned int scsi_init()
scsi_register_device(&sg_template);
#endif
max_scsi_hosts = count;
max_scsi_hosts = next_scsi_host;
return 0;
}
......
......@@ -292,9 +292,12 @@ extern Scsi_Host_Template * scsi_hosts;
looks normal. Also, it makes it possible to use the same code for a
loadable module. */
extern void * scsi_init_malloc(unsigned int size);
extern void * scsi_init_malloc(unsigned int size, int priority);
extern void scsi_init_free(char * ptr, unsigned int size);
void scan_scsis (struct Scsi_Host * shpnt);
extern int next_scsi_host;
extern int scsi_loadable_module_flag;
unsigned int scsi_init(void);
......@@ -317,7 +320,7 @@ struct Scsi_Device_Template
int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
void (*init)(void); /* Sizes arrays based upon number of devices detected */
void (*finish)(void); /* Perform initialization after attachment */
void (*attach)(Scsi_Device *); /* Attach devices to arrays */
int (*attach)(Scsi_Device *); /* Attach devices to arrays */
void (*detach)(Scsi_Device *);
};
......@@ -328,4 +331,26 @@ extern struct Scsi_Device_Template sg_template;
int scsi_register_device(struct Scsi_Device_Template * sdpnt);
/* These are used by loadable modules */
extern int scsi_register_module(int, void *);
extern void scsi_unregister_module(int, void *);
/* The different types of modules that we can load and unload */
#define MODULE_SCSI_HA 1
#define MODULE_SCSI_CONST 2
#define MODULE_SCSI_IOCTL 3
#define MODULE_SCSI_DEV 4
/*
* This is an ugly hack. If we expect to be able to load devices at run time, we need
* to leave extra room in some of the data structures. Doing a realloc to enlarge
* the structures would be riddled with race conditions, so until a better solution
* is discovered, we use this crude approach
*/
#define SD_EXTRA_DEVS 2
#define ST_EXTRA_DEVS 2
#define SR_EXTRA_DEVS 2
#define SG_EXTRA_DEVS (SD_EXTRA_DEVS + SR_EXTRA_DEVS + ST_EXTRA_DEVS)
#endif
......@@ -23,6 +23,8 @@
#include <linux/string.h>
#include <linux/malloc.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <linux/ioport.h>
#include "../block/blk.h"
#include "scsi.h"
......@@ -219,6 +221,9 @@ static void scan_scsis_done (Scsi_Cmnd * SCpnt)
printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result);
#endif
SCpnt->request.dev = 0xfffe;
if (SCpnt->request.sem != NULL)
up(SCpnt->request.sem);
}
#ifdef NO_MULTI_LUN
......@@ -242,11 +247,12 @@ void scsi_luns_setup(char *str, int *ints) {
* devices to the disk driver.
*/
static void scan_scsis (struct Scsi_Host * shpnt)
void scan_scsis (struct Scsi_Host * shpnt)
{
int dev, lun, type;
unsigned char scsi_cmd [12];
unsigned char scsi_result [256];
unsigned char scsi_result0 [256];
unsigned char * scsi_result;
Scsi_Device * SDpnt, *SDtail;
struct Scsi_Device_Template * sdtpnt;
Scsi_Cmnd SCmd;
......@@ -256,12 +262,17 @@ static void scan_scsis (struct Scsi_Host * shpnt)
type = -1;
SCmd.next = NULL;
SCmd.prev = NULL;
SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
SDtail = scsi_devices;
if(scsi_devices) {
while(SDtail->next) SDtail = SDtail->next;
}
/* Make sure we have something that is valid for DMA purposes */
scsi_result = ((current == task[0] || !shpnt->unchecked_isa_dma)
? &scsi_result0[0] : scsi_malloc(512));
shpnt->host_queue = &SCmd; /* We need this so that
commands can time out */
for (dev = 0; dev < 8; ++dev)
......@@ -306,7 +317,21 @@ static void scan_scsis (struct Scsi_Host * shpnt)
scsi_result, 256, scan_scsis_done,
SCSI_TIMEOUT + 400, 5);
/* Wait for command to finish. Use simple wait if we are booting, else
do it right and use a mutex */
if (current == task[0]){
while (SCmd.request.dev != 0xfffe);
} else {
if (SCmd.request.dev != 0xfffe){
struct semaphore sem = MUTEX_LOCKED;
SCmd.request.sem = &sem;
down(&sem);
/* Hmm.. Have to ask about this one */
while (SCmd.request.dev != 0xfffe) schedule();
}
}
#if defined(DEBUG) || defined(DEBUG_INIT)
printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
printk("scsi: return code %08x\n", SCmd.result);
......@@ -349,7 +374,17 @@ static void scan_scsis (struct Scsi_Host * shpnt)
scsi_result, 256, scan_scsis_done,
SCSI_TIMEOUT, 3);
if (current == task[0]){
while (SCmd.request.dev != 0xfffe);
} else {
if (SCmd.request.dev != 0xfffe){
struct semaphore sem = MUTEX_LOCKED;
SCmd.request.sem = &sem;
down(&sem);
/* Hmm.. Have to ask about this one */
while (SCmd.request.dev != 0xfffe) schedule();
}
}
the_result = SCmd.result;
......@@ -498,8 +533,18 @@ static void scan_scsis (struct Scsi_Host * shpnt)
scsi_result, 0x2a, scan_scsis_done,
SCSI_TIMEOUT, 3);
if (current == task[0]){
while (SCmd.request.dev != 0xfffe);
};
} else {
if (SCmd.request.dev != 0xfffe){
struct semaphore sem = MUTEX_LOCKED;
SCmd.request.sem = &sem;
down(&sem);
/* Hmm.. Have to ask about this one */
while (SCmd.request.dev != 0xfffe) schedule();
}
}
}
/* Add this device to the linked list at the end */
if(SDtail)
SDtail->next = SDpnt;
......@@ -507,7 +552,7 @@ static void scan_scsis (struct Scsi_Host * shpnt)
scsi_devices = SDpnt;
SDtail = SDpnt;
SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device));
SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
/* Some scsi devices cannot be polled for lun != 0
due to firmware bugs */
if(blacklisted(scsi_result)) break;
......@@ -534,6 +579,10 @@ static void scan_scsis (struct Scsi_Host * shpnt)
/* Last device block does not exist. Free memory. */
scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
/* If we allocated a buffer so we could do DMA, free it now */
if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
in_scan_scsis = 0;
} /* scan_scsis ends */
......@@ -1805,18 +1854,23 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
}
static unsigned short * dma_malloc_freelist = NULL;
static unsigned char * dma_malloc_freelist = NULL;
static int scsi_need_isa_bounce_buffers;
static unsigned int dma_sectors = 0;
unsigned int dma_free_sectors = 0;
unsigned int need_isa_buffer = 0;
static unsigned char * dma_malloc_buffer = NULL;
static unsigned char ** dma_malloc_pages = NULL;
#define MALLOC_PAGEBITS 12
static int scsi_register_host(Scsi_Host_Template *);
static void scsi_unregister_host(Scsi_Host_Template *);
void *scsi_malloc(unsigned int len)
{
unsigned int nbits, mask;
unsigned long flags;
int i, j;
if((len & 0x1ff) || len > 8192)
if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
return NULL;
save_flags(flags);
......@@ -1824,16 +1878,16 @@ void *scsi_malloc(unsigned int len)
nbits = len >> 9;
mask = (1 << nbits) - 1;
for(i=0;i < (dma_sectors >> 4); i++)
for(j=0; j<17-nbits; j++){
for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
if ((dma_malloc_freelist[i] & (mask << j)) == 0){
dma_malloc_freelist[i] |= (mask << j);
restore_flags(flags);
dma_free_sectors -= nbits;
#ifdef DEBUG
printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9));
printk("SMalloc: %d %x ",len, dma_malloc_pages[i] + (j << 9));
#endif
return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9));
return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
};
};
restore_flags(flags);
......@@ -1850,14 +1904,20 @@ int scsi_free(void *obj, unsigned int len)
printk("Sfree %x %d\n",obj, len);
#endif
offset = ((unsigned long) obj) - ((unsigned long) dma_malloc_buffer);
offset = -1;
for (page = 0; page < (dma_sectors >> 3); page++)
if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
(unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
{
offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
break;
}
if (offset < 0) panic("Bad offset");
page = offset >> 13;
if (page == (dma_sectors >> 3)) panic("Bad offset");
sector = offset >> 9;
if(sector >= dma_sectors) panic ("Bad page");
sector = (offset >> 9) & 15;
sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
nbits = len >> 9;
mask = (1 << nbits) - 1;
......@@ -1882,11 +1942,11 @@ int scsi_free(void *obj, unsigned int len)
static unsigned long scsi_init_memory_start = 0;
int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
void * scsi_init_malloc(unsigned int size)
void * scsi_init_malloc(unsigned int size, int priority)
{
unsigned long retval;
if(scsi_loadable_module_flag) {
retval = (unsigned long) kmalloc(size, GFP_ATOMIC);
retval = (unsigned long) kmalloc(size, priority);
} else {
retval = scsi_init_memory_start;
scsi_init_memory_start += size;
......@@ -1898,7 +1958,7 @@ void * scsi_init_malloc(unsigned int size)
void scsi_init_free(char * ptr, unsigned int size)
{ /* FIXME - not right. We need to compare addresses to see whether this was
kmalloc'd or not */
if((unsigned long) ptr < scsi_loadable_module_flag) {
if((unsigned long) ptr > scsi_init_memory_start) {
kfree(ptr);
} else {
if(((unsigned long) ptr) + size == scsi_init_memory_start)
......@@ -1919,6 +1979,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
struct Scsi_Host * shpnt;
struct Scsi_Device_Template * sdtpnt;
Scsi_Cmnd * SCpnt;
int i;
#ifdef FOO_ON_YOU
return;
#endif
......@@ -1946,9 +2007,10 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
SDpnt->scsi_request_fn = NULL;
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
if(SDpnt->type != -1){
if(SDpnt->attached){
for(j=0;j<SDpnt->host->cmd_per_lun;j++){
SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd));
SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
SCpnt->host = SDpnt->host;
SCpnt->device = SDpnt;
SCpnt->target = SDpnt->id;
......@@ -1974,6 +2036,11 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
if (scsi_devicelist)
dma_sectors = 16; /* Base value we use */
if (memory_end-1 > ISA_DMA_THRESHOLD)
scsi_need_isa_bounce_buffers = 1;
else
scsi_need_isa_bounce_buffers = 0;
for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
host = SDpnt->host;
......@@ -1995,15 +2062,21 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
scsi_init_memory_start = (scsi_init_memory_start + 3) & 0xfffffffc;
dma_malloc_freelist = (unsigned short *)
scsi_init_malloc(dma_sectors >> 3);
dma_malloc_freelist = (unsigned char *)
scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
memset(dma_malloc_freelist, 0, dma_sectors >> 3);
dma_malloc_pages = (unsigned char **)
scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
memset(dma_malloc_pages, 0, dma_sectors >> 1);
/* Some host adapters require buffers to be word aligned */
if(scsi_init_memory_start & 1) scsi_init_memory_start++;
dma_malloc_buffer = (unsigned char *)
scsi_init_malloc(dma_sectors << 9);
for(i=0; i< dma_sectors >> 3; i++)
dma_malloc_pages[i] = (unsigned char *)
scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
/* OK, now we finish the initialization by doing spin-up, read
capacity, etc, etc */
......@@ -2059,7 +2132,6 @@ static void print_inquiry(unsigned char *data)
printk("\n");
}
#ifdef NOT_YET
/*
* This entry point should be called by a loadable module if it is trying
* add a low level scsi driver to the system.
......@@ -2368,7 +2440,6 @@ void scsi_unregister_module(int module_type, void * ptr)
}
return;
}
#endif
#ifdef DEBUG_TIMEOUT
static void
......@@ -2424,5 +2495,3 @@ scsi_dump_status(void)
}
}
#endif
......@@ -30,7 +30,7 @@
*/
#include <linux/module.h>
#include "../../tools/version.h"
#include <linux/version.h>
char kernel_version[] = UTS_RELEASE;
......
......@@ -45,8 +45,9 @@ static const char RCSid[] = "$Header:";
SC->device->type != TYPE_MOD)
struct hd_struct * sd;
int revalidate_scsidisk(int dev, int maxusage);
Scsi_Disk * rscsi_disks;
Scsi_Disk * rscsi_disks = NULL;
static int * sd_sizes;
static int * sd_blocksizes;
static int * sd_hardsizes; /* Hardware sector size */
......@@ -62,13 +63,14 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt);
static void sd_init(void);
static void sd_finish(void);
static void sd_attach(Scsi_Device *);
static int sd_attach(Scsi_Device *);
static int sd_detect(Scsi_Device *);
static void sd_detach(Scsi_Device *);
struct Scsi_Device_Template sd_template = {NULL, "disk", "sd", TYPE_DISK,
SCSI_DISK_MAJOR, 0, 0, 0, 1,
sd_detect, sd_init,
sd_finish, sd_attach, NULL};
sd_finish, sd_attach, sd_detach};
static int sd_open(struct inode * inode, struct file * filp)
{
......@@ -90,6 +92,8 @@ static int sd_open(struct inode * inode, struct file * filp)
sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
};
rscsi_disks[target].device->access_count++;
if (rscsi_disks[target].device->host->hostt->usage_count)
(*rscsi_disks[target].device->host->hostt->usage_count)++;
return 0;
}
......@@ -101,6 +105,8 @@ static void sd_release(struct inode * inode, struct file * file)
target = DEVICE_NR(MINOR(inode->i_rdev));
rscsi_disks[target].device->access_count--;
if (rscsi_disks[target].device->host->hostt->usage_count)
(*rscsi_disks[target].device->host->hostt->usage_count)--;
if(rscsi_disks[target].device->removable) {
if(!rscsi_disks[target].device->access_count)
......@@ -147,7 +153,10 @@ static void sd_geninit (void)
for (i = 0; i < sd_template.dev_max; ++i)
if(rscsi_disks[i].device)
sd[i << 4].nr_sects = rscsi_disks[i].capacity;
#if 0
/* No longer needed - we keep track of this as we attach/detach */
sd_gendisk.nr_real = sd_template.dev_max;
#endif
}
/*
......@@ -1048,22 +1057,24 @@ static void sd_init()
}
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(rscsi_disks) return;
sd_template.dev_max = sd_template.dev_noticed;
sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
rscsi_disks = (Scsi_Disk *)
scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk));
scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int));
sizeof(int), GFP_ATOMIC);
memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int));
sizeof(int), GFP_ATOMIC);
sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int));
sizeof(struct hd_struct), GFP_ATOMIC);
for(i=0;i<(sd_template.dev_max << 4);i++){
sd_blocksizes[i] = 1024;
sd_hardsizes[i] = 512;
......@@ -1071,7 +1082,8 @@ static void sd_init()
blksize_size[MAJOR_NR] = sd_blocksizes;
hardsect_size[MAJOR_NR] = sd_hardsizes;
sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(struct hd_struct));
sizeof(struct hd_struct),
GFP_ATOMIC);
sd_gendisk.max_nr = sd_template.dev_max;
......@@ -1085,28 +1097,37 @@ static void sd_finish()
{
int i;
for (i = 0; i < sd_template.dev_max; ++i)
if (rscsi_disks[i].device) i = sd_init_onedisk(i);
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
sd_gendisk.next = gendisk_head;
gendisk_head = &sd_gendisk;
for (i = 0; i < sd_template.dev_max; ++i)
if (!rscsi_disks[i].capacity &&
rscsi_disks[i].device)
{
i = sd_init_onedisk(i);
if (scsi_loadable_module_flag
&& !rscsi_disks[i].has_part_table) {
sd_sizes[i << 4] = rscsi_disks[i].capacity;
revalidate_scsidisk(i << 4, 0);
}
rscsi_disks[i].has_part_table = 1;
}
/* If our host adapter is capable of scatter-gather, then we increase
the read-ahead to 16 blocks (32 sectors). If not, we use
a two block (4 sector) read ahead. */
if(rscsi_disks[0].device->host->sg_tablesize)
if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
read_ahead[MAJOR_NR] = 120;
/* 64 sector read-ahead */
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
sd_gendisk.next = gendisk_head;
gendisk_head = &sd_gendisk;
return;
}
static int sd_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n",
......@@ -1117,16 +1138,16 @@ static int sd_detect(Scsi_Device * SDp){
}
static void sd_attach(Scsi_Device * SDp){
static int sd_attach(Scsi_Device * SDp){
Scsi_Disk * dpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return;
if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
if(sd_template.nr_dev >= sd_template.dev_max)
panic ("scsi_devices corrupt (sd)");
if(sd_template.nr_dev >= sd_template.dev_max) {
SDp->attached--;
return 1;
}
for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
if(!dpnt->device) break;
......@@ -1135,8 +1156,11 @@ static void sd_attach(Scsi_Device * SDp){
SDp->scsi_request_fn = do_sd_request;
rscsi_disks[i].device = SDp;
rscsi_disks[i].has_part_table = 0;
sd_template.nr_dev++;
};
sd_gendisk.nr_real++;
return 0;
}
#define DEVICE_BUSY rscsi_disks[target].device->busy
#define USAGE rscsi_disks[target].device->access_count
......@@ -1199,3 +1223,40 @@ static int fop_revalidate_scsidisk(dev_t dev){
return revalidate_scsidisk(dev, 0);
}
static void sd_detach(Scsi_Device * SDp)
{
Scsi_Disk * dpnt;
int i;
int max_p;
int major;
int start;
for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
if(dpnt->device == SDp) {
/* If we are disconnecting a disk driver, sync and invalidate everything */
max_p = sd_gendisk.max_p;
start = i << sd_gendisk.minor_shift;
major = MAJOR_NR << 8;
for (i=max_p - 1; i >=0 ; i--) {
sync_dev(major | start | i);
invalidate_inodes(major | start | i);
invalidate_buffers(major | start | i);
sd_gendisk.part[start+i].start_sect = 0;
sd_gendisk.part[start+i].nr_sects = 0;
sd_sizes[start+i] = 0;
};
dpnt->has_part_table = 0;
dpnt->device = NULL;
dpnt->capacity = 0;
SDp->attached--;
sd_template.dev_noticed--;
sd_template.nr_dev--;
sd_gendisk.nr_real--;
return;
}
return;
}
......@@ -26,14 +26,15 @@
#include "sg.h"
static void sg_init(void);
static void sg_attach(Scsi_Device *);
static int sg_attach(Scsi_Device *);
static int sg_detect(Scsi_Device *);
static void sg_detach(Scsi_Device *);
struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", 0xff,
SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
sg_detect, sg_init,
NULL, sg_attach, NULL};
NULL, sg_attach, sg_detach};
#ifdef SG_BIG_BUFF
static char *big_buff;
......@@ -334,9 +335,6 @@ static struct file_operations sg_fops = {
static int sg_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
++sg_template.dev_noticed;
return 1;
}
......@@ -358,33 +356,36 @@ static void sg_init()
sg_registered++;
}
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
/* If we have already been through here, return */
if(scsi_generics) return;
#ifdef DEBUG
printk("sg: Init generic device.\n");
#endif
#ifdef SG_BIG_BUFF
big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF);
big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
#endif
scsi_generics = (struct scsi_generic *)
scsi_init_malloc(sg_template.dev_noticed * sizeof(struct scsi_generic));
memset(scsi_generics, 0, sg_template.dev_noticed * sizeof(struct scsi_generic));
scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS)
* sizeof(struct scsi_generic), GFP_ATOMIC);
memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
* sizeof(struct scsi_generic));
sg_template.dev_max = sg_template.dev_noticed;
}
static void sg_attach(Scsi_Device * SDp)
static int sg_attach(Scsi_Device * SDp)
{
struct scsi_generic * gpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(sg_template.nr_dev >= sg_template.dev_max)
panic ("scsi_devices corrupt (sg)");
{
SDp->attached--;
return 1;
}
for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
if(!gpnt->device) break;
......@@ -401,4 +402,22 @@ static void sg_attach(Scsi_Device * SDp)
scsi_generics[i].pending=0;
scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
sg_template.nr_dev++;
return 0;
};
static void sg_detach(Scsi_Device * SDp)
{
struct scsi_generic * gpnt;
int i;
for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
if(gpnt->device == SDp) {
gpnt->device = NULL;
SDp->attached--;
sg_template.nr_dev--;
return;
}
return;
}
......@@ -35,13 +35,14 @@
static void sr_init(void);
static void sr_finish(void);
static void sr_attach(Scsi_Device *);
static int sr_attach(Scsi_Device *);
static int sr_detect(Scsi_Device *);
static void sr_detach(Scsi_Device *);
struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM,
SCSI_CDROM_MAJOR, 0, 0, 0, 1,
sr_detect, sr_init,
sr_finish, sr_attach, NULL};
sr_finish, sr_attach, sr_detach};
Scsi_CD * scsi_CDs;
static int * sr_sizes;
......@@ -61,6 +62,8 @@ static void sr_release(struct inode * inode, struct file * file)
sync_dev(inode->i_rdev);
if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
(*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
}
static struct file_operations sr_fops =
......@@ -413,6 +416,8 @@ static int sr_open(struct inode * inode, struct file * filp)
if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
(*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
/* If this device did not have media in the drive at boot time, then
we would have been unable to get the sector size. Check to see if
......@@ -795,8 +800,6 @@ are any multiple of 512 bytes long. */
static int sr_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n",
......@@ -806,17 +809,17 @@ static int sr_detect(Scsi_Device * SDp){
return 1;
}
static void sr_attach(Scsi_Device * SDp){
static int sr_attach(Scsi_Device * SDp){
Scsi_CD * cpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return;
if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
if (sr_template.nr_dev >= sr_template.dev_max)
panic ("scsi_devices corrupt (sr)");
{
SDp->attached--;
return 1;
}
for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
if(!cpnt->device) break;
......@@ -828,6 +831,7 @@ static void sr_attach(Scsi_Device * SDp){
sr_template.nr_dev++;
if(sr_template.nr_dev > sr_template.dev_max)
panic ("scsi_devices corrupt (sr)");
return 0;
}
......@@ -923,20 +927,20 @@ static void sr_init()
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
return;
}
sr_registered++;
}
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
sr_template.dev_max = sr_template.dev_noticed;
scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD));
if (scsi_CDs) return;
sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int));
sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
sizeof(int));
sizeof(int), GFP_ATOMIC);
for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
blksize_size[MAJOR_NR] = sr_blocksizes;
......@@ -946,26 +950,61 @@ void sr_finish()
{
int i;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blk_size[MAJOR_NR] = sr_sizes;
for (i = 0; i < sr_template.nr_dev; ++i)
{
/* If we have already seen this, then skip it. Comes up
with loadable modules. */
if (scsi_CDs[i].capacity) continue;
get_sectorsize(i);
printk("Scd sectorsize = %d bytes\n", scsi_CDs[i].sector_size);
printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
scsi_CDs[i].use = 1;
scsi_CDs[i].ten = 1;
scsi_CDs[i].remap = 1;
sr_sizes[i] = scsi_CDs[i].capacity;
}
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blk_size[MAJOR_NR] = sr_sizes;
/* If our host adapter is capable of scatter-gather, then we increase
the read-ahead to 16 blocks (32 sectors). If not, we use
a two block (4 sector) read ahead. */
if(scsi_CDs[0].device->host->sg_tablesize)
if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
return;
}
static void sr_detach(Scsi_Device * SDp)
{
Scsi_CD * cpnt;
int i, major;
major = MAJOR_NR << 8;
for(cpnt = scsi_CDs, i=0; i<sg_template.dev_max; i++, cpnt++)
if(cpnt->device == SDp) {
/*
* Since the cdrom is read-only, no need to sync the device.
* We should be kind to our buffer cache, however.
*/
invalidate_inodes(major | i);
invalidate_buffers(major | i);
/*
* Reset things back to a sane state so that one can re-load a new
* driver (perhaps the same one).
*/
cpnt->device = NULL;
cpnt->capacity = 0;
SDp->attached--;
sr_template.nr_dev--;
sr_template.dev_noticed--;
sr_sizes[i] = 0;
return;
}
return;
}
......@@ -5,13 +5,13 @@
History:
Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara.
Contribution and ideas from several people including (in alphabetical
order) Klaus Ehrenfried, Wolfgang Denk, Andreas Koppenh"ofer, J"org Weule,
and Eric Youngdale.
order) Klaus Ehrenfried, Steve Hirsch, Wolfgang Denk, Andreas Koppenh"ofer,
J"org Weule, and Eric Youngdale.
Copyright 1992, 1993, 1994 Kai Makisara
email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi
Copyright 1992, 1993, 1994, 1995 Kai Makisara
email Kai.Makisara@metla.fi
Last modified: Sun Dec 18 10:15:33 1994 by root@kai.home
Last modified: Wed Jan 11 22:02:20 1995 by root@kai.home
*/
#include <linux/fs.h>
......@@ -43,6 +43,8 @@
#define ST_TWO_FM 0
#define ST_FAST_MTEOM 0
#define ST_BUFFER_WRITES 1
#define ST_ASYNC_WRITES 1
......@@ -86,13 +88,14 @@ static int st_max_buffers = ST_MAX_BUFFERS;
static Scsi_Tape * scsi_tapes;
static void st_init(void);
static void st_attach(Scsi_Device *);
static int st_attach(Scsi_Device *);
static int st_detect(Scsi_Device *);
static void st_detach(Scsi_Device *);
struct Scsi_Device_Template st_template = {NULL, "tape", "st", TYPE_TAPE,
SCSI_TAPE_MAJOR, 0, 0, 0, 0,
st_detect, st_init,
NULL, st_attach, NULL};
NULL, st_attach, st_detach};
static int st_int_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg);
......@@ -366,7 +369,6 @@ flush_buffer(struct inode * inode, struct file * filp, int seek_next)
STp->block_size;
(STp->buffer)->buffer_bytes = 0;
(STp->buffer)->read_pointer = 0;
STp->drv_block -= backspace;
result = 0;
if (!seek_next) {
if ((STp->eof == ST_FM) && !STp->eof_hit) {
......@@ -592,6 +594,9 @@ scsi_tape_open(struct inode * inode, struct file * filp)
#endif
}
if (scsi_tapes[dev].device->host->hostt->usage_count)
(*scsi_tapes[dev].device->host->hostt->usage_count)++;
return 0;
}
......@@ -671,6 +676,9 @@ scsi_tape_close(struct inode * inode, struct file * filp)
(STp->buffer)->in_use = 0;
STp->in_use = 0;
if (scsi_tapes[dev].device->host->hostt->usage_count)
(*scsi_tapes[dev].device->host->hostt->usage_count)--;
return;
}
......@@ -1164,14 +1172,15 @@ st_set_options(struct inode * inode, long options)
STp->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0;
STp->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0;
STp->two_fm = (options & MT_ST_TWO_FM) != 0;
STp->fast_mteom = (options & MT_ST_FAST_MTEOM) != 0;
#ifdef DEBUG
debugging = (options & MT_ST_DEBUGGING) != 0;
printk(
"st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n",
dev, STp->do_buffer_writes, STp->do_async_writes,
STp->do_read_ahead);
printk(" two FMs: %d, debugging: %d\n", STp->two_fm,
debugging);
printk(" two FMs: %d, fast mteom: %d debugging: %d\n",
STp->two_fm, STp->fast_mteom, debugging);
#endif
}
else if ((options & MT_ST_OPTIONS) == MT_ST_WRITE_THRESHOLD) {
......@@ -1398,6 +1407,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
fileno = blkno = at_sm = 0;
break;
case MTEOM:
if (!STp->fast_mteom) {
/* space to the end of tape */
ioctl_result = st_int_ioctl(inode, file, MTFSF, 0x3fff);
fileno = (STp->mt_status)->mt_fileno ;
......@@ -1407,6 +1417,9 @@ st_int_ioctl(struct inode * inode,struct file * file,
That's why I inserted the previous lines. I had no luck
with detecting EOM with FSF, so we go now to EOM.
Joerg Weule */
}
else
fileno = (-1);
cmd[0] = SPACE;
cmd[1] = 3;
#ifdef DEBUG
......@@ -1566,7 +1579,7 @@ st_int_ioctl(struct inode * inode,struct file * file,
else if (cmd_in == MTSETDENSITY)
STp->density = arg;
else if (cmd_in == MTEOM) {
STp->eof = ST_EOM_OK;
STp->eof = ST_EOD;
STp->eof_hit = 0;
}
else if (cmd_in != MTSETBLK && cmd_in != MTNOP) {
......@@ -1607,6 +1620,10 @@ st_int_ioctl(struct inode * inode,struct file * file,
else
STp->drv_block = (-1);
}
else if (cmd_in == MTEOM) {
(STp->mt_status)->mt_fileno = (-1);
STp->drv_block = (-1);
}
if (STp->eof == ST_NOEOF &&
(SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK)
STp->eof = ST_EOD;
......@@ -1699,7 +1716,7 @@ st_ioctl(struct inode * inode,struct file * file,
}
if (STp->eof == ST_EOM_OK || STp->eof == ST_EOM_ERROR)
(STp->mt_status)->mt_gstat |= GMT_EOT(0xffffffff);
else if (STp->eof == ST_EOD || STp->eof == ST_EOM_OK)
else if (STp->eof == ST_EOD)
(STp->mt_status)->mt_gstat |= GMT_EOD(0xffffffff);
if (STp->density == 1)
(STp->mt_status)->mt_gstat |= GMT_D_800(0xffffffff);
......@@ -1823,16 +1840,17 @@ static struct file_operations st_fops = {
NULL /* fsync */
};
static void st_attach(Scsi_Device * SDp){
static int st_attach(Scsi_Device * SDp){
Scsi_Tape * tpnt;
int i;
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
if(SDp->type != TYPE_TAPE) return;
if(SDp->type != TYPE_TAPE) return 1;
if(st_template.nr_dev >= st_template.dev_max)
panic ("scsi_devices corrupt (st)");
{
SDp->attached--;
return 1;
}
for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
if(!tpnt->device) break;
......@@ -1840,13 +1858,17 @@ static void st_attach(Scsi_Device * SDp){
if(i >= st_template.dev_max) panic ("scsi_devices corrupt (st)");
scsi_tapes[i].device = SDp;
if (SDp->scsi_level <= 2)
scsi_tapes[i].mt_status->mt_type = MT_ISSCSI1;
else
scsi_tapes[i].mt_status->mt_type = MT_ISSCSI2;
st_template.nr_dev++;
return 0;
};
static int st_detect(Scsi_Device * SDp){
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return 0;
static int st_detect(Scsi_Device * SDp)
{
if(SDp->type != TYPE_TAPE) return 0;
printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n",
......@@ -1874,19 +1896,18 @@ static void st_init()
st_registered++;
}
/* We do not support attaching loadable devices yet. */
if(scsi_loadable_module_flag) return;
scsi_tapes = (Scsi_Tape *) scsi_init_malloc(st_template.dev_noticed *
sizeof(Scsi_Tape));
st_template.dev_max = st_template.dev_noticed;
if (scsi_tapes) return;
scsi_tapes = (Scsi_Tape *) scsi_init_malloc(
(st_template.dev_noticed + ST_EXTRA_DEVS) *
sizeof(Scsi_Tape), GFP_ATOMIC);
st_template.dev_max = st_template.dev_noticed + ST_EXTRA_DEVS;
#ifdef DEBUG
printk("st: Buffer size %d bytes, write threshold %d bytes.\n",
st_buffer_size, st_write_threshold);
#endif
for (i=0, SDp = scsi_devices; i < st_template.dev_noticed; ++i) {
for (i=0; i < st_template.dev_max; ++i) {
STp = &(scsi_tapes[i]);
STp->device = NULL;
STp->capacity = 0xfffff;
......@@ -1901,25 +1922,14 @@ static void st_init()
STp->do_async_writes = ST_ASYNC_WRITES;
STp->do_read_ahead = ST_READ_AHEAD;
STp->two_fm = ST_TWO_FM;
STp->fast_mteom = ST_FAST_MTEOM;
STp->write_threshold = st_write_threshold;
STp->drv_block = 0;
STp->moves_after_eof = 1;
STp->at_sm = 0;
STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget));
STp->mt_status = (struct mtget *) scsi_init_malloc(sizeof(struct mtget), GFP_ATOMIC);
/* Initialize status */
memset((void *) scsi_tapes[i].mt_status, 0, sizeof(struct mtget));
for (; SDp; SDp = SDp->next)
if (SDp->type == TYPE_TAPE)
break;
if (!SDp)
printk("st%d: ERROR: Not found in scsi chain.\n", i);
else {
if (SDp->scsi_level <= 2)
STp->mt_status->mt_type = MT_ISSCSI1;
else
STp->mt_status->mt_type = MT_ISSCSI2;
}
SDp = SDp->next;
}
/* Allocate the buffers */
......@@ -1927,10 +1937,15 @@ static void st_init()
if (st_nbr_buffers > st_max_buffers)
st_nbr_buffers = st_max_buffers;
st_buffers = (ST_buffer **) scsi_init_malloc(st_nbr_buffers *
sizeof(ST_buffer *));
sizeof(ST_buffer *), GFP_ATOMIC);
/* FIXME - if we are hitting this because we are loading a tape module
as a loadable driver, we should not use kmalloc - it will allocate
a 64Kb region in order to buffer about 32Kb. Try using 31 blocks
instead. */
for (i=0; i < st_nbr_buffers; i++) {
st_buffers[i] = (ST_buffer *) scsi_init_malloc(sizeof(ST_buffer) -
1 + st_buffer_size);
1 + st_buffer_size, GFP_ATOMIC | GFP_DMA);
#ifdef DEBUG
/* printk("st: Buffer address: %p\n", st_buffers[i]); */
#endif
......@@ -1939,3 +1954,19 @@ static void st_init()
}
return;
}
static void st_detach(Scsi_Device * SDp)
{
Scsi_Tape * tpnt;
int i;
for(tpnt = scsi_tapes, i=0; i<st_template.dev_max; i++, tpnt++)
if(tpnt->device == SDp) {
tpnt->device = NULL;
SDp->attached--;
st_template.nr_dev--;
st_template.dev_noticed--;
return;
}
return;
}
......@@ -38,6 +38,7 @@ typedef struct {
unsigned char do_async_writes;
unsigned char do_read_ahead;
unsigned char two_fm;
unsigned char fast_mteom;
unsigned char density;
ST_buffer * buffer;
int block_size;
......
......@@ -225,13 +225,13 @@ struct inode {
struct inode * i_hash_next, * i_hash_prev;
struct inode * i_bound_to, * i_bound_by;
struct inode * i_mount;
struct socket * i_socket;
unsigned short i_count;
unsigned short i_wcount;
unsigned short i_flags;
unsigned char i_lock;
unsigned char i_dirt;
unsigned char i_pipe;
unsigned char i_sock;
unsigned char i_seek;
unsigned char i_update;
union {
......@@ -246,6 +246,7 @@ struct inode {
struct nfs_inode_info nfs_i;
struct xiafs_inode_info xiafs_i;
struct sysv_inode_info sysv_i;
struct socket socket_i;
void * generic_ip;
} u;
};
......
/* $Id: mtio.h,v 1.13 1994/07/19 19:35:52 root Exp $
/* $Id: /usr/src/linux-1.1.64/include/linux/mtio.h at Tue Jan 10 21:02:51 1995 by root@kai.home$
*
* linux/mtio.h header file for Linux. Written by H. Bergman
*/
......@@ -220,5 +220,6 @@ struct mtpos {
#define MT_ST_READ_AHEAD 0x4
#define MT_ST_DEBUGGING 0x8
#define MT_ST_TWO_FM 0x10
#define MT_ST_FAST_MTEOM 0x20
#endif /* _LINUX_MTIO_H */
......@@ -81,8 +81,6 @@ struct socket {
struct wait_queue **wait; /* ptr to place to wait on */
struct inode *inode;
struct fasync_struct *fasync_list; /* Asynchronous wake up list */
struct socket *nextsock; /* next on the allocated socks */
struct socket *prevsock; /* precious on the allocated socks */
};
#define SOCK_INODE(S) ((S)->inode)
......
......@@ -72,6 +72,10 @@
#define PCI_CLASS_REVISION 0x08 /* High 24 bits are class, low 8
revision */
#define PCI_REVISION_ID 0x08 /* Revision ID */
#define PCI_CLASS_PROG 0x09 /* Reg. Level Programming Interface */
#define PCI_CLASS_DEVICE 0x0a /* Device class */
#define PCI_CACHE_LINE_SIZE 0x0c /* 8 bits */
#define PCI_LATENCY_TIMER 0x0d /* 8 bits */
#define PCI_HEADER_TYPE 0x0e /* 8 bits */
......@@ -197,6 +201,9 @@ struct pci_class_type {
#define PCI_VENDOR_ID_ADAPTEC 0x9004
#define PCI_DEVICE_ID_ADAPTEC_2940 0x7178
#define PCI_VENDOR_ID_DPT 0x1044
#define PCI_DEVICE_ID_DPT 0xa400
#define PCI_VENDOR_ID_S3 0x5333
#define PCI_DEVICE_ID_S3_864_1 0x88c0
#define PCI_DEVICE_ID_S3_864_2 0x88c1
......@@ -261,10 +268,11 @@ struct pci_vendor_type {
};
#define PCI_VENDOR_NUM 17
#define PCI_VENDOR_NUM 18
#define PCI_VENDOR_TYPE { \
{PCI_VENDOR_ID_NCR, "NCR"}, \
{PCI_VENDOR_ID_ADAPTEC, "Adaptec"}, \
{PCI_VENDOR_ID_DPT, "DPT"}, \
{PCI_VENDOR_ID_S3, "S3 Inc."}, \
{PCI_VENDOR_ID_OPTI, "OPTI"}, \
{PCI_VENDOR_ID_UMC, "UMC"}, \
......@@ -289,13 +297,14 @@ struct pci_device_type {
char *device_name;
};
#define PCI_DEVICE_NUM 33
#define PCI_DEVICE_NUM 34
#define PCI_DEVICE_TYPE { \
{PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, "53c810"}, \
{PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C815, "53c815"}, \
{PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C820, "53c820"}, \
{PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C825, "53c825"}, \
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_2940, "2940"}, \
{PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT, "SmartCache/Raid"}, \
{PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_864_1, "Vision 864-P"}, \
{PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_864_2, "Vision 864-P"}, \
{PCI_VENDOR_ID_S3, PCI_DEVICE_ID_S3_928, "Vision 928-P"}, \
......@@ -327,6 +336,7 @@ struct pci_device_type {
{0,0,"UNKNOWN DEVICE.PLEASE FIND OUT AND MAIL POTTER@CAO-VLSI.IBP.FR"} \
}
/* PCI BIOS */
extern int pcibios_present (void);
......
......@@ -59,16 +59,16 @@
/* ignore the rest if you have only one interface board & driver */
#if !(SBPCD_ISSUE-2) /* second interface board: */
#define CDROM_PORT 0x0370
#define CDROM_PORT 0x0320
#define SBPRO 0
#endif
#if !(SBPCD_ISSUE-3) /* third interface board: */
#define CDROM_PORT 0x0330
#define SBPRO 0
#define CDROM_PORT 0x0630
#define SBPRO 1
#endif
#if !(SBPCD_ISSUE-4) /* fourth interface board: */
#define CDROM_PORT 0x0230
#define SBPRO 1
#define CDROM_PORT 0x0634
#define SBPRO 0
#endif
/*==========================================================================*/
......@@ -545,8 +545,7 @@ Read XA Parameter:
#define CMD1_x08 0x08
#define CMD2_x08 0x08
#define CMDT_x08 0x08
#define CMD2_xD4 0xd4
#define CMD2_xDA 0xda
#define CMD2_SETSPEED 0xda
#define CMD0_PATH_CHECK 0x00
#define CMD1_PATH_CHECK 0x00
......@@ -563,6 +562,7 @@ Read XA Parameter:
#define CMDL_READ 0x02
#define CMDT_READ 0x28
#define CMD0_READ_XA 0x03
#define CMD2_READ_XA 0xd4
#define CMDL_READ_XA 0x03 /* really ?? */
#define CMD0_READ_HEAD 0x04
#define CMD0_SPINUP 0x05
......
......@@ -98,7 +98,6 @@ extern void aha274x_setup(char *str, int *ints);
extern void buslogic_setup(char *str, int *ints);
extern void scsi_luns_setup(char *str, int *ints);
extern void sound_setup(char *str, int *ints);
extern void sock_setup(char *str, int *ints);
#ifdef CONFIG_SBPCD
extern void sbpcd_setup(char *str, int *ints);
#endif CONFIG_SBPCD
......
......@@ -57,6 +57,11 @@ extern char * ftape_big_buffer;
extern void (*do_floppy)(void);
#endif
#ifdef CONFIG_SCSI
#include "../drivers/scsi/scsi.h"
#include "../drivers/scsi/hosts.h"
#endif
extern int sys_tz;
extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr);
......@@ -267,6 +272,15 @@ struct symbol_table symbol_table = { 0, 0, 0, /* for stacked module support */
X(dev_ioctl),
X(dev_queue_xmit),
X(dev_base),
#endif
#ifdef CONFIG_SCSI
/* Supports loadable scsi drivers */
X(scsi_register_module),
X(scsi_unregister_module),
X(scsi_free),
X(scsi_malloc),
X(scsi_register),
X(scsi_unregister),
#endif
/* Added to make file system as module */
X(set_writetime),
......
......@@ -94,7 +94,7 @@ void request_region(unsigned int from, unsigned int num, const char *name)
/*
* This is for compatibility with older drivers.
* It can be removed when all driver call the new function.
* It can be removed when all drivers call the new function.
*/
void snarf_region(unsigned int from, unsigned int num)
{
......
......@@ -27,6 +27,8 @@
* to be allocated when needed, and mr.
* Uphoff's max is used as max to be
* allowed to allocate.
* Linus : Argh. removed all the socket allocation
* altogether: it's in the inode now.
*
*
* This program is free software; you can redistribute it and/or
......@@ -94,45 +96,14 @@ static struct file_operations socket_file_ops = {
sock_fasync
};
/*
* The lists of sockets
*/
static struct socket *freesockets = NULL; /* List of free sockets,
pick the first */
static struct socket *usedsockets = NULL; /* Doubly-linked list of the
active sockets */
/*
* Used to wait for a socket.
*/
static struct wait_queue *socket_wait_free = NULL;
/*
* The protocol list. Each protocol is registered in here.
*/
static struct proto_ops *pops[NPROTO];
/*
* Maximum number of sockets -- override-able on command-line.
*/
static int maxnsockets = NSOCKETS;
/*
* Number of sockets allocated
*/
static int nsockets = 0;
/*
* Statistics counters of the free/used lists
* Statistics counters of the socket lists
*/
static int sockets_in_use = 0;
static int sockets_in_free = 0;
/*
* Overrides default max number of sockets if supplied on command-line.
*/
void sock_setup(char *str, int *ints)
{
maxnsockets = ints[0] ? ints[1] : NSOCKETS;
}
/*
* Support routines. Move socket addresses back and forth across the kernel/user
......@@ -219,25 +190,13 @@ static int get_fd(struct inode *inode)
/*
* Go from an inode to its socket slot.
*
* The original socket implementation wasn't very clever, which is
* why this exists at all..
*/
struct socket *socki_lookup(struct inode *inode)
inline struct socket *socki_lookup(struct inode *inode)
{
struct socket *sock;
if ((sock = inode->i_socket) != NULL)
{
if (sock->state != SS_FREE && SOCK_INODE(sock) == inode)
return sock;
printk("socket.c: uhhuh. stale inode->i_socket pointer\n");
}
for (sock = usedsockets; sock != NULL; sock = sock->nextsock)
if (sock->state != SS_FREE && SOCK_INODE(sock) == inode)
{
printk("socket.c: uhhuh. Found socket despite no inode->i_socket pointer\n");
return(sock);
}
return(NULL);
return &inode->u.socket_i;
}
/*
......@@ -247,149 +206,51 @@ struct socket *socki_lookup(struct inode *inode)
static inline struct socket *sockfd_lookup(int fd, struct file **pfile)
{
struct file *file;
struct inode *inode;
if (fd < 0 || fd >= NR_OPEN || !(file = current->files->fd[fd]))
return(NULL);
return NULL;
inode = file->f_inode;
if (!inode || !inode->i_sock)
return NULL;
if (pfile)
*pfile = file;
return(socki_lookup(file->f_inode));
return socki_lookup(inode);
}
/*
* Allocate a socket. Wait if we are out of sockets.
* Allocate a socket.
*/
static struct socket *sock_alloc(int wait)
static struct socket *sock_alloc(void)
{
struct socket *sock;
int i;
struct inode * inode;
struct socket * sock;
while (1)
{
if (freesockets == NULL)
{
/* Lets see if we can allocate some more */
cli();
/* Alloc them from same memory page, if possible.
Nothing SHOULD prevent us from allocing one at
the time.. */
for (i = 0; i < 16 && nsockets < maxnsockets; ++i)
{
sock = (struct socket*)kmalloc(sizeof(struct socket),GFP_KERNEL);
if (sock == NULL) break; /* Ah well.. */
sock->state = SS_FREE;
sock->nextsock = freesockets;
sock->prevsock = NULL;
freesockets = sock;
++sockets_in_free;
++nsockets;
}
sti();
}
inode = get_empty_inode();
if (!inode)
return NULL;
inode->i_mode = S_IFSOCK;
inode->i_sock = 1;
inode->i_uid = current->uid;
inode->i_gid = current->gid;
cli();
sock = freesockets;
if (sock != NULL) /* Freelist, we pick
the first -- or only */
{
/*
* Move it to the `usedsockets' linked-list
* at its FRONT (thus ->prevsock = NULL)
*/
freesockets = sock->nextsock;
sock->nextsock = usedsockets;
sock->prevsock = NULL;
/* Is there something in there already ? */
if (usedsockets != NULL)
/* Yes, attach the `previous' pointer */
usedsockets->prevsock = sock;
usedsockets = sock;
--sockets_in_free;
++sockets_in_use;
sti();
/*
* Got one..
*/
sock = &inode->u.socket_i;
sock->state = SS_UNCONNECTED;
sock->flags = 0;
sock->ops = NULL;
sock->data = NULL;
sock->conn = NULL;
sock->iconn = NULL;
sock->next = NULL;
sock->wait = &inode->i_wait;
sock->inode = inode; /* "backlink": we could use pointer arithmetic instead */
sock->fasync_list = NULL;
/*
* This really shouldn't be necessary, but everything
* else depends on inodes, so we grab it.
* Sleeps are also done on the i_wait member of this
* inode. The close system call will iput this inode
* for us.
*/
if (!(SOCK_INODE(sock) = get_empty_inode()))
{
printk("NET: sock_alloc: no more inodes\n");
/*
* Roll-back the linkage
*/
cli();
/* Not the last ? */
if (sock->nextsock != NULL)
sock->nextsock->prevsock = sock->prevsock;
/* Not the first ? */
if (sock->prevsock != NULL)
sock->prevsock->nextsock = sock->nextsock;
else
/* It is the first, update the head-handle */
usedsockets = sock->nextsock;
/* Link it back to the free-list */
sock->nextsock = freesockets;
sock->prevsock = NULL; /* Not used, but .. */
freesockets = sock;
++sockets_in_free;
--sockets_in_use;
sti();
sock->state = SS_FREE;
return(NULL);
}
SOCK_INODE(sock)->i_mode = S_IFSOCK;
SOCK_INODE(sock)->i_uid = current->euid;
SOCK_INODE(sock)->i_gid = current->egid;
SOCK_INODE(sock)->i_socket = sock;
sock->wait = &SOCK_INODE(sock)->i_wait;
return(sock);
}
sti();
/*
* The rest of these are in fact vestigial from the previous
* version, which didn't have growing list of sockets.
* These may become necessary if there are 2000 (or whatever
* the hard limit is set to) sockets already in system,
* but then the system itself is quite catatonic.. IMO [mea]
*/
/*
* If its a 'now or never request' then return.
*/
if (!wait)
return(NULL);
/*
* Sleep on the socket free'ing queue.
*/
interruptible_sleep_on(&socket_wait_free);
/*
* If we have been interrupted then return.
*/
if (current->signal & ~current->blocked)
{
return(NULL);
}
}
sockets_in_use++;
return sock;
}
/*
......@@ -407,9 +268,7 @@ static inline void sock_release_peer(struct socket *peer)
static void sock_release(struct socket *sock)
{
int oldstate;
struct inode *inode;
struct socket *peersock, *nextsock;
unsigned long flags;
if ((oldstate = sock->state) != SS_UNCONNECTED)
sock->state = SS_DISCONNECTING;
......@@ -434,40 +293,8 @@ static void sock_release(struct socket *sock)
sock->ops->release(sock, peersock);
if (peersock)
sock_release_peer(peersock);
inode = SOCK_INODE(sock);
/*
* Remove this `sock' from the doubly-linked chain.
*/
save_flags(flags);
cli();
sock->state = SS_FREE; /* this really releases us */
/* Not the last ? */
if (sock->nextsock != NULL)
sock->nextsock->prevsock = sock->prevsock;
/* Not the first ? */
if (sock->prevsock != NULL)
sock->prevsock->nextsock = sock->nextsock;
else
/* It is the first, update the head-handle */
usedsockets = sock->nextsock;
/* Link it back to the free-list */
sock->nextsock = freesockets;
sock->prevsock = NULL; /* Not really used, but.. */
freesockets = sock;
--sockets_in_use; /* Bookkeeping.. */
++sockets_in_free;
restore_flags(flags);
/*
* This will wake anyone waiting for a free socket.
*/
wake_up_interruptible(&socket_wait_free);
/*
* We need to do this. If sock alloc was called we already have an inode.
*/
iput(inode);
iput(SOCK_INODE(sock));
}
/*
......@@ -802,7 +629,7 @@ static int sock_socket(int family, int type, int protocol)
* default.
*/
if (!(sock = sock_alloc(1)))
if (!(sock = sock_alloc()))
{
printk("NET: sock_socket: no more sockets\n");
return(-ENOSR); /* Was: EAGAIN, but we are out of
......@@ -975,7 +802,7 @@ static int sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrl
return(-EINVAL);
}
if (!(newsock = sock_alloc(0)))
if (!(newsock = sock_alloc()))
{
printk("NET: sock_accept: no more sockets\n");
return(-ENOSR); /* Was: EAGAIN, but we are out of system
......@@ -1547,10 +1374,7 @@ void sock_init(void)
int socket_get_info(char *buffer, char **start, off_t offset, int length)
{
int len = sprintf(buffer,
"sockets: used %d free %d alloced %d highlimit %d\n",
sockets_in_use, sockets_in_free,
nsockets, maxnsockets);
int len = sprintf(buffer, "sockets: used %d\n", sockets_in_use);
if (offset >= len)
{
*start = buffer;
......
......@@ -49,7 +49,7 @@ int unix_get_info(char *buffer, char **start, off_t offset, int length)
len += sprintf(buffer, "Num RefCount Protocol Flags Type St Path\n");
for(i = 0; i < NSOCKETS; i++)
for(i = 0; i < NSOCKETS_UNIX; i++)
{
save_flags(flags);
cli();
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment