Commit 2b2c89a1 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.23

parent 8f0ec1f9
VERSION = 1
PATCHLEVEL = 3
SUBLEVEL = 22
SUBLEVEL = 23
ARCH = i386
......
......@@ -49,6 +49,16 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
goto bad_area;
if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
goto bad_area;
if (error_code & 4) {
/*
* accessing the stack below %esp is always a bug.
* The "+ 32" is there due to some instructions (like
* pusha) doing pre-decrement on the stack and that
* doesn't show up until later..
*/
if (address + 32 < regs->esp)
goto bad_area;
}
vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
vma->vm_start = (address & PAGE_MASK);
/*
......
......@@ -46,6 +46,9 @@ NEW! - should work for for EZ-Drive disks as well (not verified)
NEW! - ide-cd.c now compiles separate from ide.c
NEW! - Bus-Master DMA support for Intel PCI Triton chipset IDE interfaces
NEW! - for details, see comments at top of triton.c
NEW! - ide-cd.c now supports door locking and auto-loading.
NEW! Also preliminary support for multisession and direct
NEW! reads of audio data.
For work in progress, see the comments in ide.c, ide-cd.c, and triton.c.
......@@ -161,6 +164,31 @@ interface (/dev/hda) and an IDE cdrom drive on the secondary interface
mkdir /cd
mount /dev/cdrom /cd -t iso9660 -o ro
If, after doing all of the above, mount doesn't work and you see
errors from the driver (with dmesg) complaining about `status=0xff',
this means that the hardware is not responding to the driver's attempts
to read it. One of the following is probably the problem:
- Your hardware is broken.
- You are using the wrong address for the device, or you have the
drive jumpered wrong. Review the configuration instructions above.
- Your IDE controller requires some nonstandard initialization sequence
before it will work properly. If this is the case, there will often
be a separate MS-DOS driver just for the controller. IDE interfaces
on sound cards usually fall into this category. Such configurations
can often be made to work by first booting MS-DOS, loading the
appropriate drivers, and then warm-booting linux (without powering
off). This can be automated using loadlin in the MS-DOS autoexec.
If you always get timeout errors, interrupts from the drive are probably
not making it to the host. Check how you have the hardware jumpered
and make sure it matches what the driver expects (see the configuration
instructions above). If you have a PCI system, also check the BIOS
setup; i've had one report of a system which was shipped with IRQ 15
disabled by the BIOS.
The kernel is able to execute binaries directly off of the cdrom,
provided it is mounted with the default block size of 1024 (as above).
......
......@@ -3,20 +3,17 @@
* linux/kernel/hd.c
*
* Copyright (C) 1991, 1992 Linus Torvalds
*/
/*
*
*
* Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
* in the early extended-partition checks and added DM partitions
*/
/*
*
* Support for DiskManager v6.0x added by Mark Lord (mlord@bnr.ca)
* with information provided by OnTrack. This now works for linux fdisk
* and LILO, as well as loadlin and bootln. Note that disks other than
* /dev/hda *must* have a "DOS" type 0x51 partition in the first slot (hda1).
*
* Added support for "missing/deleted" extended partitions - mlord@bnr.ca
*
* More flexible handling of extended partitions - aeb, 950831
*/
#include <linux/config.h>
......@@ -82,14 +79,15 @@ static void extended_partition(struct gendisk *hd, int dev)
{
struct buffer_head *bh;
struct partition *p;
unsigned long first_sector, this_sector;
unsigned long first_sector, this_sector, this_size;
int mask = (1 << hd->minor_shift) - 1;
int i;
first_sector = hd->part[MINOR(dev)].start_sect;
this_sector = first_sector;
while (1) {
if ((current_minor & mask) >= (4 + hd->max_p))
if ((current_minor & mask) >= hd->max_p)
return;
if (!(bh = bread(dev,0,1024)))
return;
......@@ -100,29 +98,56 @@ static void extended_partition(struct gendisk *hd, int dev)
bh->b_dirt = 0;
bh->b_uptodate = 0;
bh->b_req = 0;
if (*(unsigned short *) (bh->b_data+510) != 0xAA55)
goto done;
p = (struct partition *) (0x1BE + bh->b_data);
this_size = hd->part[MINOR(dev)].nr_sects;
/*
* Process the first entry, which should be the real
* data partition.
* Usually, the first entry is the real data partition,
* the 2nd entry is the next extended partition, or empty,
* and the 3rd and 4th entries are unused.
* However, DRDOS sometimes has the extended partition as
* the first entry (when the data partition is empty),
* and OS/2 seems to use all four entries.
*/
if (p->sys_ind == EXTENDED_PARTITION)
goto done; /* shouldn't happen */
if (p->sys_ind && p->nr_sects)
add_partition(hd, current_minor, this_sector+p->start_sect, p->nr_sects);
current_minor++;
p++;
/*
* First process the data partition(s)
*/
for (i=0; i<4; i++, p++) {
if (!p->nr_sects || p->sys_ind == EXTENDED_PARTITION)
continue;
if (p->start_sect + p->nr_sects > this_size)
continue;
add_partition(hd, current_minor, this_sector+p->start_sect, p->nr_sects);
current_minor++;
if ((current_minor & mask) >= hd->max_p)
goto done;
}
/*
* Process the second entry, which should be a link
* to the next logical partition. Create a minor
* for this just long enough to get the next partition
* table. The minor will be reused for the real
* Next, process the (first) extended partition, if present.
* (So far, there seems to be no reason to make
* extended_partition() recursive and allow a tree
* of extended partitions.)
* It should be a link to the next logical partition.
* Create a minor for this just long enough to get the next
* partition table. The minor will be reused for the next
* data partition.
*/
if (p->sys_ind != EXTENDED_PARTITION ||
!(hd->part[current_minor].nr_sects = p->nr_sects))
goto done; /* no more logicals in this partition */
p -= 4;
for (i=0; i<4; i++, p++)
if(p->nr_sects && p->sys_ind == EXTENDED_PARTITION)
break;
if (i == 4)
goto done; /* nothing left to do */
hd->part[current_minor].nr_sects = p->nr_sects;
hd->part[current_minor].start_sect = first_sector + p->start_sect;
this_sector = first_sector + p->start_sect;
dev = ((hd->major) << 8) | current_minor;
......@@ -211,6 +236,9 @@ static int msdos_partition(struct gendisk *hd, unsigned int dev, unsigned long f
printk(" <");
extended_partition(hd, (hd->major << 8) | minor);
printk(" >");
/* prevent someone doing mkfs or mkswap on
an extended partition */
hd->part[minor].nr_sects = 0;
}
}
/*
......
......@@ -41,21 +41,35 @@
* PLAYAUDIO12 is broken on the Aztech; work around it.
* 2.05x Aug 11, 1995 -- lots of data structure renaming/restructuring in ide.c
* (my apologies to Scott, but now ide-cd.c is independent)
* 3.00 Aug 22, 1995 -- Implement CDROMMULTISESSION ioctl (UNTESTED).
* Implement CDROMREADAUDIO ioctl (UNTESTED).
* Use input_ide_data() and output_ide_data().
* Add door locking.
* Fix usage count leak in cdrom_open, which happened
* when a read-write mount was attempted.
* Try to load the disk on open.
* Implement CDROMEJECT_SW ioctl (off by default).
* Read total cdrom capacity during open.
* Rearrange logic in cdrom_decode_status. Issue
* request sense commands for failed packet commands
* from here instead of from cdrom_queue_packet_command.
* Fix a race condition in retrieving error information.
* Suppress printing normal unit attention errors and
* some drive not ready errors.
* Implement CDROMVOLREAD ioctl.
* Implement CDROMREADMODE1/2 ioctls.
* Fix race condition in setting up interrupt handlers
* when the `serialize' option is used.
* 3.01 Sep 2, 1995 -- Fix ordering of reenabling interrupts in
* cdrom_queue_request.
* Another try at using ide_[input,output]_data.
*
* FIX ME!! A day-one bug exists when the ide.c "serialize" option is used.
* For this to always work correctly, ide_set_handler() must be called
* *just before* the final trigger is given to the drive (to cause it to go
* off and get data and then interrupt us again). Otherwise, we may get the
* interrupt before set_handler() has actually run, resulting in "unexpected_intr".
*
* This can only happen in scenarios where we handle a "final" interrupt
* for one IDE port on, say irq14, and then initiate a new request for the
* other port on, say irq15, from the irq14 interrupt handler. If we are
* running with "unmask" on, or have done sti(), then Whammo -- we're exposed.
*
* Places where this needs fixing have been identified in the code with "BUG".
* -ml August 11, 1995
*
* NOTE: I've tried to implement support for multisession CDs and
* direct audio reads in this version, but i haven't been able to fully
* test them due to a lack of the proper hardware. I'd appreciate hearing
* if the multisession stuff works; i'd also be interested in hearing
* if you get anything other than a `Parameter not supported'
* (asc=0x26, ascq=1) error when trying to do a direct audio read.
*
* ATAPI cd-rom driver. To be used with ide.c.
*
......@@ -80,6 +94,7 @@
#include <linux/hdreg.h>
#include <linux/cdrom.h>
#include <asm/irq.h>
#include <asm/io.h>
#define _IDE_CD_C /* used in blk.h */
#include "ide.h"
......@@ -98,17 +113,10 @@
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#if 1 /* "old" method */
#define OUT_WORDS(b,n) outsw (IDE_DATA_REG, (b), (n))
#define IN_WORDS(b,n) insw (IDE_DATA_REG, (b), (n))
#else /* "new" method -- should really fix each instance instead of this */
#define OUT_WORDS(b,n) output_ide_data(drive,b,(n)/2)
#define IN_WORDS(b,n) input_ide_data(drive,b,(n)/2)
#endif
/* special command codes for strategy routine. */
#define PACKET_COMMAND 4315
#define PACKET_COMMAND 4315
#define REQUEST_SENSE_COMMAND 4316
#define RESET_DRIVE_COMMAND 4317
/* Some ATAPI command opcodes (just like SCSI).
(Some other cdrom-specific codes are in cdrom.h.) */
......@@ -116,9 +124,11 @@
#define REQUEST_SENSE 0x03
#define START_STOP 0x1b
#define ALLOW_MEDIUM_REMOVAL 0x1e
#define READ_CAPACITY 0x25
#define READ_10 0x28
#define MODE_SENSE_10 0x5a
#define MODE_SELECT_10 0x55
#define READ_CD 0xbe
/* ATAPI sense keys (mostly copied from scsi.h). */
......@@ -135,25 +145,72 @@
#define MISCOMPARE 0x0e
/* We want some additional flags for cd-rom drives.
To save space in the ide_drive_t struct, use one of the fields which
doesn't make sense for cd-roms -- `bios_sect'. */
To save space in the ide_drive_t struct, use some fields which
doesn't make sense for cd-roms -- `bios_sect' and `bios_head'. */
struct ide_cd_flags {
/* Configuration flags. These describe the capabilities of the drive.
They generally do not change after initialization, unless we learn
more about the drive from stuff failing. */
struct ide_cd_config_flags {
unsigned drq_interrupt : 1; /* Device sends an interrupt when ready
for a packet command. */
unsigned no_playaudio12: 1; /* The PLAYAUDIO12 command is not supported. */
unsigned media_changed : 1; /* Driver has noticed a media change. */
unsigned toc_valid : 1; /* Saved TOC information is current. */
unsigned no_lba_toc : 1; /* Drive cannot return TOC info in LBA format. */
unsigned msf_as_bcd : 1; /* Drive uses BCD in PLAYAUDIO_MSF. */
unsigned no_doorlock : 1; /* Drive cannot lock the door. */
unsigned old_readcd : 1; /* Drive uses old READ CD opcode. */
unsigned reserved : 2;
};
#define CDROM_CONFIG_FLAGS(drive) ((struct ide_cd_config_flags *)&((drive)->bios_sect))
/* State flags. These give information about the current state of the
drive, and will change during normal operation. */
struct ide_cd_state_flags {
unsigned media_changed : 1; /* Driver has noticed a media change. */
unsigned toc_valid : 1; /* Saved TOC information is current. */
unsigned door_locked : 1; /* We think that the drive door is locked. */
unsigned eject_on_close: 1; /* Drive should eject when device is closed. */
unsigned reserved : 4;
};
#define CDROM_STATE_FLAGS(drive) ((struct ide_cd_state_flags *)&((drive)->bios_head))
#define CDROM_FLAGS(drive) ((struct ide_cd_flags *)&((drive)->bios_sect))
#define SECTOR_BUFFER_SIZE CD_FRAMESIZE
/****************************************************************************
* Routines to read and write data from/to the drive, using
* the routines input_ide_data() and output_ide_data() from ide.c.
*
* All transfer lengths should be multiples of 16-bit shorts.
*/
static inline
void cdrom_in_bytes (ide_drive_t *drive, void *buffer, uint bytecount)
{
ide_input_data (drive, buffer, bytecount / 4);
if ((bytecount & 0x03 >= 2))
{
insw (IDE_DATA_REG, buffer + (bytecount & ~0x03), 1);
}
}
static inline
void cdrom_out_bytes (ide_drive_t *drive, void *buffer, uint bytecount)
{
ide_output_data (drive, buffer, bytecount / 4);
if ((bytecount & 0x03 >= 2))
{
outsw (IDE_DATA_REG, buffer + (bytecount & ~0x03), 1);
}
}
/****************************************************************************
* Descriptions of ATAPI error codes.
......@@ -298,7 +355,7 @@ struct {
/****************************************************************************
* Generic packet command support routines.
* Generic packet command support and error handling routines.
*/
......@@ -312,7 +369,7 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
the drive, and we don't want to fill the syslog with useless errors. */
if (failed_command &&
failed_command->c[0] == SCMD_READ_SUBCHANNEL &&
(reqbuf->sense_key == 2 || reqbuf->sense_key == 6))
(reqbuf->sense_key == NOT_READY || reqbuf->sense_key == UNIT_ATTENTION))
return;
#if VERBOSE_IDE_CD_ERRORS
......@@ -380,6 +437,15 @@ void cdrom_analyze_sense_data (ide_drive_t *drive,
}
#else
/* Suppress printing unit attention and `in progress of becoming ready'
errors when we're not being verbose. */
if (reqbuf->sense_key == UNIT_ATTENTION ||
(reqbuf->sense_key == NOT_READY && (reqbuf->asc == 4 ||
reqbuf->asc == 0x3a)))
return;
printk ("%s: code: %x key: %x asc: %x ascq: %x\n",
drive->name,
reqbuf->error_code, reqbuf->sense_key, reqbuf->asc, reqbuf->ascq);
......@@ -402,12 +468,14 @@ static void restore_request (struct request *rq)
}
static void cdrom_queue_request_sense (ide_drive_t *drive)
static void cdrom_queue_request_sense (ide_drive_t *drive,
struct semaphore *sem,
struct atapi_request_sense *reqbuf)
{
struct request *rq;
struct packet_command *pc;
struct atapi_request_sense *reqbuf;
unsigned long flags;
int len;
int major = HWIF(drive)->major;
......@@ -427,16 +495,30 @@ static void cdrom_queue_request_sense (ide_drive_t *drive)
restore_flags (flags);
/* If the request didn't explicitly specify where to put the sense data,
use the statically allocated structure. */
if (reqbuf == NULL)
reqbuf = &drive->cdrom_info.sense_data;
/* Make up a new request to retrieve sense information. */
reqbuf = &drive->cdrom_info.sense_data;
pc = &HWIF(drive)->request_sense_pc;
memset (pc, 0, sizeof (*pc));
/* The request_sense structure has an odd number of (16-bit) words,
which won't work well with 32-bit transfers. However, we don't care
about the last two bytes, so just truncate the structure down
to an even length. */
len = sizeof (*reqbuf) / 4;
len *= 4;
pc->c[0] = REQUEST_SENSE;
pc->c[4] = sizeof (*reqbuf);
pc->c[4] = len;
pc->buffer = (char *)reqbuf;
pc->buflen = sizeof (*reqbuf);
pc->buflen = len;
pc->sense_data = reqbuf; /* The only reason to set this here is so
that cdrom_end_request can find the correct
buffer for dumps to the syslog. */
rq = &HWIF(drive)->request_sense_request;
rq->dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS);
......@@ -446,7 +528,7 @@ static void cdrom_queue_request_sense (ide_drive_t *drive)
rq->nr_sectors = 0;
rq->current_nr_sectors = 0;
rq->buffer = (char *)pc;
rq->sem = NULL;
rq->sem = sem;
rq->bh = NULL;
rq->bhtail = NULL;
rq->next = NULL;
......@@ -477,9 +559,8 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive)
if (rq->cmd == REQUEST_SENSE_COMMAND && uptodate)
{
struct atapi_request_sense *reqbuf;
reqbuf = &drive->cdrom_info.sense_data;
cdrom_analyze_sense_data (drive, reqbuf, NULL);
struct packet_command *pc = (struct packet_command *)rq->buffer;
cdrom_analyze_sense_data (drive, pc->sense_data, NULL);
}
ide_end_request (uptodate, HWGROUP(drive));
......@@ -490,8 +571,8 @@ static void cdrom_end_request (int uptodate, ide_drive_t *drive)
buffers. */
static void cdrom_saw_media_change (ide_drive_t *drive)
{
CDROM_FLAGS (drive)->media_changed = 1;
CDROM_FLAGS (drive)->toc_valid = 0;
CDROM_STATE_FLAGS (drive)->media_changed = 1;
CDROM_STATE_FLAGS (drive)->toc_valid = 0;
drive->cdrom_info.nsectors_buffered = 0;
}
......@@ -520,97 +601,126 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, int *stat_ret
{
cmd = rq->cmd;
/* Check for tray open */
if (sense_key == NOT_READY)
if (cmd == REQUEST_SENSE_COMMAND)
{
struct packet_command *pc;
cdrom_saw_media_change (drive);
/* We got an error trying to get sense info from the drive
(probably while trying to recover from a former error).
Just give up. */
/* Fail the request if this is a read command. */
if (cmd == READ)
{
printk ("%s : tray open\n", drive->name);
cdrom_end_request (0, drive);
}
struct packet_command *pc = (struct packet_command *)rq->buffer;
pc->stat = 1;
cdrom_end_request (1, drive);
if (ide_error (drive, "request sense failure", stat))
return 1;
}
else
else if (cmd == PACKET_COMMAND)
{
/* All other functions, except for READ. */
struct packet_command *pc = (struct packet_command *)rq->buffer;
struct semaphore *sem = NULL;
/* Check for tray open. */
if (sense_key == NOT_READY)
{
/* Otherwise, it's some other packet command.
Print an error message to the syslog.
cdrom_saw_media_change (drive);
/* Print an error message to the syslog.
Exception: don't print anything if this is a read subchannel
command. This is because workman constantly polls the drive
with this command, and we don't want to uselessly fill up
the syslog. */
pc = (struct packet_command *)rq->buffer;
if (pc->c[0] != SCMD_READ_SUBCHANNEL)
printk ("%s : tray open\n", drive->name);
/* Set the error flag and complete the request. */
pc->stat = 1;
cdrom_end_request (1, drive);
printk ("%s : tray open or drive not ready\n", drive->name);
}
}
/* Check for media change. */
else if (sense_key == UNIT_ATTENTION)
{
cdrom_saw_media_change (drive);
printk ("%s: media changed\n", drive->name);
/* Return failure for a packet command, so that
cdrom_queue_packet_command can do a request sense before
the command gets retried. */
/* Check for media change. */
else if (sense_key == UNIT_ATTENTION)
{
cdrom_saw_media_change (drive);
printk ("%s: media changed\n", drive->name);
}
if (cmd == PACKET_COMMAND)
/* Otherwise, print an error. */
else
{
struct packet_command *pc = (struct packet_command *)rq->buffer;
pc->stat = 1;
cdrom_end_request (1, drive);
ide_dump_status (drive, "packet command error", stat);
}
/* Otherwise, it's a block read. Arrange to retry it.
But be sure to give up if we've retried too many times. */
else if ((++rq->errors > ERROR_MAX))
/* Set the error flag and complete the request.
Then, if we have a CHECK CONDITION status, queue a request
sense command. We must be careful, though: we don't want
the thread in cdrom_queue_packet_command to wake up until
the request sense has completed. We do this by transferring
the semaphore from the packet command request to the
request sense request. */
if ((stat & ERR_STAT) != 0)
{
cdrom_end_request (0, drive);
sem = rq->sem;
rq->sem = NULL;
}
}
/* Don't attempt to retry if this was a packet command. */
else if (cmd == PACKET_COMMAND)
{
struct packet_command *pc = (struct packet_command *)rq->buffer;
ide_dump_status (drive, "packet command error", stat);
pc->stat = 1; /* signal error */
pc->stat = 1;
cdrom_end_request (1, drive);
}
/* No point in retrying after an illegal request or data protect error.*/
else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT)
{
ide_dump_status (drive, "command error", stat);
cdrom_end_request (0, drive);
if ((stat & ERR_STAT) != 0)
cdrom_queue_request_sense (drive, sem, pc->sense_data);
}
/* If there were other errors, go to the default handler. */
else if ((err & ~ABRT_ERR) != 0)
else
{
if (ide_error (drive, "cdrom_decode_status", stat))
return 1;
}
/* Handle errors from READ requests. */
/* Else, abort if we've racked up too many retries. */
else if ((++rq->errors > ERROR_MAX))
{
cdrom_end_request (0, drive);
}
/* Check for tray open. */
if (sense_key == NOT_READY)
{
cdrom_saw_media_change (drive);
/* If we got a CHECK_STATUS condition, and this was a READ request,
queue a request sense command to try to find out more about
what went wrong (and clear a unit attention)? For packet commands,
this is done separately in cdrom_queue_packet_command. */
if ((stat & ERR_STAT) != 0 && cmd == READ)
cdrom_queue_request_sense (drive);
/* Fail the request. */
printk ("%s : tray open\n", drive->name);
cdrom_end_request (0, drive);
}
/* Check for media change. */
else if (sense_key == UNIT_ATTENTION)
{
cdrom_saw_media_change (drive);
/* Arrange to retry the request.
But be sure to give up if we've retried too many times. */
if (++rq->errors > ERROR_MAX)
{
cdrom_end_request (0, drive);
}
}
/* No point in retrying after an illegal request or
data protect error.*/
else if (sense_key == ILLEGAL_REQUEST || sense_key == DATA_PROTECT)
{
ide_dump_status (drive, "command error", stat);
cdrom_end_request (0, drive);
}
/* If there were other errors, go to the default handler. */
else if ((err & ~ABRT_ERR) != 0)
{
if (ide_error (drive, "cdrom_decode_status", stat))
return 1;
}
/* Else, abort if we've racked up too many retries. */
else if ((++rq->errors > ERROR_MAX))
{
cdrom_end_request (0, drive);
}
/* If we got a CHECK_CONDITION status, queue a request sense
command. */
if ((stat & ERR_STAT) != 0)
cdrom_queue_request_sense (drive, NULL, NULL);
}
}
/* Retry, or handle the next request. */
......@@ -620,10 +730,14 @@ static int cdrom_decode_status (ide_drive_t *drive, int good_stat, int *stat_ret
/* Set up the device registers for transferring a packet command on DEV,
expecting to later transfer XFERLEN bytes. This should be followed
by a call to cdrom_transfer_packet_command; however, if this is a
drq_interrupt device, one must wait for an interrupt first. */
static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen)
expecting to later transfer XFERLEN bytes. HANDLER is the routine
which actually transfers the command to the drive. If this is a
drq_interrupt device, this routine will arrange for HANDLER to be
called when the interrupt from the drive arrives. Otherwise, HANDLER
will be called immediately after the drive is prepared for the transfer. */
static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen,
ide_handler_t *handler)
{
/* Wait for the controller to be idle. */
if (ide_wait_stat (drive, 0, BUSY_STAT, WAIT_READY)) return 1;
......@@ -636,19 +750,29 @@ static int cdrom_start_packet_command (ide_drive_t *drive, int xferlen)
OUT_BYTE (xferlen & 0xff, IDE_LCYL_REG);
OUT_BYTE (xferlen >> 8 , IDE_HCYL_REG);
OUT_BYTE (drive->ctl, IDE_CONTROL_REG);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt)
{
ide_set_handler (drive, handler);
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
}
else
{
OUT_BYTE (WIN_PACKETCMD, IDE_COMMAND_REG); /* packet command */
(*handler) (drive);
}
return 0;
}
/* Send a packet command to DEV described by CMD_BUF and CMD_LEN.
/* Send a packet command to DRIVE described by CMD_BUF and CMD_LEN.
The device registers must have already been prepared
by cdrom_start_packet_command. */
static int cdrom_transfer_packet_command (ide_drive_t *drive,
char *cmd_buf, int cmd_len)
{
if (CDROM_FLAGS (drive)->drq_interrupt)
if (CDROM_CONFIG_FLAGS (drive)->drq_interrupt)
{
/* Here we should have been called after receiving an interrupt
from the device. DRQ should how be set. */
......@@ -664,7 +788,7 @@ static int cdrom_transfer_packet_command (ide_drive_t *drive,
}
/* Send the command to the device. */
OUT_WORDS (cmd_buf, cmd_len/2);
cdrom_out_bytes (drive, cmd_buf, cmd_len);
return 0;
}
......@@ -714,7 +838,7 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
dest = info->sector_buffer + info->nsectors_buffered * SECTOR_SIZE;
while (sectors_to_buffer > 0)
{
IN_WORDS (dest, SECTOR_SIZE / 2);
cdrom_in_bytes (drive, dest, SECTOR_SIZE);
--sectors_to_buffer;
--sectors_to_transfer;
++info->nsectors_buffered;
......@@ -725,7 +849,7 @@ static void cdrom_buffer_sectors (ide_drive_t *drive, unsigned long sector,
while (sectors_to_transfer > 0)
{
char dum[SECTOR_SIZE];
IN_WORDS (dum, sizeof (dum) / 2);
cdrom_in_bytes (drive, dum, sizeof (dum));
--sectors_to_transfer;
}
}
......@@ -753,9 +877,9 @@ int cdrom_read_check_ireason (ide_drive_t *drive, int len, int ireason)
and quit this request. */
while (len > 0)
{
short dum = 0;
OUT_WORDS (&dum, 1);
len -= 2;
int dum = 0;
cdrom_out_bytes (drive, &dum, sizeof (dum));
len -= sizeof (dum);
}
}
......@@ -833,7 +957,7 @@ static void cdrom_read_intr (ide_drive_t *drive)
{
/* We need to throw away a sector. */
char dum[SECTOR_SIZE];
IN_WORDS (dum, sizeof (dum) / 2);
cdrom_in_bytes (drive, dum, sizeof (dum));
--rq->current_nr_sectors;
--nskip;
......@@ -869,7 +993,7 @@ static void cdrom_read_intr (ide_drive_t *drive)
/* Read this_transfer sectors into the current buffer. */
while (this_transfer > 0)
{
IN_WORDS (rq->buffer, SECTOR_SIZE / 2);
cdrom_in_bytes (drive, rq->buffer, SECTOR_SIZE);
rq->buffer += SECTOR_SIZE;
--rq->nr_sectors;
--rq->current_nr_sectors;
......@@ -882,7 +1006,7 @@ static void cdrom_read_intr (ide_drive_t *drive)
/* Done moving data!
Wait for another interrupt. */
ide_set_handler(drive, &cdrom_read_intr); /* this one is okay */
ide_set_handler (drive, &cdrom_read_intr);
}
......@@ -952,7 +1076,7 @@ static int cdrom_read_from_buffer (ide_drive_t *drive)
* However, for drq_interrupt devices, it is called from an interrupt
* when the drive is ready to accept the command.
*/
static int cdrom_start_read_continuation (ide_drive_t *drive)
static void cdrom_start_read_continuation (ide_drive_t *drive)
{
struct packet_command pc;
struct request *rq = HWGROUP(drive)->rq;
......@@ -981,7 +1105,7 @@ static int cdrom_start_read_continuation (ide_drive_t *drive)
drive->name, rq->current_nr_sectors);
cdrom_end_request (0, drive);
IDE_DO_REQUEST;
return 1;
return;
}
sector -= nskip;
......@@ -1016,23 +1140,18 @@ static int cdrom_start_read_continuation (ide_drive_t *drive)
pc.c[5] = conv.b.b0;
}
if (cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c)))
return 1;
/* Set up our interrupt handler and return. */
ide_set_handler(drive, &cdrom_read_intr); /* BUG: do this BEFORE triggering drive */
/* Set up to receive the data-ready interrupt from the drive. */
ide_set_handler (drive, &cdrom_read_intr);
return 0;
/* Send the command to the drive and return. */
(void) cdrom_transfer_packet_command (drive, pc.c, sizeof (pc.c));
}
/*
* Start a read request from the CD-ROM.
* Returns 0 if the request was started successfully,
* 1 if there was an error and we should either retry or move on to the
* next request.
*/
static int cdrom_start_read (ide_drive_t *drive, unsigned int block)
static void cdrom_start_read (ide_drive_t *drive, unsigned int block)
{
struct request *rq = HWGROUP(drive)->rq;
......@@ -1042,23 +1161,13 @@ static int cdrom_start_read (ide_drive_t *drive, unsigned int block)
/* Satisfy whatever we can of this request from our cached sector. */
if (cdrom_read_from_buffer (drive))
return 1;
return;
/* Clear the local sector buffer. */
drive->cdrom_info.nsectors_buffered = 0;
if (cdrom_start_packet_command (drive, 32768))
return 1;
if (CDROM_FLAGS (drive)->drq_interrupt)
ide_set_handler(drive, (ide_handler_t *)&cdrom_start_read_continuation); /* BUG: do this BEFORE triggering drive */
else
{
if (cdrom_start_read_continuation (drive))
return 1;
}
return 0;
/* Start sending the read request to the drive. */
cdrom_start_packet_command (drive, 32768, cdrom_start_read_continuation);
}
......@@ -1068,9 +1177,11 @@ static int cdrom_start_read (ide_drive_t *drive, unsigned int block)
* Execute all other packet commands.
*/
/* Forward declaration */
/* Forward declarations. */
static int
cdrom_request_sense (ide_drive_t *drive, struct atapi_request_sense *reqbuf);
cdrom_lockdoor (ide_drive_t *drive, int lockflag,
struct atapi_request_sense *reqbuf);
/* Interrupt routine for packet command completion. */
......@@ -1131,15 +1242,15 @@ static void cdrom_pc_intr (ide_drive_t *drive)
}
/* Transfer the data. */
OUT_WORDS (pc->buffer, thislen / 2);
cdrom_out_bytes (drive, pc->buffer, thislen);
/* If we haven't moved enough data to satisfy the drive,
add some padding. */
while (len > thislen)
{
short dum = 0;
OUT_WORDS (&dum, 1);
len -= 2;
int dum = 0;
cdrom_out_bytes (drive, &dum, sizeof (dum));
len -= sizeof (dum);
}
/* Keep count of how much data we've moved. */
......@@ -1160,15 +1271,15 @@ static void cdrom_pc_intr (ide_drive_t *drive)
}
/* Transfer the data. */
IN_WORDS (pc->buffer, thislen / 2);
cdrom_in_bytes (drive, pc->buffer, thislen);
/* If we haven't moved enough data to satisfy the drive,
add some padding. */
while (len > thislen)
{
short dum = 0;
IN_WORDS (&dum, 1);
len -= 2;
int dum = 0;
cdrom_in_bytes (drive, &dum, sizeof (dum));
len -= sizeof (dum);
}
/* Keep count of how much data we've moved. */
......@@ -1184,26 +1295,24 @@ static void cdrom_pc_intr (ide_drive_t *drive)
}
/* Now we wait for another interrupt. */
ide_set_handler(drive, &cdrom_pc_intr); /* this one is okay */
ide_set_handler (drive, &cdrom_pc_intr);
}
static int cdrom_do_pc_continuation (ide_drive_t *drive)
static void cdrom_do_pc_continuation (ide_drive_t *drive)
{
struct request *rq = HWGROUP(drive)->rq;
struct packet_command *pc = (struct packet_command *)rq->buffer;
if (cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c)))
return 1;
/* Set up our interrupt handler and return. */
ide_set_handler(drive, &cdrom_pc_intr); /* BUG: do this BEFORE triggering drive */
/* Set up a handler for the data-ready interrupt. */
ide_set_handler (drive, &cdrom_pc_intr);
return 0;
/* Send the command to the drive and return. */
cdrom_transfer_packet_command (drive, pc->c, sizeof (pc->c));
}
static int cdrom_do_packet_command (ide_drive_t *drive)
static void cdrom_do_packet_command (ide_drive_t *drive)
{
int len;
struct request *rq = HWGROUP(drive)->rq;
......@@ -1214,42 +1323,34 @@ static int cdrom_do_packet_command (ide_drive_t *drive)
pc->stat = 0;
if (cdrom_start_packet_command (drive, len))
return 1;
/* Start sending the command to the drive. */
cdrom_start_packet_command (drive, len, cdrom_do_pc_continuation);
}
if (CDROM_FLAGS (drive)->drq_interrupt)
ide_set_handler(drive, (ide_handler_t *)&cdrom_do_pc_continuation); /* BUG: do this BEFORE triggering drive */
else
{
if (cdrom_do_pc_continuation (drive))
return 1;
}
return 0;
/* Sleep for TIME jiffies.
Not to be called from an interrupt handler. */
static
void cdrom_sleep (int time)
{
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + time;
schedule ();
}
static
int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
void cdrom_queue_request (ide_drive_t *drive, struct request *req)
{
int retries = 3;
unsigned long flags;
struct request req, **p, **pfirst;
struct semaphore sem = MUTEX_LOCKED;
struct request **p, **pfirst;
int major = HWIF(drive)->major;
struct semaphore sem = MUTEX_LOCKED;
retry:
req.dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS);
req.cmd = PACKET_COMMAND;
req.errors = 0;
req.sector = 0;
req.nr_sectors = 0;
req.current_nr_sectors = 0;
req.buffer = (char *)pc;
req.sem = &sem;
req.bh = NULL;
req.bhtail = NULL;
req.next = NULL;
req->dev = MKDEV (major, (drive->select.b.unit) << PARTN_BITS);
req->sem = &sem;
req->errors = 0;
req->next = NULL;
save_flags (flags);
cli ();
......@@ -1260,42 +1361,88 @@ int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
{
p = &((*p)->next);
}
*p = &req;
*p = req;
if (p == pfirst)
blk_dev[major].request_fn ();
down (&sem);
restore_flags (flags);
}
static
int cdrom_queue_packet_command (ide_drive_t *drive, struct packet_command *pc)
{
struct atapi_request_sense my_reqbuf;
int retries = 10;
struct request req;
/* If our caller has not provided a place to stick any sense data,
use our own area. */
if (pc->sense_data == NULL)
pc->sense_data = &my_reqbuf;
pc->sense_data->sense_key = 0;
/* Start of retry loop. */
do {
req.cmd = PACKET_COMMAND;
req.sector = 0;
req.nr_sectors = 0;
req.current_nr_sectors = 0;
req.buffer = (char *)pc;
req.bh = NULL;
req.bhtail = NULL;
cdrom_queue_request (drive, &req);
if (pc->stat != 0)
{
/* The request failed. Retry if it was due to a unit attention status
(usually means media was changed). */
struct atapi_request_sense *reqbuf = pc->sense_data;
if (reqbuf->sense_key == UNIT_ATTENTION)
;
/* Also retry if the drive is in the process of loading a disk.
This time, however, wait a little between retries to give
the drive time. */
else if (reqbuf->sense_key == NOT_READY && reqbuf->asc == 4)
{
cdrom_sleep (HZ);
}
/* Otherwise, don't retry. */
else
retries = 0;
down (&sem);
--retries;
}
/* End of retry loop. */
} while (pc->stat != 0 && retries >= 0);
/* Return an error if the command failed. */
if (pc->stat != 0)
{
/* The request failed. Try to do a request sense to get more information
about the error; store the result in the cdrom_info struct
for this drive. Check to be sure that it wasn't a request sense
request that failed, though, to prevent infinite loops. */
struct atapi_request_sense *reqbuf = &drive->cdrom_info.sense_data;
if (pc->c[0] == REQUEST_SENSE || cdrom_request_sense (drive, reqbuf))
{
memset (reqbuf, 0, sizeof (*reqbuf));
reqbuf->asc = 0xff;
}
cdrom_analyze_sense_data (drive, reqbuf, pc);
return -EIO;
/* If the error was a unit attention (usually means media was changed),
retry the command. */
if (reqbuf->sense_key == UNIT_ATTENTION && retries > 0)
else
{
/* The command succeeded. If it was anything other than a request sense,
eject, or door lock command, and we think that the door is presently
unlocked, lock it again. (The door was probably unlocked via
an explicit CDROMEJECT ioctl.) */
if (CDROM_STATE_FLAGS (drive)->door_locked == 0 &&
(pc->c[0] != REQUEST_SENSE &&
pc->c[0] != ALLOW_MEDIUM_REMOVAL &&
pc->c[0] != START_STOP))
{
--retries;
goto retry;
(void) cdrom_lockdoor (drive, 1, NULL);
}
return -EIO;
return 0;
}
else
return 0;
}
......@@ -1310,6 +1457,14 @@ void ide_do_rw_cdrom (ide_drive_t *drive, unsigned long block)
if (rq -> cmd == PACKET_COMMAND || rq -> cmd == REQUEST_SENSE_COMMAND)
cdrom_do_packet_command (drive);
else if (rq -> cmd == RESET_DRIVE_COMMAND)
{
cdrom_end_request (1, drive);
if (ide_do_reset (drive))
return;
}
else if (rq -> cmd != READ)
{
printk ("ide-cd: bad cmd %d\n", rq -> cmd);
......@@ -1322,7 +1477,13 @@ void ide_do_rw_cdrom (ide_drive_t *drive, unsigned long block)
/****************************************************************************
* ioctl handling.
* Ioctl handling.
*
* Routines which queue packet commands take as a final argument a pointer
* to an atapi_request_sense struct. If execution of the command results
* in an error with a CHECK CONDITION status, this structure will be filled
* with the results of the subsequent request sense command. The pointer
* can also be NULL, in which case no sense information is returned.
*/
static inline
......@@ -1374,59 +1535,74 @@ int msf_to_lba (byte m, byte s, byte f)
}
static void
cdrom_check_status (ide_drive_t *drive)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.c[0] = TEST_UNIT_READY;
(void) cdrom_queue_packet_command (drive, &pc);
}
static int
cdrom_request_sense (ide_drive_t *drive, struct atapi_request_sense *reqbuf)
cdrom_check_status (ide_drive_t *drive,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.c[0] = REQUEST_SENSE;
pc.c[4] = sizeof (*reqbuf);
pc.buffer = (char *)reqbuf;
pc.buflen = sizeof (*reqbuf);
pc.sense_data = reqbuf;
pc.c[0] = TEST_UNIT_READY;
return cdrom_queue_packet_command (drive, &pc);
}
#if 0
/* Lock the door if LOCKFLAG is nonzero; unlock it otherwise. */
static int
cdrom_lockdoor (ide_drive_t *drive, int lockflag)
cdrom_lockdoor (ide_drive_t *drive, int lockflag,
struct atapi_request_sense *reqbuf)
{
struct atapi_request_sense my_reqbuf;
int stat;
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
if (reqbuf == NULL)
reqbuf = &my_reqbuf;
pc.c[0] = ALLOW_MEDIUM_REMOVAL;
pc.c[4] = (lockflag != 0);
return cdrom_queue_packet_command (drive, &pc);
/* If the drive cannot lock the door, just pretend. */
if (CDROM_CONFIG_FLAGS (drive)->no_doorlock)
stat = 0;
else
{
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = ALLOW_MEDIUM_REMOVAL;
pc.c[4] = (lockflag != 0);
stat = cdrom_queue_packet_command (drive, &pc);
}
if (stat == 0)
CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
else
{
/* If we got an illegal field error, the drive
probably cannot lock the door. */
if (reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x24)
{
printk ("%s: door locking not supported\n", drive->name);
CDROM_CONFIG_FLAGS (drive)->no_doorlock = 1;
stat = 0;
CDROM_STATE_FLAGS (drive)->door_locked = lockflag;
}
}
return stat;
}
#endif
/* Eject the disk if EJECTFLAG is 0.
If EJECTFLAG is 1, try to reload the disk. */
static int
cdrom_eject (ide_drive_t *drive, int ejectflag)
cdrom_eject (ide_drive_t *drive, int ejectflag,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = START_STOP;
pc.c[4] = 2 + (ejectflag != 0);
......@@ -1435,11 +1611,13 @@ cdrom_eject (ide_drive_t *drive, int ejectflag)
static int
cdrom_pause (ide_drive_t *drive, int pauseflag)
cdrom_pause (ide_drive_t *drive, int pauseflag,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = SCMD_PAUSE_RESUME;
pc.c[8] = !pauseflag;
......@@ -1448,11 +1626,13 @@ cdrom_pause (ide_drive_t *drive, int pauseflag)
static int
cdrom_startstop (ide_drive_t *drive, int startflag)
cdrom_startstop (ide_drive_t *drive, int startflag,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = START_STOP;
pc.c[1] = 1;
......@@ -1461,13 +1641,45 @@ cdrom_startstop (ide_drive_t *drive, int startflag)
}
static int
cdrom_read_capacity (ide_drive_t *drive, unsigned *capacity,
struct atapi_request_sense *reqbuf)
{
struct {
unsigned lba;
unsigned blocklen;
} capbuf;
int stat;
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = READ_CAPACITY;
pc.buffer = (char *)&capbuf;
pc.buflen = sizeof (capbuf);
stat = cdrom_queue_packet_command (drive, &pc);
if (stat == 0)
{
byte_swap_long (&capbuf.lba);
*capacity = capbuf.lba;
}
return stat;
}
static int
cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag,
char *buf, int buflen)
int format, char *buf, int buflen,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.buffer = buf;
pc.buflen = buflen;
......@@ -1475,6 +1687,7 @@ cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag,
pc.c[6] = trackno;
pc.c[7] = (buflen >> 8);
pc.c[8] = (buflen & 0xff);
pc.c[9] = (format << 6);
if (msf_flag) pc.c[1] = 2;
return cdrom_queue_packet_command (drive, &pc);
}
......@@ -1482,11 +1695,16 @@ cdrom_read_tocentry (ide_drive_t *drive, int trackno, int msf_flag,
/* Try to read the entire TOC for the disk into our internal buffer. */
static int
cdrom_read_toc (ide_drive_t *drive)
cdrom_read_toc (ide_drive_t *drive,
struct atapi_request_sense *reqbuf)
{
int msf_flag;
int stat, ntracks, i;
struct atapi_toc *toc = drive->cdrom_info.toc;
struct {
struct atapi_toc_header hdr;
struct atapi_toc_entry ent;
} ms_tmp;
if (toc == NULL)
{
......@@ -1504,18 +1722,19 @@ cdrom_read_toc (ide_drive_t *drive)
/* Check to see if the existing data is still valid.
If it is, just return. */
if (CDROM_FLAGS (drive)->toc_valid)
cdrom_check_status (drive);
if (CDROM_STATE_FLAGS (drive)->toc_valid)
(void) cdrom_check_status (drive, NULL);
if (CDROM_FLAGS (drive)->toc_valid) return 0;
if (CDROM_STATE_FLAGS (drive)->toc_valid) return 0;
/* Some drives can't return TOC data in LBA format. */
msf_flag = (CDROM_FLAGS (drive)->no_lba_toc);
msf_flag = (CDROM_CONFIG_FLAGS (drive)->no_lba_toc);
/* First read just the header, so we know how long the TOC is. */
stat = cdrom_read_tocentry (drive, 0, msf_flag, (char *)toc,
stat = cdrom_read_tocentry (drive, 0, msf_flag, 0, (char *)&toc->hdr,
sizeof (struct atapi_toc_header) +
sizeof (struct atapi_toc_entry));
sizeof (struct atapi_toc_entry),
reqbuf);
if (stat) return stat;
ntracks = toc->hdr.last_track - toc->hdr.first_track + 1;
......@@ -1523,9 +1742,10 @@ cdrom_read_toc (ide_drive_t *drive)
if (ntracks > MAX_TRACKS) ntracks = MAX_TRACKS;
/* Now read the whole schmeer. */
stat = cdrom_read_tocentry (drive, 0, msf_flag, (char *)toc,
stat = cdrom_read_tocentry (drive, 0, msf_flag, 0, (char *)&toc->hdr,
sizeof (struct atapi_toc_header) +
(ntracks+1) * sizeof (struct atapi_toc_entry));
(ntracks+1) * sizeof (struct atapi_toc_entry),
reqbuf);
if (stat) return stat;
byte_swap_word (&toc->hdr.toc_length);
for (i=0; i<=ntracks; i++)
......@@ -1539,8 +1759,32 @@ cdrom_read_toc (ide_drive_t *drive)
byte_swap_long (&toc->ent[i].lba);
}
/* Read the multisession information. */
stat = cdrom_read_tocentry (drive, 0, msf_flag, 1,
(char *)&ms_tmp, sizeof (ms_tmp),
reqbuf);
if (stat) return stat;
if (msf_flag)
{
byte *adr = (byte *)&(ms_tmp.ent.lba);
toc->last_session_lba = msf_to_lba (adr[1], adr[2], adr[3]);
}
else
{
byte_swap_long (&ms_tmp.ent.lba);
toc->last_session_lba = ms_tmp.ent.lba;
}
toc->xa_flag = (ms_tmp.hdr.first_track != ms_tmp.hdr.last_track);
/* Now try to get the total cdrom capacity. */
stat = cdrom_read_capacity (drive, &toc->capacity, reqbuf);
if (stat) toc->capacity = 0x1fffff;
HWIF(drive)->gd->sizes[drive->select.b.unit << PARTN_BITS]
= toc->capacity * SECTORS_PER_FRAME;
/* Remember that we've read this stuff. */
CDROM_FLAGS (drive)->toc_valid = 1;
CDROM_STATE_FLAGS (drive)->toc_valid = 1;
return 0;
}
......@@ -1548,11 +1792,13 @@ cdrom_read_toc (ide_drive_t *drive)
static int
cdrom_read_subchannel (ide_drive_t *drive,
char *buf, int buflen)
char *buf, int buflen,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.buffer = buf;
pc.buflen = buflen;
......@@ -1568,11 +1814,13 @@ cdrom_read_subchannel (ide_drive_t *drive,
/* modeflag: 0 = current, 1 = changeable mask, 2 = default, 3 = saved */
static int
cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag,
char *buf, int buflen)
char *buf, int buflen,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.buffer = buf;
pc.buflen = buflen;
......@@ -1585,11 +1833,13 @@ cdrom_mode_sense (ide_drive_t *drive, int pageno, int modeflag,
static int
cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen)
cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.buffer = buf;
pc.buflen = - buflen;
......@@ -1603,11 +1853,13 @@ cdrom_mode_select (ide_drive_t *drive, int pageno, char *buf, int buflen)
static int
cdrom_play_lba_range_play12 (ide_drive_t *drive, int lba_start, int lba_end)
cdrom_play_lba_range_play12 (ide_drive_t *drive, int lba_start, int lba_end,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = SCMD_PLAYAUDIO12;
*(int *)(&pc.c[2]) = lba_start;
......@@ -1620,17 +1872,19 @@ cdrom_play_lba_range_play12 (ide_drive_t *drive, int lba_start, int lba_end)
static int
cdrom_play_lba_range_msf (ide_drive_t *drive, int lba_start, int lba_end)
cdrom_play_lba_range_msf (ide_drive_t *drive, int lba_start, int lba_end,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.c[0] = SCMD_PLAYAUDIO_MSF;
lba_to_msf (lba_start, &pc.c[3], &pc.c[4], &pc.c[5]);
lba_to_msf (lba_end-1, &pc.c[6], &pc.c[7], &pc.c[8]);
if (CDROM_FLAGS (drive)->msf_as_bcd)
if (CDROM_CONFIG_FLAGS (drive)->msf_as_bcd)
{
pc.c[3] = bin2bcd (pc.c[3]);
pc.c[4] = bin2bcd (pc.c[4]);
......@@ -1647,7 +1901,8 @@ cdrom_play_lba_range_msf (ide_drive_t *drive, int lba_start, int lba_end)
/* Play audio starting at LBA LBA_START and finishing with the
LBA before LBA_END. */
static int
cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end)
cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end,
struct atapi_request_sense *reqbuf)
{
/* This is rather annoying.
My NEC-260 won't recognize group 5 commands such as PLAYAUDIO12;
......@@ -1660,27 +1915,29 @@ cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end)
great. Otherwise, if the drive reports an illegal command code,
try PLAYAUDIO_MSF using the NEC 260-style bcd parameters. */
if (CDROM_FLAGS (drive)->no_playaudio12)
return cdrom_play_lba_range_msf (drive, lba_start, lba_end);
if (CDROM_CONFIG_FLAGS (drive)->no_playaudio12)
return cdrom_play_lba_range_msf (drive, lba_start, lba_end, reqbuf);
else
{
int stat;
struct atapi_request_sense *reqbuf;
struct atapi_request_sense my_reqbuf;
if (reqbuf == NULL)
reqbuf = &my_reqbuf;
stat = cdrom_play_lba_range_play12 (drive, lba_start, lba_end);
stat = cdrom_play_lba_range_play12 (drive, lba_start, lba_end, reqbuf);
if (stat == 0) return 0;
/* It failed. Try to find out why. */
reqbuf = &drive->cdrom_info.sense_data;
if (reqbuf->sense_key == 0x05 && reqbuf->asc == 0x20)
if (reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x20)
{
/* The drive didn't recognize the command.
Retry with the MSF variant. */
printk ("%s: Drive does not support PLAYAUDIO12; "
"trying PLAYAUDIO_MSF\n", drive->name);
CDROM_FLAGS (drive)->no_playaudio12 = 1;
CDROM_FLAGS (drive)->msf_as_bcd = 1;
return cdrom_play_lba_range_msf (drive, lba_start, lba_end);
CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1;
CDROM_CONFIG_FLAGS (drive)->msf_as_bcd = 1;
return cdrom_play_lba_range_msf (drive, lba_start, lba_end, reqbuf);
}
/* Failed for some other reason. Give up. */
......@@ -1691,13 +1948,14 @@ cdrom_play_lba_range (ide_drive_t *drive, int lba_start, int lba_end)
static
int cdrom_get_toc_entry (ide_drive_t *drive, int track,
struct atapi_toc_entry **ent)
struct atapi_toc_entry **ent,
struct atapi_request_sense *reqbuf)
{
int stat, ntracks;
struct atapi_toc *toc;
/* Make sure our saved TOC is valid. */
stat = cdrom_read_toc (drive);
stat = cdrom_read_toc (drive, reqbuf);
if (stat) return stat;
toc = drive->cdrom_info.toc;
......@@ -1716,25 +1974,94 @@ int cdrom_get_toc_entry (ide_drive_t *drive, int track,
}
static int
cdrom_read_block (ide_drive_t *drive, int format, int lba,
char *buf, int buflen,
struct atapi_request_sense *reqbuf)
{
struct packet_command pc;
struct atapi_request_sense my_reqbuf;
int stat;
if (reqbuf == NULL)
reqbuf = &my_reqbuf;
memset (&pc, 0, sizeof (pc));
pc.sense_data = reqbuf;
pc.buffer = buf;
pc.buflen = buflen;
if (CDROM_CONFIG_FLAGS (drive)->old_readcd)
pc.c[0] = 0xd4;
else
pc.c[0] = READ_CD;
pc.c[1] = (format << 2);
*(int *)(&pc.c[2]) = lba;
byte_swap_long ((int *)(&pc.c[2]));
pc.c[8] = 1; /* one block */
pc.c[9] = 0x10;
stat = cdrom_queue_packet_command (drive, &pc);
/* If the drive doesn't recognize the READ CD opcode, retry the command
with an older opcode for that command. */
if (stat && reqbuf->sense_key == ILLEGAL_REQUEST && reqbuf->asc == 0x20 &&
CDROM_CONFIG_FLAGS (drive)->old_readcd == 0)
{
printk ("%s: Drive does not recognize READ_CD; trying opcode 0xd4\n",
drive->name);
CDROM_CONFIG_FLAGS (drive)->old_readcd = 1;
return cdrom_read_block (drive, format, lba, buf, buflen, reqbuf);
}
return stat;
}
int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
struct file *file, unsigned int cmd, unsigned long arg)
struct file *file, unsigned int cmd, unsigned long arg)
{
switch (cmd)
{
case CDROMEJECT:
return cdrom_eject (drive, 0);
{
int stat;
if (drive->usage > 1)
return -EBUSY;
stat = cdrom_lockdoor (drive, 0, NULL);
if (stat) return stat;
return cdrom_eject (drive, 0, NULL);
}
case CDROMEJECT_SW:
{
CDROM_STATE_FLAGS (drive)->eject_on_close = arg;
return 0;
}
case CDROMPAUSE:
return cdrom_pause (drive, 1);
return cdrom_pause (drive, 1, NULL);
case CDROMRESUME:
return cdrom_pause (drive, 0);
return cdrom_pause (drive, 0, NULL);
case CDROMSTART:
return cdrom_startstop (drive, 1);
return cdrom_startstop (drive, 1, NULL);
case CDROMSTOP:
return cdrom_startstop (drive, 0);
{
int stat;
stat = cdrom_startstop (drive, 0, NULL);
if (stat) return stat;
/* pit says the Dolphin needs this. */
return cdrom_eject (drive, 1, NULL);
}
case CDROMPLAYMSF:
{
......@@ -1753,7 +2080,7 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
if (lba_end <= lba_start) return -EINVAL;
return cdrom_play_lba_range (drive, lba_start, lba_end);
return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
}
/* Like just about every other Linux cdrom driver, we ignore the
......@@ -1769,9 +2096,9 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
memcpy_fromfs (&ti, (void *) arg, sizeof(ti));
stat = cdrom_get_toc_entry (drive, ti.cdti_trk0, &first_toc);
stat = cdrom_get_toc_entry (drive, ti.cdti_trk0, &first_toc, NULL);
if (stat) return stat;
stat = cdrom_get_toc_entry (drive, ti.cdti_trk1, &last_toc);
stat = cdrom_get_toc_entry (drive, ti.cdti_trk1, &last_toc, NULL);
if (stat) return stat;
if (ti.cdti_trk1 != CDROM_LEADOUT) ++last_toc;
......@@ -1780,7 +2107,7 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
if (lba_end <= lba_start) return -EINVAL;
return cdrom_play_lba_range (drive, lba_start, lba_end);
return cdrom_play_lba_range (drive, lba_start, lba_end, NULL);
}
case CDROMREADTOCHDR:
......@@ -1793,7 +2120,7 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
if (stat) return stat;
/* Make sure our saved TOC is valid. */
stat = cdrom_read_toc (drive);
stat = cdrom_read_toc (drive, NULL);
if (stat) return stat;
toc = drive->cdrom_info.toc;
......@@ -1818,7 +2145,7 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
memcpy_fromfs (&tocentry, (void *) arg, sizeof (tocentry));
stat = cdrom_get_toc_entry (drive, tocentry.cdte_track, &toce);
stat = cdrom_get_toc_entry (drive, tocentry.cdte_track, &toce, NULL);
if (stat) return stat;
tocentry.cdte_ctrl = toce->control;
......@@ -1853,7 +2180,7 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
memcpy_fromfs (&subchnl, (void *) arg, sizeof (subchnl));
stat = cdrom_read_subchannel (drive, buffer, sizeof (buffer));
stat = cdrom_read_subchannel (drive, buffer, sizeof (buffer), NULL);
if (stat) return stat;
abs_lba = *(int *)&buffer[8];
......@@ -1898,9 +2225,9 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
if (stat) return stat;
memcpy_fromfs (&volctrl, (void *) arg, sizeof (volctrl));
stat = cdrom_mode_sense (drive, 0x0e, 0, buffer, sizeof (buffer));
stat = cdrom_mode_sense (drive, 0x0e, 0, buffer, sizeof (buffer),NULL);
if (stat) return stat;
stat = cdrom_mode_sense (drive, 0x0e, 1, mask , sizeof (buffer));
stat = cdrom_mode_sense (drive, 0x0e, 1, mask , sizeof (buffer),NULL);
if (stat) return stat;
buffer[1] = buffer[2] = 0;
......@@ -1910,35 +2237,219 @@ int ide_cdrom_ioctl (ide_drive_t *drive, struct inode *inode,
buffer[21] = volctrl.channel2 & mask[21];
buffer[23] = volctrl.channel3 & mask[23];
return cdrom_mode_select (drive, 0x0e, buffer, sizeof (buffer));
return cdrom_mode_select (drive, 0x0e, buffer, sizeof (buffer), NULL);
}
case CDROMVOLREAD:
{
struct cdrom_volctrl volctrl;
char buffer[24];
int stat;
stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (volctrl));
if (stat) return stat;
stat = cdrom_mode_sense (drive, 0x0e, 0, buffer, sizeof (buffer), NULL);
if (stat) return stat;
volctrl.channel0 = buffer[17];
volctrl.channel1 = buffer[19];
volctrl.channel2 = buffer[21];
volctrl.channel3 = buffer[23];
memcpy_tofs ((void *) arg, &volctrl, sizeof (volctrl));
return 0;
}
case CDROMMULTISESSION:
{
struct cdrom_multisession ms_info;
struct atapi_toc *toc;
int stat;
stat = verify_area (VERIFY_READ, (void *)arg, sizeof (ms_info));
if (stat) return stat;
stat = verify_area (VERIFY_WRITE, (void *)arg, sizeof (ms_info));
if (stat) return stat;
memcpy_fromfs (&ms_info, (void *)arg, sizeof (ms_info));
/* Make sure the TOC information is valid. */
stat = cdrom_read_toc (drive, NULL);
if (stat) return stat;
toc = drive->cdrom_info.toc;
if (ms_info.addr_format == CDROM_MSF)
lba_to_msf (toc->last_session_lba,
&ms_info.addr.msf.minute,
&ms_info.addr.msf.second,
&ms_info.addr.msf.frame);
else if (ms_info.addr_format == CDROM_LBA)
ms_info.addr.lba = toc->last_session_lba;
else
return -EINVAL;
ms_info.xa_flag = toc->xa_flag;
memcpy_tofs ((void *)arg, &ms_info, sizeof (ms_info));
return 0;
}
/* Read 2352 byte blocks from audio tracks. */
case CDROMREADAUDIO:
{
int stat, lba;
struct atapi_toc *toc;
struct cdrom_read_audio ra;
char buf[CD_FRAMESIZE_RAW];
/* Make sure the TOC is up to date. */
stat = cdrom_read_toc (drive, NULL);
if (stat) return stat;
toc = drive->cdrom_info.toc;
stat = verify_area (VERIFY_READ, (char *)arg, sizeof (ra));
if (stat) return stat;
memcpy_fromfs (&ra, (void *)arg, sizeof (ra));
if (ra.nframes < 0 || ra.nframes > toc->capacity)
return -EINVAL;
else if (ra.nframes == 0)
return 0;
stat = verify_area (VERIFY_WRITE, (char *)ra.buf,
ra.nframes * CD_FRAMESIZE_RAW);
if (stat) return stat;
if (ra.addr_format == CDROM_MSF)
lba = msf_to_lba (ra.addr.msf.minute, ra.addr.msf.second,
ra.addr.msf.frame);
else if (ra.addr_format == CDROM_LBA)
lba = ra.addr.lba;
else
return -EINVAL;
if (lba < 0 || lba >= toc->capacity)
return -EINVAL;
while (ra.nframes > 0)
{
stat = cdrom_read_block (drive, 1, lba, buf,
CD_FRAMESIZE_RAW, NULL);
if (stat) return stat;
memcpy_tofs (ra.buf, buf, CD_FRAMESIZE_RAW);
ra.buf += CD_FRAMESIZE_RAW;
--ra.nframes;
++lba;
}
return 0;
}
case CDROMREADMODE1:
case CDROMREADMODE2:
{
struct cdrom_msf msf;
int blocksize, format, stat, lba;
struct atapi_toc *toc;
char buf[CD_FRAMESIZE_RAW0];
if (cmd == CDROMREADMODE1)
{
blocksize = CD_FRAMESIZE;
format = 2;
}
else
{
blocksize = CD_FRAMESIZE_RAW0;
format = 3;
}
stat = verify_area (VERIFY_READ, (char *)arg, sizeof (msf));
if (stat) return stat;
stat = verify_area (VERIFY_WRITE, (char *)arg, blocksize);
if (stat) return stat;
memcpy_fromfs (&msf, (void *)arg, sizeof (msf));
lba = msf_to_lba (msf.cdmsf_min0, msf.cdmsf_sec0, msf.cdmsf_frame0);
/* Make sure the TOC is up to date. */
stat = cdrom_read_toc (drive, NULL);
if (stat) return stat;
toc = drive->cdrom_info.toc;
if (lba < 0 || lba >= toc->capacity)
return -EINVAL;
stat = cdrom_read_block (drive, format, lba, buf, blocksize, NULL);
if (stat) return stat;
memcpy_tofs ((char *)arg, buf, blocksize);
return 0;
}
#if 0 /* Doesn't work reliably yet. */
case CDROMRESET:
{
struct request req;
memset (&req, 0, sizeof (req));
req.cmd = RESET_DRIVE_COMMAND;
cdrom_queue_request (drive, &req);
return 0;
}
#endif
#ifdef TEST
case 0x1234:
{
int stat;
struct packet_command pc;
int len, lena;
memset (&pc, 0, sizeof (pc));
stat = verify_area (VERIFY_READ, (void *) arg, sizeof (pc.c));
if (stat) return stat;
memcpy_fromfs (&pc.c, (void *) arg, sizeof (pc.c));
arg += sizeof (pc.c);
return cdrom_queue_packet_command (drive, &pc);
}
stat = verify_area (VERIFY_READ, (void *) arg, sizeof (len));
if (stat) return stat;
memcpy_fromfs (&len, (void *) arg , sizeof (len));
arg += sizeof (len);
case 0x1235:
{
int stat;
struct atapi_request_sense reqbuf;
if (len > 0) {
stat = verify_area (VERIFY_WRITE, (void *) arg, len);
if (stat) return stat;
}
stat = verify_area (VERIFY_WRITE, (void *) arg, sizeof (reqbuf));
if (stat) return stat;
lena = len;
if (lena < 0) lena = 0;
stat = cdrom_request_sense (drive, &reqbuf);
{
char buf[lena];
if (len > 0) {
pc.buflen = len;
pc.buffer = buf;
}
memcpy_tofs ((void *) arg, &reqbuf, sizeof (reqbuf));
stat = cdrom_queue_packet_command (drive, &pc);
if (len > 0)
memcpy_tofs ((void *)arg, buf, len);
}
return stat;
}
......@@ -1960,10 +2471,10 @@ int ide_cdrom_check_media_change (ide_drive_t *drive)
{
int retval;
cdrom_check_status (drive);
(void) cdrom_check_status (drive, NULL);
retval = CDROM_FLAGS (drive)->media_changed;
CDROM_FLAGS (drive)->media_changed = 0;
retval = CDROM_STATE_FLAGS (drive)->media_changed;
CDROM_STATE_FLAGS (drive)->media_changed = 0;
return retval;
}
......@@ -1972,15 +2483,43 @@ int ide_cdrom_check_media_change (ide_drive_t *drive)
int ide_cdrom_open (struct inode *ip, struct file *fp, ide_drive_t *drive)
{
/* no write access */
if (fp->f_mode & 2) return -EROFS;
if (fp->f_mode & 2)
{
--drive->usage;
return -EROFS;
}
#if 0 /* With this, one cannot eject a disk with workman */
/* If this is the first open, lock the door. */
/* If this is the first open, check the drive status. */
if (drive->usage == 1)
(void) cdrom_lockdoor (drive, 1);
#endif
{
int stat;
struct atapi_request_sense my_reqbuf;
my_reqbuf.sense_key = 0;
/* Get the drive status. */
stat = cdrom_check_status (drive, &my_reqbuf);
/* If the tray is open, try to close it. */
if (stat && my_reqbuf.sense_key == NOT_READY)
{
cdrom_eject (drive, 1, &my_reqbuf);
stat = cdrom_check_status (drive, &my_reqbuf);
}
/* Return an error if there are still problems. */
if (stat && my_reqbuf.sense_key != UNIT_ATTENTION)
{
--drive->usage;
return -ENXIO;
}
/* Now lock the door. */
(void) cdrom_lockdoor (drive, 1, &my_reqbuf);
/* And try to read the TOC information now. */
(void) cdrom_read_toc (drive, &my_reqbuf);
}
/* Should check that there's a disk in the drive? */
return 0;
}
......@@ -1995,10 +2534,12 @@ void ide_cdrom_release (struct inode *inode, struct file *file, ide_drive_t *dri
{
invalidate_buffers (inode->i_rdev);
#if 0
/* Unlock the door. */
(void) cdrom_lockdoor (drive, 0);
#endif
(void) cdrom_lockdoor (drive, 0, NULL);
/* Do an eject if we were requested to do so. */
if (CDROM_STATE_FLAGS (drive)->eject_on_close)
(void) cdrom_eject (drive, 0, NULL);
}
}
......@@ -2015,28 +2556,35 @@ void ide_cdrom_setup (ide_drive_t *drive)
drive->special.all = 0;
drive->ready_stat = 0;
CDROM_FLAGS (drive)->media_changed = 0;
CDROM_FLAGS (drive)->toc_valid = 0;
CDROM_STATE_FLAGS (drive)->media_changed = 0;
CDROM_STATE_FLAGS (drive)->toc_valid = 0;
CDROM_STATE_FLAGS (drive)->door_locked = 0;
/* Turn this off by default, since many people don't like it. */
CDROM_STATE_FLAGS (drive)->eject_on_close= 0;
CDROM_FLAGS (drive)->no_playaudio12 = 0;
CDROM_FLAGS (drive)->no_lba_toc = 0;
CDROM_FLAGS (drive)->msf_as_bcd = 0;
CDROM_FLAGS (drive)->drq_interrupt = ((drive->id->config & 0x0060) == 0x20);
CDROM_CONFIG_FLAGS (drive)->no_doorlock = 0;
CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 0;
CDROM_CONFIG_FLAGS (drive)->old_readcd = 0;
CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 0;
CDROM_CONFIG_FLAGS (drive)->msf_as_bcd = 0;
CDROM_CONFIG_FLAGS (drive)->drq_interrupt =
((drive->id->config & 0x0060) == 0x20);
/* Accommodate some broken drives... */
if (strcmp (drive->id->model, "CD220E") == 0) /* Creative Labs */
CDROM_FLAGS (drive)->no_lba_toc = 1;
CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1;
else if (strcmp (drive->id->model, "TO-ICSLYAL") == 0 || /* Acer CD525E */
strcmp (drive->id->model, "OTI-SCYLLA") == 0)
CDROM_FLAGS (drive)->no_lba_toc = 1;
CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1;
else if (strcmp (drive->id->model, "CDA26803I SE") == 0) /* Aztech */
{
CDROM_FLAGS (drive)->no_lba_toc = 1;
CDROM_CONFIG_FLAGS (drive)->no_lba_toc = 1;
/* This drive _also_ does not implement PLAYAUDIO12 correctly. */
CDROM_FLAGS (drive)->no_playaudio12 = 1;
CDROM_CONFIG_FLAGS (drive)->no_playaudio12 = 1;
}
drive->cdrom_info.toc = NULL;
......@@ -2046,19 +2594,14 @@ void ide_cdrom_setup (ide_drive_t *drive)
}
#undef MIN
#undef SECTOR_SIZE
#undef SECTOR_BITS
/*
* TODO:
* Read actual disk capacity.
* Multisession support.
* Direct reading of audio data.
* Eject-on-dismount.
* Lock door while there's a mounted volume.
* CDROM_GET_UPC
* CDROMRESET
* Lock the door when a read request completes successfully and the
* door is not already locked. Also try to reorganize to reduce
* duplicated functionality between read and ioctl paths?
* Establish interfaces for an IDE port driver, and break out the cdrom
* code into a loadable module.
*/
/*
* linux/drivers/block/ide.c Version 5.11 Aug 29, 1995
* linux/drivers/block/ide.c Version 5.12 Sep 1, 1995
*
* Copyright (C) 1994, 1995 Linus Torvalds & authors (see below)
*/
......@@ -130,15 +130,24 @@
* added automatic PCI CMD640 detection/support
* added option for VLB CMD640 support
* tweaked probe to find cdrom on hdb with disks on hda,hdc
* Version 5.12 some performance tuning
* added message to alert user to bad /dev/hd[cd] entries
* OOOPS! fixed bug in atapi reset
* driver now forces "serialize" again for all cmd640 chips
* noticed REALLY_SLOW_IO had no effect, moved it to ide.c
* made do_drive_cmd() into public ide_do_drive_cmd()
*
* Driver compile-time options are in ide.h
*
* To do, in likely order of completion:
* - improved CMD support: probably handing this off to someone else
* - add ioctls to get/set interface timings on cmd640, ht6560b, triton
* - modify kernel to obtain BIOS geometry for drives on 2nd/3rd/4th i/f
* - improved CMD support: probably handing this off to someone else
* - find someone to work on IDE *tape drive* support
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <linux/config.h>
#include <linux/types.h>
#include <linux/string.h>
......@@ -156,6 +165,7 @@
#include <asm/byteorder.h>
#include <asm/irq.h>
#include <asm/segment.h>
#include <asm/io.h>
#ifdef CONFIG_PCI
#include <linux/bios32.h>
......@@ -239,7 +249,7 @@ static void init_ide_data (void)
/* fill in any non-zero initial values */
hwif->noprobe = (h > 1);
hwif->io_base = default_io_base[h];
hwif->ctl_port = hwif->io_base ? hwif->io_base + 0x206 : 0x000;
hwif->ctl_port = hwif->io_base ? hwif->io_base+0x206 : 0x000;
#ifdef CONFIG_BLK_DEV_HD
if (hwif->io_base == HD_DATA)
hwif->noprobe = 1; /* may be overriden by ide_setup() */
......@@ -268,7 +278,6 @@ static void init_ide_data (void)
}
}
#ifdef __i386__
#define VLB_SYNC 1
/*
* Some localbus EIDE interfaces require a special access sequence
......@@ -278,34 +287,32 @@ static void init_ide_data (void)
* to ensure that the reads all happen together.
*/
static inline void do_vlb_sync (unsigned short port) {
unsigned int _v;
__asm__ __volatile__ (
"inb %w1,%b0\n\t"
"inb %w1,%b0\n\t"
"inb %w1,%b0"
: "=&a" (_v) /* outputs */
: "d" (port) ); /* inputs */
(void) inb (port);
(void) inb (port);
(void) inb (port);
}
#endif /* __i386__ */
/*
* This is used for most PIO data transfers *from* the IDE interface
*/
void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
unsigned short io_base = HWIF(drive)->io_base;
unsigned short data_reg = io_base+IDE_DATA_OFFSET;
if (drive->vlb_32bit) {
#ifdef VLB_SYNC
if (drive->vlb_sync) {
cli();
do_vlb_sync(IDE_NSECTOR_REG);
insl(IDE_DATA_REG, buffer, wcount);
do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
insl(data_reg, buffer, wcount);
if (drive->unmask)
sti();
} else
#endif /* VLB_SYNC */
insl(IDE_DATA_REG, buffer, wcount);
insl(data_reg, buffer, wcount);
} else
insw(IDE_DATA_REG, buffer, wcount<<1);
insw(data_reg, buffer, wcount<<1);
}
/*
......@@ -313,19 +320,22 @@ void ide_input_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
*/
void ide_output_data (ide_drive_t *drive, void *buffer, unsigned int wcount)
{
unsigned short io_base = HWIF(drive)->io_base;
unsigned short data_reg = io_base+IDE_DATA_OFFSET;
if (drive->vlb_32bit) {
#ifdef VLB_SYNC
if (drive->vlb_sync) {
cli();
do_vlb_sync(IDE_NSECTOR_REG);
outsl(IDE_DATA_REG, buffer, wcount);
do_vlb_sync(io_base+IDE_NSECTOR_OFFSET);
outsl(data_reg, buffer, wcount);
if (drive->unmask)
sti();
} else
#endif /* VLB_SYNC */
outsl(IDE_DATA_REG, buffer, wcount);
outsl(data_reg, buffer, wcount);
} else
outsw(IDE_DATA_REG, buffer, wcount<<1);
outsw(data_reg, buffer, wcount<<1);
}
#if SUPPORT_HT6560B
......@@ -677,8 +687,8 @@ int ide_do_reset (ide_drive_t *drive)
if (!drive->keep_settings)
drive->unmask = 0;
OUT_BYTE (drive->select.all, IDE_SELECT_REG);
udelay (20);
OUT_BYTE (WIN_SRST, IDE_COMMAND_REG);
udelay (10);
hwgroup->reset_timeout = jiffies + WAIT_WORSTCASE;
start_reset_timer (hwif); /* begin periodic polling */
restore_flags (flags);
......@@ -851,12 +861,10 @@ int ide_error (ide_drive_t *drive, const char *msg, byte stat)
err = ide_dump_status(drive, msg, stat);
if ((rq = HWGROUP(drive)->rq) == NULL || drive == NULL)
return 0;
#ifdef IDE_DRIVE_CMD
if (rq->cmd == IDE_DRIVE_CMD) { /* never retry an explicit DRIVE_CMD */
end_drive_cmd(drive, stat, err);
return 0;
}
#endif /* IDE_DRIVE_CMD */
if (stat & BUSY_STAT) { /* other bits are useless when BUSY */
rq->errors |= ERROR_RESET;
} else {
......@@ -1105,7 +1113,6 @@ static void recal_intr (ide_drive_t *drive)
IDE_DO_REQUEST;
}
#ifdef IDE_DRIVE_CMD
/*
* drive_cmd_intr() is invoked on completion of a special DRIVE_CMD.
*/
......@@ -1120,7 +1127,6 @@ static void drive_cmd_intr (ide_drive_t *drive)
return;
IDE_DO_REQUEST;
}
#endif /* IDE_DRIVE_CMD */
/*
* do_special() is used to issue WIN_SPECIFY, WIN_RESTORE, and WIN_SETMULT
......@@ -1175,26 +1181,28 @@ static inline void do_special (ide_drive_t *drive)
int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeout)
{
byte stat;
unsigned long flags;
test:
udelay(1); /* spec allows drive 400ns to change "BUSY" */
if (OK_STAT((stat = GET_STAT()), good, bad))
return 0; /* fast exit for most frequent case */
if (!(stat & BUSY_STAT)) {
(void) ide_error(drive, "status error", stat);
return 1;
}
udelay(1); /* spec allows drive 400ns to assert "BUSY" */
if (GET_STAT() & BUSY_STAT) {
unsigned long flags;
save_flags(flags);
sti();
timeout += jiffies;
while (GET_STAT() & BUSY_STAT) {
if (jiffies > timeout) {
restore_flags(flags);
(void) ide_error(drive, "status timeout", GET_STAT());
return 1;
}
save_flags(flags);
sti();
timeout += jiffies;
do {
if (!((stat = GET_STAT()) & BUSY_STAT)) {
restore_flags(flags);
goto test;
}
restore_flags(flags);
udelay(1); /* spec allows 400ns for status to stabilize */
}
if (OK_STAT(stat=GET_STAT(), good, bad))
return 0;
(void) ide_error(drive, "status error", stat);
} while (jiffies <= timeout);
restore_flags(flags);
(void) ide_error(drive, "status timeout", GET_STAT());
return 1;
}
......@@ -1205,28 +1213,30 @@ int ide_wait_stat (ide_drive_t *drive, byte good, byte bad, unsigned long timeou
*/
static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block)
{
unsigned short io_base = HWIF(drive)->io_base;
OUT_BYTE(drive->ctl,IDE_CONTROL_REG);
OUT_BYTE(rq->nr_sectors,IDE_NSECTOR_REG);
OUT_BYTE(rq->nr_sectors,io_base+IDE_NSECTOR_OFFSET);
if (drive->select.b.lba) {
#ifdef DEBUG
printk("%s: %sing: LBAsect=%ld, sectors=%ld, buffer=0x%08lx\n",
drive->name, (rq->cmd==READ)?"read":"writ",
block, rq->nr_sectors, (unsigned long) rq->buffer);
#endif
OUT_BYTE(block,IDE_SECTOR_REG);
OUT_BYTE(block>>=8,IDE_LCYL_REG);
OUT_BYTE(block>>=8,IDE_HCYL_REG);
OUT_BYTE(((block>>8)&0x0f)|drive->select.all,IDE_SELECT_REG);
OUT_BYTE(block,io_base+IDE_SECTOR_OFFSET);
OUT_BYTE(block>>=8,io_base+IDE_LCYL_OFFSET);
OUT_BYTE(block>>=8,io_base+IDE_HCYL_OFFSET);
OUT_BYTE(((block>>8)&0x0f)|drive->select.all,io_base+IDE_SELECT_OFFSET);
} else {
unsigned int sect,head,cyl,track;
track = block / drive->sect;
sect = block % drive->sect + 1;
OUT_BYTE(sect,IDE_SECTOR_REG);
OUT_BYTE(sect,io_base+IDE_SECTOR_OFFSET);
head = track % drive->head;
cyl = track / drive->head;
OUT_BYTE(cyl,IDE_LCYL_REG);
OUT_BYTE(cyl>>8,IDE_HCYL_REG);
OUT_BYTE(head|drive->select.all,IDE_SELECT_REG);
OUT_BYTE(cyl,io_base+IDE_LCYL_OFFSET);
OUT_BYTE(cyl>>8,io_base+IDE_HCYL_OFFSET);
OUT_BYTE(head|drive->select.all,io_base+IDE_SELECT_OFFSET);
#ifdef DEBUG
printk("%s: %sing: CHS=%d/%d/%d, sectors=%ld, buffer=0x%08lx\n",
drive->name, (rq->cmd==READ)?"read":"writ", cyl,
......@@ -1239,7 +1249,7 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned
return;
#endif /* CONFIG_BLK_DEV_TRITON */
ide_set_handler(drive, &read_intr);
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, IDE_COMMAND_REG);
OUT_BYTE(drive->mult_count ? WIN_MULTREAD : WIN_READ, io_base+IDE_COMMAND_OFFSET);
return;
}
if (rq->cmd == WRITE) {
......@@ -1247,7 +1257,7 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned
if (drive->using_dma && !(HWIF(drive)->dmaproc(ide_dma_write, drive)))
return;
#endif /* CONFIG_BLK_DEV_TRITON */
OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, IDE_COMMAND_REG);
OUT_BYTE(drive->mult_count ? WIN_MULTWRITE : WIN_WRITE, io_base+IDE_COMMAND_OFFSET);
if (ide_wait_stat(drive, DATA_READY, drive->bad_wstat, WAIT_DRQ)) {
printk("%s: no DRQ after issuing %s\n", drive->name,
drive->mult_count ? "MULTWRITE" : "WRITE");
......@@ -1265,13 +1275,12 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned
}
return;
}
#ifdef IDE_DRIVE_CMD
if (rq->cmd == IDE_DRIVE_CMD) {
byte *args = rq->buffer;
if (args) {
printk("%s: DRIVE_CMD cmd=0x%02x sc=0x%02x fr=0x%02x\n",
drive->name, args[0], args[1], args[2]);
OUT_BYTE(args[2],IDE_FEATURE_REG);
OUT_BYTE(args[2],io_base+IDE_FEATURE_OFFSET);
ide_cmd(drive, args[0], args[1], &drive_cmd_intr);
return;
} else {
......@@ -1286,7 +1295,6 @@ static inline void do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned
return;
}
}
#endif /* IDE_DRIVE_CMD */
printk("%s: bad command: %d\n", drive->name, rq->cmd);
ide_end_request(0, HWGROUP(drive));
}
......@@ -1574,6 +1582,10 @@ static ide_drive_t *get_info_ptr (int i_rdev)
ide_drive_t *drive = &hwif->drives[unit];
if (drive->present)
return drive;
} else if (major == IDE0_MAJOR && unit < 4) {
printk("ide: probable bad entry for /dev/hd%c%d\n",
'a' + unit, MINOR(i_rdev) & PARTN_MASK);
printk("ide: to fix it, run: /usr/src/linux/drivers/block/MAKEDEV.ide\n");
}
break;
}
......@@ -1581,14 +1593,13 @@ static ide_drive_t *get_info_ptr (int i_rdev)
return NULL;
}
#ifdef IDE_DRIVE_CMD
/*
* This function issues a specific IDE drive command onto the
* tail of the request queue, and waits for it to be completed.
* If arg is NULL, it goes through all the motions,
* but without actually sending a command to the drive.
*/
static int do_drive_cmd(int rdev, char *args)
int ide_do_drive_cmd(int rdev, char *args)
{
unsigned long flags;
unsigned int major = MAJOR(rdev);
......@@ -1626,7 +1637,6 @@ static int do_drive_cmd(int rdev, char *args)
restore_flags(flags);
return rq.errors ? -EIO : 0; /* return -EIO if errors */
}
#endif /* IDE_DRIVE_CMD */
static int ide_open(struct inode * inode, struct file * filp)
{
......@@ -1646,13 +1656,9 @@ static int ide_open(struct inode * inode, struct file * filp)
return ide_cdrom_open (inode, filp, drive);
#endif /* CONFIG_BLK_DEV_IDECD */
if (drive->removeable) {
check_disk_change(inode->i_rdev);
#ifdef IDE_DRIVE_CMD
{
byte door_lock[] = {WIN_DOORLOCK,0,0,0};
do_drive_cmd(inode->i_rdev, door_lock);
}
#endif /* IDE_DRIVE_CMD */
check_disk_change(inode->i_rdev);
ide_do_drive_cmd(inode->i_rdev, door_lock);
}
return 0;
}
......@@ -1674,13 +1680,9 @@ static void ide_release(struct inode * inode, struct file * file)
else
#endif /* CONFIG_BLK_DEV_IDECD */
if (drive->removeable) {
invalidate_buffers(inode->i_rdev);
#ifdef IDE_DRIVE_CMD
{
byte door_unlock[] = {WIN_DOORUNLOCK,0,0,0};
do_drive_cmd(inode->i_rdev, door_unlock);
}
#endif /* IDE_DRIVE_CMD */
invalidate_buffers(inode->i_rdev);
ide_do_drive_cmd(inode->i_rdev, door_unlock);
}
}
}
......@@ -1876,10 +1878,7 @@ static int ide_ioctl (struct inode *inode, struct file *file,
drive->mult_req = arg;
drive->special.b.set_multmode = 1;
restore_flags(flags);
#ifndef IDE_DRIVE_CMD
return 0;
#else
do_drive_cmd (inode->i_rdev, NULL);
ide_do_drive_cmd (inode->i_rdev, NULL);
return (drive->mult_count == arg) ? 0 : -EIO;
case HDIO_DRIVE_CMD:
......@@ -1887,20 +1886,19 @@ static int ide_ioctl (struct inode *inode, struct file *file,
unsigned long args;
if (NULL == (long *) arg)
err = do_drive_cmd(inode->i_rdev,NULL);
err = ide_do_drive_cmd(inode->i_rdev,NULL);
else {
if (!(err = verify_area(VERIFY_READ,(long *)arg,sizeof(long))))
{
args = get_user((long *)arg);
if (!(err = verify_area(VERIFY_WRITE,(long *)arg,sizeof(long)))) {
err = do_drive_cmd(inode->i_rdev,(char *)&args);
err = ide_do_drive_cmd(inode->i_rdev,(char *)&args);
put_user(args,(long *)arg);
}
}
}
return err;
}
#endif /* IDE_DRIVE_CMD */
RO_IOCTLS(inode->i_rdev, arg);
......@@ -2398,7 +2396,8 @@ void init_cmd640_vlb (void)
byte reg;
unsigned short port = 0x178;
printk("ide: buggy CMD640 interface: ");
single_threaded = 1;
printk("ide: buggy CMD640 interface: serialized, ");
reg = read_cmd640_vlb(port, 0x50);
if (reg == 0xff || (reg & 0x90) != 0x90) {
#if TRY_CMD640_VLB_AT_0x78
......@@ -2406,9 +2405,8 @@ void init_cmd640_vlb (void)
if (reg == 0xff || (reg & 0x90) != 0x90)
#endif
{
single_threaded = 1;
disallow_unmask = 1;
printk("(probe failed) serialized, disabled unmasking\n");
printk("(probe failed) disabled unmasking\n");
return;
}
}
......@@ -2578,8 +2576,14 @@ void ide_setup (char *s)
#if SUPPORT_HT6560B
case -4: /* "ht6560b" */
if (hw > 1) goto bad_hwif;
ide_hwifs[0].select = 0x1c;
ide_hwifs[1].select = 0x1d;
/*
* Using 0x1c and 0x1d apparently selects a
* faster interface speed than 0x3c and 0x3d.
*
* Need to add an ioctl to select between them.
*/
ide_hwifs[0].select = 0x3c;
ide_hwifs[1].select = 0x3d;
goto do_serialize;
#endif /* SUPPORT_HT6560B */
#if SUPPORT_DTC2278
......@@ -2752,7 +2756,7 @@ static int init_irq (ide_hwif_t *hwif)
restore_flags(flags); /* safe now that hwif->hwgroup is set up */
printk("%s at 0x%03x-0x%03x,0x%03x on irq %d", hwif->name,
hwif->io_base, hwif->io_base + 7, hwif->ctl_port, hwif->irq);
hwif->io_base, hwif->io_base+7, hwif->ctl_port, hwif->irq);
if (hwgroup->hwif != hwif) {
char *name = hwgroup->hwif->name;
if (hwgroup->hwif->irq == hwif->irq)
......@@ -2818,12 +2822,13 @@ void init_cmd640 (byte bus, byte fn)
int rc;
unsigned char reg;
single_threaded = 1;
printk("ide: buggy CMD640 interface: ");
if ((rc = pcibios_read_config_byte(bus, fn, 0x51, &reg))
|| (rc = pcibios_write_config_byte(bus, fn, 0x51, reg | 0xc8)))
buggy_interface_fallback (rc);
else
printk("disabled read-ahead, enabled secondary\n");
printk("serialized, disabled read-ahead, enabled secondary\n");
}
#endif /* SUPPORT_CMD640 */
......@@ -2840,8 +2845,6 @@ static void ide_probe_pci (unsigned short vendor, unsigned short device, ide_pci
byte fn, bus;
int rc;
if (!pcibios_present())
return;
save_flags(flags);
cli();
for (index = 0; !pcibios_find_device (vendor, device, index, &bus, &fn); ++index) {
......@@ -2892,7 +2895,8 @@ unsigned long ide_init (unsigned long mem_start, unsigned long mem_end)
/*
* Find/initialize PCI IDE interfaces
*/
ide_init_pci ();
if (pcibios_present())
ide_init_pci ();
#endif /* CONFIG_PCI */
/*
......
......@@ -17,11 +17,10 @@
/******************************************************************************
* IDE driver configuration options (play with these as desired):
*
* REALLY_SLOW_IO can be defined in ide.c and ide-cd.c, if necessary
*/
#undef REALLY_SLOW_IO /* most systems can safely undef this */
#include <asm/io.h>
#undef REALLY_FAST_IO /* define if ide ports are perfect */
#define REALLY_FAST_IO /* define if ide ports are perfect */
#define INITIAL_MULT_COUNT 0 /* off=0; on=2,4,8,16,32, etc.. */
#ifndef DISK_RECOVERY_TIME /* off=0; on=access_delay_time */
......@@ -81,14 +80,25 @@ typedef unsigned char byte; /* used everywhere */
#define HWIF(drive) ((ide_hwif_t *)drive->hwif)
#define HWGROUP(drive) ((ide_hwgroup_t *)(HWIF(drive)->hwgroup))
#define IDE_DATA_REG (HWIF(drive)->io_base)
#define IDE_ERROR_REG (HWIF(drive)->io_base+1)
#define IDE_NSECTOR_REG (HWIF(drive)->io_base+2)
#define IDE_SECTOR_REG (HWIF(drive)->io_base+3)
#define IDE_LCYL_REG (HWIF(drive)->io_base+4)
#define IDE_HCYL_REG (HWIF(drive)->io_base+5)
#define IDE_SELECT_REG (HWIF(drive)->io_base+6)
#define IDE_STATUS_REG (HWIF(drive)->io_base+7)
#define IDE_DATA_OFFSET (0)
#define IDE_ERROR_OFFSET (1)
#define IDE_NSECTOR_OFFSET (2)
#define IDE_SECTOR_OFFSET (3)
#define IDE_LCYL_OFFSET (4)
#define IDE_HCYL_OFFSET (5)
#define IDE_SELECT_OFFSET (6)
#define IDE_STATUS_OFFSET (7)
#define IDE_FEATURE_OFFSET IDE_ERROR_OFFSET
#define IDE_COMMAND_OFFSET IDE_STATUS_OFFSET
#define IDE_DATA_REG (HWIF(drive)->io_base+IDE_DATA_OFFSET)
#define IDE_ERROR_REG (HWIF(drive)->io_base+IDE_ERROR_OFFSET)
#define IDE_NSECTOR_REG (HWIF(drive)->io_base+IDE_NSECTOR_OFFSET)
#define IDE_SECTOR_REG (HWIF(drive)->io_base+IDE_SECTOR_OFFSET)
#define IDE_LCYL_REG (HWIF(drive)->io_base+IDE_LCYL_OFFSET)
#define IDE_HCYL_REG (HWIF(drive)->io_base+IDE_HCYL_OFFSET)
#define IDE_SELECT_REG (HWIF(drive)->io_base+IDE_SELECT_OFFSET)
#define IDE_STATUS_REG (HWIF(drive)->io_base+IDE_STATUS_OFFSET)
#define IDE_CONTROL_REG (HWIF(drive)->ctl_port)
#define IDE_FEATURE_REG IDE_ERROR_REG
#define IDE_COMMAND_REG IDE_STATUS_REG
......@@ -414,6 +424,17 @@ int ide_do_reset (ide_drive_t *);
*/
void *ide_alloc (unsigned long bytecount, unsigned long within_area);
/*
* This function issues a specific IDE drive command onto the
* tail of the request queue, and waits for it to be completed.
* If arg is NULL, it goes through all the motions,
* but without actually sending a command to the drive.
*
* The value of arg is passed to the internal handler as rq->buffer.
*/
int ide_do_drive_cmd(int rdev, char *args);
#ifdef CONFIG_BLK_DEV_IDECD
/*
* These are routines in ide-cd.c invoked from ide.c
......
......@@ -194,6 +194,29 @@ static int build_dmatable (ide_drive_t *drive)
return 1; /* let the PIO routines handle this weirdness */
}
static int config_drive_for_dma (ide_drive_t *drive)
{
const char **list;
struct hd_driveid *id = drive->id;
if (id && (id->capability & 1)) {
/* Enable DMA on any drive that supports mword2 DMA */
if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
drive->using_dma = 1;
return 0; /* DMA enabled */
}
/* Consult the list of known "good" drives */
list = good_dma_drives;
while (*list) {
if (!strcmp(*list++,id->model)) {
drive->using_dma = 1;
return 0; /* DMA enabled */
}
}
}
return 1; /* DMA not enabled */
}
/*
* triton_dmaproc() initiates/aborts DMA read/write operations on a drive.
*
......@@ -207,40 +230,31 @@ static int build_dmatable (ide_drive_t *drive)
*/
static int triton_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
{
const char **list;
unsigned long dma_base = HWIF(drive)->dma_base;
unsigned int reading = (1 << 3);
if (func == ide_dma_abort) {
outb(inb(dma_base)&~1, dma_base); /* stop DMA */
return 0;
}
if (func == ide_dma_check) {
struct hd_driveid *id = drive->id;
if (id && (id->capability & 1)) {
/* Enable DMA on any drive that supports mword2 DMA */
if ((id->field_valid & 2) && (id->dma_mword & 0x404) == 0x404) {
drive->using_dma = 1;
return 0; /* DMA enabled */
}
/* Consult the list of known "good" drives */
list = good_dma_drives;
while (*list) {
if (!strcmp(*list++,id->model)) {
drive->using_dma = 1;
return 0; /* DMA enabled */
}
}
}
return 1; /* DMA not enabled */
switch (func) {
case ide_dma_abort:
outb(inb(dma_base)&~1, dma_base); /* stop DMA */
return 0;
case ide_dma_check:
return config_drive_for_dma (drive);
case ide_dma_write:
reading = 0;
case ide_dma_read:
break;
default:
printk("triton_dmaproc: unsupported func: %d\n", func);
return 1;
}
if (build_dmatable (drive))
return 1;
outl(virt_to_bus (HWIF(drive)->dmatable), dma_base + 4); /* PRD table */
outb((!func) << 3, dma_base); /* specify r/w */
outb(reading, dma_base); /* specify r/w */
outb(0x26, dma_base+2); /* clear status bits */
ide_set_handler (drive, &dma_intr); /* issue cmd to drive */
OUT_BYTE(func ? WIN_WRITEDMA : WIN_READDMA, IDE_COMMAND_REG);
outb(inb(dma_base)|1, dma_base); /* begin DMA */
OUT_BYTE(reading ? WIN_READDMA : WIN_WRITEDMA, IDE_COMMAND_REG);
outb(inb(dma_base)|1, dma_base); /* begin DMA */
return 0;
}
......@@ -326,8 +340,8 @@ void ide_init_triton (byte bus, byte fn)
base = bmiba + 8;
} else
continue;
printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+5);
if (check_region(base, 6)) {
printk(" %s: BusMaster DMA at 0x%04x-0x%04x", hwif->name, base, base+7);
if (check_region(base, 8)) {
printk(" -- ERROR, PORTS ALREADY IN USE");
} else {
unsigned long *table;
......
......@@ -245,8 +245,6 @@ endif
ifdef CONFIG_ARCNET
L_OBJS += arcnet.o
else
M_OBJS += arcnet.o
endif
ifdef CONFIG_PI
......
......@@ -319,10 +319,14 @@ unsigned long lance_init(unsigned long mem_start, unsigned long mem_end)
for (port = lance_portlist; *port; port++) {
int ioaddr = *port;
if ( check_region(ioaddr, LANCE_TOTAL_SIZE) == 0
&& inb(ioaddr + 14) == 0x57
&& inb(ioaddr + 15) == 0x57) {
mem_start = lance_probe1(ioaddr, mem_start);
if ( check_region(ioaddr, LANCE_TOTAL_SIZE) == 0) {
/* Detect "normal" 0x57 0x57 and the NI6510EB 0x52 0x44
signatures w/ minimal I/O reads */
char offset15, offset14 = inb(ioaddr + 14);
if ((offset14 == 0x52 || offset14 == 0x57) &&
((offset15 = inb(ioaddr + 15)) == 0x57 || offset15 == 0x44))
mem_start = lance_probe1(ioaddr, mem_start);
}
}
......
......@@ -121,10 +121,11 @@ __IN(b,"")
#undef RETURN_TYPE
#define RETURN_TYPE unsigned short
/* __IN(w,"w","0" (0)) */
__IN(w,)
__IN(w,"")
#undef RETURN_TYPE
#define RETURN_TYPE unsigned int
__IN(l,"")
#undef RETURN_TYPE
__OUT(b,"b",char)
__OUT(w,"w",short)
......
#ifndef _LINUX_HDREG_H
#define _LINUX_HDREG_H
#include <linux/config.h>
/*
* This file contains some defines for the AT-hd-controller.
* Various sources.
......@@ -154,9 +152,12 @@ struct hd_driveid {
/* unsigned short reservedyy[96];*/ /* reserved (words 160-255) */
};
#ifdef __KERNEL__
/*
* These routines are used for kernel command line parameters from main.c:
*/
#include <linux/config.h>
#ifdef CONFIG_BLK_DEV_HD
void hd_setup(char *, int *);
#endif /* CONFIG_BLK_DEV_HD */
......@@ -164,4 +165,6 @@ void hd_setup(char *, int *);
void ide_setup(char *);
#endif /* CONFIG_BLK_DEV_IDE */
#endif /* __KERNEL__ */
#endif /* _LINUX_HDREG_H */
......@@ -25,7 +25,7 @@
struct igmphdr
{
unsigned char type;
unsigned char unused;
unsigned char code;
unsigned short csum;
unsigned long group;
};
......@@ -37,7 +37,7 @@ struct igmphdr
struct igmp_header
{
unsigned char type;
unsigned char unused;
unsigned char code;
unsigned short csum;
unsigned long group;
};
......
......@@ -110,6 +110,8 @@ struct mcd_Toc {
struct msf diskTime;
};
#if 0
#ifndef I_WAS_HERE
#error Please edit this file first.
#endif
#endif
......@@ -173,6 +173,8 @@
#define MCDX_E 1 /* unspec error */
#define MCDX_EOM 2 /* end of media */
#if 0
#ifndef I_WAS_HERE
#error Please edit this file first.
#endif
#endif
......@@ -1305,7 +1305,7 @@ int dev_ioctl(unsigned int cmd, void *arg)
void dev_init(void)
{
struct device *dev, *dev2;
struct device *dev, **dp;
/*
* Add the devices.
......@@ -1313,24 +1313,25 @@ void dev_init(void)
* from the chain disconnecting the device until the
* next reboot.
*/
dev2 = NULL;
for (dev = dev_base; dev != NULL; dev=dev->next)
dp = &dev_base;
while ((dev = *dp) != NULL)
{
int i;
for (i = 0; i < DEV_NUMBUFFS; i++) {
skb_queue_head_init(dev->buffs + i);
}
if (dev->init && dev->init(dev))
{
/*
* It failed to come up. Unhook it.
*/
if (dev2 == NULL)
dev_base = dev->next;
else
dev2->next = dev->next;
*dp = dev->next;
}
else
{
dev2 = dev;
dp = &dev->next;
}
}
proc_net_register(&(struct proc_dir_entry) {
......@@ -1339,6 +1340,5 @@ void dev_init(void)
0, &proc_net_inode_operations,
dev_get_info
});
}
......@@ -1819,7 +1819,7 @@ void ip_queue_xmit(struct sock *sk, struct device *dev,
iph->tot_len = ntohs(skb->len-(((unsigned char *)iph)-skb->data));
#ifdef CONFIG_IP_FIREWALL
if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) != 1)
if(ip_fw_chk(iph, dev, ip_fw_blk_chain, ip_fw_blk_policy, 0) < 1)
/* just don't send this packet */
return;
#endif
......
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