Merge git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/bart/ide-2.6: (32 commits) ide-atapi: start dma in a drive-specific way ide-atapi: put the rest of non-ide-cd code into the else-clause of ide_transfer_pc ide-atapi: remove timeout arg to ide_issue_pc ide-cd: remove handler wrappers ide-cd: remove xferlen arg to cdrom_start_packet_command ide-atapi: split drive-specific functionality in ide_issue_pc ide-atapi: assign expiry and timeout based on device type ide-atapi: compute cmd_len based on device type in ide_transfer_pc ide: remove the last ide-scsi remnants ide-atapi: remove ide-scsi remnants from ide_pc_intr() ide-atapi: remove ide-scsi remnants from ide_transfer_pc() ide-atapi: remove ide-scsi remnants from ide_issue_pc ide-cd: move cdrom_timer_expiry to ide-atapi.c ide-atapi: teach ide atapi about drive->waiting_for_dma ide-atapi: accomodate transfer length calculation for ide-cd ide-atapi: setup dma for ide-cd ide-atapi: combine drive-specific assignments ide-atapi: add a dev_is_idecd-inline remove ide-scsi ide-floppy: allocate only toplevel packet commands ...
This commit is contained in:
commit
2640c9a90f
|
@ -310,15 +310,6 @@ Who: Krzysztof Piotr Oledzki <ole@ans.pl>
|
|||
|
||||
---------------------------
|
||||
|
||||
What: ide-scsi (BLK_DEV_IDESCSI)
|
||||
When: 2.6.29
|
||||
Why: The 2.6 kernel supports direct writing to ide CD drives, which
|
||||
eliminates the need for ide-scsi. The new method is more
|
||||
efficient in every way.
|
||||
Who: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
|
||||
|
||||
---------------------------
|
||||
|
||||
What: i2c_attach_client(), i2c_detach_client(), i2c_driver->detach_client()
|
||||
When: 2.6.29 (ideally) or 2.6.30 (more likely)
|
||||
Why: Deprecated by the new (standard) device driver binding model. Use
|
||||
|
|
|
@ -2152,11 +2152,6 @@ M: Gadi Oxman <gadio@netvision.net.il>
|
|||
L: linux-kernel@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
IDE-SCSI DRIVER
|
||||
L: linux-ide@vger.kernel.org
|
||||
L: linux-scsi@vger.kernel.org
|
||||
S: Orphan
|
||||
|
||||
IDLE-I7300
|
||||
P: Andy Henroid
|
||||
M: andrew.d.henroid@intel.com
|
||||
|
|
|
@ -137,6 +137,7 @@ config BLK_DEV_DELKIN
|
|||
|
||||
config BLK_DEV_IDECD
|
||||
tristate "Include IDE/ATAPI CDROM support"
|
||||
select IDE_ATAPI
|
||||
---help---
|
||||
If you have a CD-ROM drive using the ATAPI protocol, say Y. ATAPI is
|
||||
a newer protocol used by IDE CD-ROM and TAPE drives, similar to the
|
||||
|
@ -185,23 +186,6 @@ config BLK_DEV_IDETAPE
|
|||
To compile this driver as a module, choose M here: the
|
||||
module will be called ide-tape.
|
||||
|
||||
config BLK_DEV_IDESCSI
|
||||
tristate "SCSI emulation support (DEPRECATED)"
|
||||
depends on SCSI
|
||||
select IDE_ATAPI
|
||||
---help---
|
||||
WARNING: ide-scsi is no longer needed for cd writing applications!
|
||||
The 2.6 kernel supports direct writing to ide-cd, which eliminates
|
||||
the need for ide-scsi + the entire scsi stack just for writing a
|
||||
cd. The new method is more efficient in every way.
|
||||
|
||||
This will provide SCSI host adapter emulation for IDE ATAPI devices,
|
||||
and will allow you to use a SCSI device driver instead of a native
|
||||
ATAPI driver.
|
||||
|
||||
If both this SCSI emulation and native ATAPI support are compiled
|
||||
into the kernel, the native support will be used.
|
||||
|
||||
config BLK_DEV_IDEACPI
|
||||
bool "IDE ACPI support"
|
||||
depends on ACPI
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
EXTRA_CFLAGS += -Idrivers/ide
|
||||
|
||||
ide-core-y += ide.o ide-ioctls.o ide-io.o ide-iops.o ide-lib.o ide-probe.o \
|
||||
ide-taskfile.o ide-pm.o ide-park.o ide-pio-blacklist.o
|
||||
ide-taskfile.o ide-pm.o ide-park.o ide-pio-blacklist.o ide-sysfs.o
|
||||
|
||||
# core IDE code
|
||||
ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/cdrom.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/ide.h>
|
||||
#include <scsi/scsi.h>
|
||||
|
@ -14,6 +15,13 @@
|
|||
#define debug_log(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define ATAPI_MIN_CDB_BYTES 12
|
||||
|
||||
static inline int dev_is_idecd(ide_drive_t *drive)
|
||||
{
|
||||
return drive->media == ide_cdrom || drive->media == ide_optical;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether we can support a device,
|
||||
* based on the ATAPI IDENTIFY command results.
|
||||
|
@ -233,18 +241,49 @@ void ide_retry_pc(ide_drive_t *drive, struct gendisk *disk)
|
|||
}
|
||||
EXPORT_SYMBOL_GPL(ide_retry_pc);
|
||||
|
||||
int ide_scsi_expiry(ide_drive_t *drive)
|
||||
int ide_cd_expiry(ide_drive_t *drive)
|
||||
{
|
||||
struct ide_atapi_pc *pc = drive->pc;
|
||||
struct request *rq = HWGROUP(drive)->rq;
|
||||
unsigned long wait = 0;
|
||||
|
||||
debug_log("%s called for %lu at %lu\n", __func__,
|
||||
pc->scsi_cmd->serial_number, jiffies);
|
||||
debug_log("%s: rq->cmd[0]: 0x%x\n", __func__, rq->cmd[0]);
|
||||
|
||||
pc->flags |= PC_FLAG_TIMEDOUT;
|
||||
|
||||
return 0; /* we do not want the IDE subsystem to retry */
|
||||
/*
|
||||
* Some commands are *slow* and normally take a long time to complete.
|
||||
* Usually we can use the ATAPI "disconnect" to bypass this, but not all
|
||||
* commands/drives support that. Let ide_timer_expiry keep polling us
|
||||
* for these.
|
||||
*/
|
||||
switch (rq->cmd[0]) {
|
||||
case GPCMD_BLANK:
|
||||
case GPCMD_FORMAT_UNIT:
|
||||
case GPCMD_RESERVE_RZONE_TRACK:
|
||||
case GPCMD_CLOSE_TRACK:
|
||||
case GPCMD_FLUSH_CACHE:
|
||||
wait = ATAPI_WAIT_PC;
|
||||
break;
|
||||
default:
|
||||
if (!(rq->cmd_flags & REQ_QUIET))
|
||||
printk(KERN_INFO "cmd 0x%x timed out\n",
|
||||
rq->cmd[0]);
|
||||
wait = 0;
|
||||
break;
|
||||
}
|
||||
return wait;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_scsi_expiry);
|
||||
EXPORT_SYMBOL_GPL(ide_cd_expiry);
|
||||
|
||||
int ide_cd_get_xferlen(struct request *rq)
|
||||
{
|
||||
if (blk_fs_request(rq))
|
||||
return 32768;
|
||||
else if (blk_sense_request(rq) || blk_pc_request(rq) ||
|
||||
rq->cmd_type == REQ_TYPE_ATA_PC)
|
||||
return rq->data_len;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
|
||||
|
||||
/*
|
||||
* This is the usual interrupt handler which will be called during a packet
|
||||
|
@ -258,21 +297,14 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
|
|||
struct request *rq = hwif->hwgroup->rq;
|
||||
const struct ide_tp_ops *tp_ops = hwif->tp_ops;
|
||||
xfer_func_t *xferfunc;
|
||||
ide_expiry_t *expiry;
|
||||
unsigned int timeout, temp;
|
||||
u16 bcount;
|
||||
u8 stat, ireason, scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI), dsc = 0;
|
||||
u8 stat, ireason, dsc = 0;
|
||||
|
||||
debug_log("Enter %s - interrupt handler\n", __func__);
|
||||
|
||||
if (scsi) {
|
||||
timeout = ide_scsi_get_timeout(pc);
|
||||
expiry = ide_scsi_expiry;
|
||||
} else {
|
||||
timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
|
||||
: WAIT_TAPE_CMD;
|
||||
expiry = NULL;
|
||||
}
|
||||
timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
|
||||
: WAIT_TAPE_CMD;
|
||||
|
||||
if (pc->flags & PC_FLAG_TIMEDOUT) {
|
||||
drive->pc_callback(drive, 0);
|
||||
|
@ -284,8 +316,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
|
|||
|
||||
if (pc->flags & PC_FLAG_DMA_IN_PROGRESS) {
|
||||
if (hwif->dma_ops->dma_end(drive) ||
|
||||
(drive->media == ide_tape && !scsi && (stat & ATA_ERR))) {
|
||||
if (drive->media == ide_floppy && !scsi)
|
||||
(drive->media == ide_tape && (stat & ATA_ERR))) {
|
||||
if (drive->media == ide_floppy)
|
||||
printk(KERN_ERR "%s: DMA %s error\n",
|
||||
drive->name, rq_data_dir(pc->rq)
|
||||
? "write" : "read");
|
||||
|
@ -307,7 +339,7 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
|
|||
|
||||
local_irq_enable_in_hardirq();
|
||||
|
||||
if (drive->media == ide_tape && !scsi &&
|
||||
if (drive->media == ide_tape &&
|
||||
(stat & ATA_ERR) && rq->cmd[0] == REQUEST_SENSE)
|
||||
stat &= ~ATA_ERR;
|
||||
|
||||
|
@ -315,11 +347,8 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
|
|||
/* Error detected */
|
||||
debug_log("%s: I/O error\n", drive->name);
|
||||
|
||||
if (drive->media != ide_tape || scsi) {
|
||||
if (drive->media != ide_tape)
|
||||
pc->rq->errors++;
|
||||
if (scsi)
|
||||
goto cmd_finished;
|
||||
}
|
||||
|
||||
if (rq->cmd[0] == REQUEST_SENSE) {
|
||||
printk(KERN_ERR "%s: I/O error in request sense"
|
||||
|
@ -335,7 +364,6 @@ static ide_startstop_t ide_pc_intr(ide_drive_t *drive)
|
|||
/* queued, but not started */
|
||||
return ide_stopped;
|
||||
}
|
||||
cmd_finished:
|
||||
pc->error = 0;
|
||||
|
||||
if ((pc->flags & PC_FLAG_WAIT_FOR_DSC) && (stat & ATA_DSC) == 0)
|
||||
|
@ -382,25 +410,8 @@ cmd_finished:
|
|||
"us more data than expected - "
|
||||
"discarding data\n",
|
||||
drive->name);
|
||||
if (scsi)
|
||||
temp = pc->buf_size - pc->xferred;
|
||||
else
|
||||
temp = 0;
|
||||
if (temp) {
|
||||
if (pc->sg)
|
||||
drive->pc_io_buffers(drive, pc,
|
||||
temp, 0);
|
||||
else
|
||||
tp_ops->input_data(drive, NULL,
|
||||
pc->cur_pos, temp);
|
||||
printk(KERN_ERR "%s: transferred %d of "
|
||||
"%d bytes\n",
|
||||
drive->name,
|
||||
temp, bcount);
|
||||
}
|
||||
pc->xferred += temp;
|
||||
pc->cur_pos += temp;
|
||||
ide_pad_transfer(drive, 0, bcount - temp);
|
||||
|
||||
ide_pad_transfer(drive, 0, bcount);
|
||||
goto next_irq;
|
||||
}
|
||||
debug_log("The device wants to send us more data than "
|
||||
|
@ -410,14 +421,13 @@ cmd_finished:
|
|||
} else
|
||||
xferfunc = tp_ops->output_data;
|
||||
|
||||
if ((drive->media == ide_floppy && !scsi && !pc->buf) ||
|
||||
(drive->media == ide_tape && !scsi && pc->bh) ||
|
||||
(scsi && pc->sg)) {
|
||||
if ((drive->media == ide_floppy && !pc->buf) ||
|
||||
(drive->media == ide_tape && pc->bh)) {
|
||||
int done = drive->pc_io_buffers(drive, pc, bcount,
|
||||
!!(pc->flags & PC_FLAG_WRITING));
|
||||
|
||||
/* FIXME: don't do partial completions */
|
||||
if (drive->media == ide_floppy && !scsi)
|
||||
if (drive->media == ide_floppy)
|
||||
ide_end_request(drive, 1, done >> 9);
|
||||
} else
|
||||
xferfunc(drive, NULL, pc->cur_pos, bcount);
|
||||
|
@ -430,7 +440,7 @@ cmd_finished:
|
|||
rq->cmd[0], bcount);
|
||||
next_irq:
|
||||
/* And set the interrupt handler again */
|
||||
ide_set_handler(drive, ide_pc_intr, timeout, expiry);
|
||||
ide_set_handler(drive, ide_pc_intr, timeout, NULL);
|
||||
return ide_started;
|
||||
}
|
||||
|
||||
|
@ -479,11 +489,12 @@ static int ide_delayed_transfer_pc(ide_drive_t *drive)
|
|||
|
||||
static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
|
||||
{
|
||||
struct ide_atapi_pc *pc = drive->pc;
|
||||
struct ide_atapi_pc *uninitialized_var(pc);
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct request *rq = hwif->hwgroup->rq;
|
||||
ide_expiry_t *expiry;
|
||||
unsigned int timeout;
|
||||
int cmd_len;
|
||||
ide_startstop_t startstop;
|
||||
u8 ireason;
|
||||
|
||||
|
@ -493,101 +504,124 @@ static ide_startstop_t ide_transfer_pc(ide_drive_t *drive)
|
|||
return startstop;
|
||||
}
|
||||
|
||||
ireason = ide_read_ireason(drive);
|
||||
if (drive->media == ide_tape &&
|
||||
(drive->dev_flags & IDE_DFLAG_SCSI) == 0)
|
||||
ireason = ide_wait_ireason(drive, ireason);
|
||||
|
||||
if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
|
||||
printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
|
||||
"a packet command\n", drive->name);
|
||||
return ide_do_reset(drive);
|
||||
if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
|
||||
if (drive->dma)
|
||||
drive->waiting_for_dma = 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* If necessary schedule the packet transfer to occur 'timeout'
|
||||
* miliseconds later in ide_delayed_transfer_pc() after the device
|
||||
* says it's ready for a packet.
|
||||
*/
|
||||
if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
|
||||
timeout = drive->pc_delay;
|
||||
expiry = &ide_delayed_transfer_pc;
|
||||
if (dev_is_idecd(drive)) {
|
||||
/* ATAPI commands get padded out to 12 bytes minimum */
|
||||
cmd_len = COMMAND_SIZE(rq->cmd[0]);
|
||||
if (cmd_len < ATAPI_MIN_CDB_BYTES)
|
||||
cmd_len = ATAPI_MIN_CDB_BYTES;
|
||||
|
||||
timeout = rq->timeout;
|
||||
expiry = ide_cd_expiry;
|
||||
} else {
|
||||
if (drive->dev_flags & IDE_DFLAG_SCSI) {
|
||||
timeout = ide_scsi_get_timeout(pc);
|
||||
expiry = ide_scsi_expiry;
|
||||
pc = drive->pc;
|
||||
|
||||
cmd_len = ATAPI_MIN_CDB_BYTES;
|
||||
|
||||
/*
|
||||
* If necessary schedule the packet transfer to occur 'timeout'
|
||||
* miliseconds later in ide_delayed_transfer_pc() after the
|
||||
* device says it's ready for a packet.
|
||||
*/
|
||||
if (drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) {
|
||||
timeout = drive->pc_delay;
|
||||
expiry = &ide_delayed_transfer_pc;
|
||||
} else {
|
||||
timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
|
||||
: WAIT_TAPE_CMD;
|
||||
expiry = NULL;
|
||||
}
|
||||
|
||||
ireason = ide_read_ireason(drive);
|
||||
if (drive->media == ide_tape)
|
||||
ireason = ide_wait_ireason(drive, ireason);
|
||||
|
||||
if ((ireason & ATAPI_COD) == 0 || (ireason & ATAPI_IO)) {
|
||||
printk(KERN_ERR "%s: (IO,CoD) != (0,1) while issuing "
|
||||
"a packet command\n", drive->name);
|
||||
|
||||
return ide_do_reset(drive);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set the interrupt routine */
|
||||
ide_set_handler(drive, ide_pc_intr, timeout, expiry);
|
||||
|
||||
/* Begin DMA, if necessary */
|
||||
if (pc->flags & PC_FLAG_DMA_OK) {
|
||||
pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
|
||||
hwif->dma_ops->dma_start(drive);
|
||||
if (dev_is_idecd(drive)) {
|
||||
if (drive->dma)
|
||||
hwif->dma_ops->dma_start(drive);
|
||||
} else {
|
||||
if (pc->flags & PC_FLAG_DMA_OK) {
|
||||
pc->flags |= PC_FLAG_DMA_IN_PROGRESS;
|
||||
hwif->dma_ops->dma_start(drive);
|
||||
}
|
||||
}
|
||||
|
||||
/* Send the actual packet */
|
||||
if ((drive->atapi_flags & IDE_AFLAG_ZIP_DRIVE) == 0)
|
||||
hwif->tp_ops->output_data(drive, NULL, rq->cmd, 12);
|
||||
hwif->tp_ops->output_data(drive, NULL, rq->cmd, cmd_len);
|
||||
|
||||
return ide_started;
|
||||
}
|
||||
|
||||
ide_startstop_t ide_issue_pc(ide_drive_t *drive, unsigned int timeout,
|
||||
ide_expiry_t *expiry)
|
||||
ide_startstop_t ide_issue_pc(ide_drive_t *drive)
|
||||
{
|
||||
struct ide_atapi_pc *pc = drive->pc;
|
||||
struct ide_atapi_pc *pc;
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
ide_expiry_t *expiry = NULL;
|
||||
unsigned int timeout;
|
||||
u32 tf_flags;
|
||||
u16 bcount;
|
||||
u8 scsi = !!(drive->dev_flags & IDE_DFLAG_SCSI);
|
||||
|
||||
/* We haven't transferred any data yet */
|
||||
pc->xferred = 0;
|
||||
pc->cur_pos = pc->buf;
|
||||
|
||||
/* Request to transfer the entire buffer at once */
|
||||
if (drive->media == ide_tape && scsi == 0)
|
||||
bcount = pc->req_xfer;
|
||||
else
|
||||
bcount = min(pc->req_xfer, 63 * 1024);
|
||||
|
||||
if (pc->flags & PC_FLAG_DMA_ERROR) {
|
||||
pc->flags &= ~PC_FLAG_DMA_ERROR;
|
||||
ide_dma_off(drive);
|
||||
}
|
||||
|
||||
if ((pc->flags & PC_FLAG_DMA_OK) &&
|
||||
(drive->dev_flags & IDE_DFLAG_USING_DMA)) {
|
||||
if (scsi)
|
||||
hwif->sg_mapped = 1;
|
||||
drive->dma = !hwif->dma_ops->dma_setup(drive);
|
||||
if (scsi)
|
||||
hwif->sg_mapped = 0;
|
||||
}
|
||||
|
||||
if (!drive->dma)
|
||||
pc->flags &= ~PC_FLAG_DMA_OK;
|
||||
|
||||
if (scsi)
|
||||
tf_flags = 0;
|
||||
else if (drive->media == ide_cdrom || drive->media == ide_optical)
|
||||
if (dev_is_idecd(drive)) {
|
||||
tf_flags = IDE_TFLAG_OUT_NSECT | IDE_TFLAG_OUT_LBAL;
|
||||
else
|
||||
bcount = ide_cd_get_xferlen(hwif->hwgroup->rq);
|
||||
expiry = ide_cd_expiry;
|
||||
timeout = ATAPI_WAIT_PC;
|
||||
|
||||
if (drive->dma)
|
||||
drive->dma = !hwif->dma_ops->dma_setup(drive);
|
||||
} else {
|
||||
pc = drive->pc;
|
||||
|
||||
/* We haven't transferred any data yet */
|
||||
pc->xferred = 0;
|
||||
pc->cur_pos = pc->buf;
|
||||
|
||||
tf_flags = IDE_TFLAG_OUT_DEVICE;
|
||||
bcount = ((drive->media == ide_tape) ?
|
||||
pc->req_xfer :
|
||||
min(pc->req_xfer, 63 * 1024));
|
||||
|
||||
if (pc->flags & PC_FLAG_DMA_ERROR) {
|
||||
pc->flags &= ~PC_FLAG_DMA_ERROR;
|
||||
ide_dma_off(drive);
|
||||
}
|
||||
|
||||
if ((pc->flags & PC_FLAG_DMA_OK) &&
|
||||
(drive->dev_flags & IDE_DFLAG_USING_DMA))
|
||||
drive->dma = !hwif->dma_ops->dma_setup(drive);
|
||||
|
||||
if (!drive->dma)
|
||||
pc->flags &= ~PC_FLAG_DMA_OK;
|
||||
|
||||
timeout = (drive->media == ide_floppy) ? WAIT_FLOPPY_CMD
|
||||
: WAIT_TAPE_CMD;
|
||||
}
|
||||
|
||||
ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma);
|
||||
|
||||
/* Issue the packet command */
|
||||
if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
|
||||
if (drive->dma)
|
||||
drive->waiting_for_dma = 0;
|
||||
ide_execute_command(drive, ATA_CMD_PACKET, ide_transfer_pc,
|
||||
timeout, NULL);
|
||||
timeout, expiry);
|
||||
return ide_started;
|
||||
} else {
|
||||
ide_execute_pkt_cmd(drive);
|
||||
|
|
|
@ -53,14 +53,6 @@
|
|||
|
||||
#include "ide-cd.h"
|
||||
|
||||
#define IDECD_DEBUG_LOG 1
|
||||
|
||||
#if IDECD_DEBUG_LOG
|
||||
#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
|
||||
#else
|
||||
#define ide_debug_log(lvl, fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
static DEFINE_MUTEX(idecd_ref_mutex);
|
||||
|
||||
static void ide_cd_release(struct kref *);
|
||||
|
@ -519,37 +511,8 @@ end_request:
|
|||
return 1;
|
||||
}
|
||||
|
||||
static int cdrom_timer_expiry(ide_drive_t *drive)
|
||||
{
|
||||
struct request *rq = HWGROUP(drive)->rq;
|
||||
unsigned long wait = 0;
|
||||
|
||||
ide_debug_log(IDE_DBG_RQ, "Call %s: rq->cmd[0]: 0x%x\n", __func__,
|
||||
rq->cmd[0]);
|
||||
|
||||
/*
|
||||
* Some commands are *slow* and normally take a long time to complete.
|
||||
* Usually we can use the ATAPI "disconnect" to bypass this, but not all
|
||||
* commands/drives support that. Let ide_timer_expiry keep polling us
|
||||
* for these.
|
||||
*/
|
||||
switch (rq->cmd[0]) {
|
||||
case GPCMD_BLANK:
|
||||
case GPCMD_FORMAT_UNIT:
|
||||
case GPCMD_RESERVE_RZONE_TRACK:
|
||||
case GPCMD_CLOSE_TRACK:
|
||||
case GPCMD_FLUSH_CACHE:
|
||||
wait = ATAPI_WAIT_PC;
|
||||
break;
|
||||
default:
|
||||
if (!(rq->cmd_flags & REQ_QUIET))
|
||||
printk(KERN_INFO PFX "cmd 0x%x timed out\n",
|
||||
rq->cmd[0]);
|
||||
wait = 0;
|
||||
break;
|
||||
}
|
||||
return wait;
|
||||
}
|
||||
static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *);
|
||||
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
|
||||
|
||||
/*
|
||||
* Set up the device registers for transferring a packet command on DEV,
|
||||
|
@ -559,11 +522,13 @@ static int cdrom_timer_expiry(ide_drive_t *drive)
|
|||
* called when the interrupt from the drive arrives. Otherwise, HANDLER
|
||||
* will be called immediately after the drive is prepared for the transfer.
|
||||
*/
|
||||
static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
|
||||
int xferlen,
|
||||
ide_handler_t *handler)
|
||||
static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct request *rq = hwif->hwgroup->rq;
|
||||
int xferlen;
|
||||
|
||||
xferlen = ide_cd_get_xferlen(rq);
|
||||
|
||||
ide_debug_log(IDE_DBG_PC, "Call %s, xferlen: %d\n", __func__, xferlen);
|
||||
|
||||
|
@ -581,13 +546,14 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
|
|||
drive->waiting_for_dma = 0;
|
||||
|
||||
/* packet command */
|
||||
ide_execute_command(drive, ATA_CMD_PACKET, handler,
|
||||
ATAPI_WAIT_PC, cdrom_timer_expiry);
|
||||
ide_execute_command(drive, ATA_CMD_PACKET,
|
||||
cdrom_transfer_packet_command,
|
||||
ATAPI_WAIT_PC, ide_cd_expiry);
|
||||
return ide_started;
|
||||
} else {
|
||||
ide_execute_pkt_cmd(drive);
|
||||
|
||||
return (*handler) (drive);
|
||||
return cdrom_transfer_packet_command(drive);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -598,11 +564,10 @@ static ide_startstop_t cdrom_start_packet_command(ide_drive_t *drive,
|
|||
* there's data ready.
|
||||
*/
|
||||
#define ATAPI_MIN_CDB_BYTES 12
|
||||
static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
|
||||
struct request *rq,
|
||||
ide_handler_t *handler)
|
||||
static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct request *rq = hwif->hwgroup->rq;
|
||||
int cmd_len;
|
||||
ide_startstop_t startstop;
|
||||
|
||||
|
@ -629,7 +594,7 @@ static ide_startstop_t cdrom_transfer_packet_command(ide_drive_t *drive,
|
|||
}
|
||||
|
||||
/* arm the interrupt handler */
|
||||
ide_set_handler(drive, handler, rq->timeout, cdrom_timer_expiry);
|
||||
ide_set_handler(drive, cdrom_newpc_intr, rq->timeout, ide_cd_expiry);
|
||||
|
||||
/* ATAPI commands get padded out to 12 bytes minimum */
|
||||
cmd_len = COMMAND_SIZE(rq->cmd[0]);
|
||||
|
@ -717,8 +682,6 @@ static int ide_cd_check_transfer_size(ide_drive_t *drive, int len)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static ide_startstop_t cdrom_newpc_intr(ide_drive_t *);
|
||||
|
||||
static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
|
||||
struct request *rq)
|
||||
{
|
||||
|
@ -760,20 +723,6 @@ static ide_startstop_t ide_cd_prepare_rw_request(ide_drive_t *drive,
|
|||
return ide_started;
|
||||
}
|
||||
|
||||
/*
|
||||
* Routine to send a read/write packet command to the drive. This is usually
|
||||
* called directly from cdrom_start_{read,write}(). However, for drq_interrupt
|
||||
* devices, it is called from an interrupt when the drive is ready to accept
|
||||
* the command.
|
||||
*/
|
||||
static ide_startstop_t cdrom_start_rw_cont(ide_drive_t *drive)
|
||||
{
|
||||
struct request *rq = drive->hwif->hwgroup->rq;
|
||||
|
||||
/* send the command to the drive and return */
|
||||
return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fix up a possibly partially-processed request so that we can start it over
|
||||
* entirely, or even put it back on the request queue.
|
||||
|
@ -1096,7 +1045,7 @@ static ide_startstop_t cdrom_newpc_intr(ide_drive_t *drive)
|
|||
} else {
|
||||
timeout = ATAPI_WAIT_PC;
|
||||
if (!blk_fs_request(rq))
|
||||
expiry = cdrom_timer_expiry;
|
||||
expiry = ide_cd_expiry;
|
||||
}
|
||||
|
||||
ide_set_handler(drive, cdrom_newpc_intr, timeout, expiry);
|
||||
|
@ -1163,13 +1112,6 @@ static ide_startstop_t cdrom_start_rw(ide_drive_t *drive, struct request *rq)
|
|||
return ide_started;
|
||||
}
|
||||
|
||||
static ide_startstop_t cdrom_do_newpc_cont(ide_drive_t *drive)
|
||||
{
|
||||
struct request *rq = HWGROUP(drive)->rq;
|
||||
|
||||
return cdrom_transfer_packet_command(drive, rq, cdrom_newpc_intr);
|
||||
}
|
||||
|
||||
static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
|
||||
{
|
||||
|
||||
|
@ -1214,18 +1156,12 @@ static void cdrom_do_block_pc(ide_drive_t *drive, struct request *rq)
|
|||
static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
|
||||
sector_t block)
|
||||
{
|
||||
ide_handler_t *fn;
|
||||
int xferlen;
|
||||
|
||||
ide_debug_log(IDE_DBG_RQ, "Call %s, rq->cmd[0]: 0x%x, "
|
||||
"rq->cmd_type: 0x%x, block: %llu\n",
|
||||
__func__, rq->cmd[0], rq->cmd_type,
|
||||
(unsigned long long)block);
|
||||
|
||||
if (blk_fs_request(rq)) {
|
||||
xferlen = 32768;
|
||||
fn = cdrom_start_rw_cont;
|
||||
|
||||
if (cdrom_start_rw(drive, rq) == ide_stopped)
|
||||
return ide_stopped;
|
||||
|
||||
|
@ -1233,9 +1169,6 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
|
|||
return ide_stopped;
|
||||
} else if (blk_sense_request(rq) || blk_pc_request(rq) ||
|
||||
rq->cmd_type == REQ_TYPE_ATA_PC) {
|
||||
xferlen = rq->data_len;
|
||||
fn = cdrom_do_newpc_cont;
|
||||
|
||||
if (!rq->timeout)
|
||||
rq->timeout = ATAPI_WAIT_PC;
|
||||
|
||||
|
@ -1250,7 +1183,7 @@ static ide_startstop_t ide_cd_do_request(ide_drive_t *drive, struct request *rq,
|
|||
return ide_stopped;
|
||||
}
|
||||
|
||||
return cdrom_start_packet_command(drive, xferlen, fn);
|
||||
return cdrom_start_packet_command(drive);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,10 +8,14 @@
|
|||
#include <linux/cdrom.h>
|
||||
#include <asm/byteorder.h>
|
||||
|
||||
/*
|
||||
* typical timeout for packet command
|
||||
*/
|
||||
#define ATAPI_WAIT_PC (60 * HZ)
|
||||
#define IDECD_DEBUG_LOG 0
|
||||
|
||||
#if IDECD_DEBUG_LOG
|
||||
#define ide_debug_log(lvl, fmt, args...) __ide_debug_log(lvl, fmt, args)
|
||||
#else
|
||||
#define ide_debug_log(lvl, fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define ATAPI_WAIT_WRITE_BUSY (10 * HZ)
|
||||
|
||||
/************************************************************************/
|
||||
|
|
|
@ -197,7 +197,7 @@ static ide_startstop_t idefloppy_issue_pc(ide_drive_t *drive,
|
|||
|
||||
pc->retries++;
|
||||
|
||||
return ide_issue_pc(drive, WAIT_FLOPPY_CMD, NULL);
|
||||
return ide_issue_pc(drive);
|
||||
}
|
||||
|
||||
void ide_floppy_create_read_capacity_cmd(struct ide_atapi_pc *pc)
|
||||
|
@ -342,38 +342,38 @@ static ide_startstop_t ide_floppy_do_request(ide_drive_t *drive,
|
|||
* Look at the flexible disk page parameters. We ignore the CHS capacity
|
||||
* parameters and use the LBA parameters instead.
|
||||
*/
|
||||
static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive)
|
||||
static int ide_floppy_get_flexible_disk_page(ide_drive_t *drive,
|
||||
struct ide_atapi_pc *pc)
|
||||
{
|
||||
struct ide_disk_obj *floppy = drive->driver_data;
|
||||
struct gendisk *disk = floppy->disk;
|
||||
struct ide_atapi_pc pc;
|
||||
u8 *page;
|
||||
int capacity, lba_capacity;
|
||||
u16 transfer_rate, sector_size, cyls, rpm;
|
||||
u8 heads, sectors;
|
||||
|
||||
ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
|
||||
ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_FLEXIBLE_DISK_PAGE);
|
||||
|
||||
if (ide_queue_pc_tail(drive, disk, &pc)) {
|
||||
if (ide_queue_pc_tail(drive, disk, pc)) {
|
||||
printk(KERN_ERR PFX "Can't get flexible disk page params\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (pc.buf[3] & 0x80)
|
||||
if (pc->buf[3] & 0x80)
|
||||
drive->dev_flags |= IDE_DFLAG_WP;
|
||||
else
|
||||
drive->dev_flags &= ~IDE_DFLAG_WP;
|
||||
|
||||
set_disk_ro(disk, !!(drive->dev_flags & IDE_DFLAG_WP));
|
||||
|
||||
page = &pc.buf[8];
|
||||
page = &pc->buf[8];
|
||||
|
||||
transfer_rate = be16_to_cpup((__be16 *)&pc.buf[8 + 2]);
|
||||
sector_size = be16_to_cpup((__be16 *)&pc.buf[8 + 6]);
|
||||
cyls = be16_to_cpup((__be16 *)&pc.buf[8 + 8]);
|
||||
rpm = be16_to_cpup((__be16 *)&pc.buf[8 + 28]);
|
||||
heads = pc.buf[8 + 4];
|
||||
sectors = pc.buf[8 + 5];
|
||||
transfer_rate = be16_to_cpup((__be16 *)&pc->buf[8 + 2]);
|
||||
sector_size = be16_to_cpup((__be16 *)&pc->buf[8 + 6]);
|
||||
cyls = be16_to_cpup((__be16 *)&pc->buf[8 + 8]);
|
||||
rpm = be16_to_cpup((__be16 *)&pc->buf[8 + 28]);
|
||||
heads = pc->buf[8 + 4];
|
||||
sectors = pc->buf[8 + 5];
|
||||
|
||||
capacity = cyls * heads * sectors * sector_size;
|
||||
|
||||
|
@ -499,7 +499,7 @@ static int ide_floppy_get_capacity(ide_drive_t *drive)
|
|||
|
||||
/* Clik! disk does not support get_flexible_disk_page */
|
||||
if (!(drive->atapi_flags & IDE_AFLAG_CLIK_DRIVE))
|
||||
(void) ide_floppy_get_flexible_disk_page(drive);
|
||||
(void) ide_floppy_get_flexible_disk_page(drive, &pc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -31,10 +31,11 @@
|
|||
* On exit we set nformats to the number of records we've actually initialized.
|
||||
*/
|
||||
|
||||
static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
|
||||
static int ide_floppy_get_format_capacities(ide_drive_t *drive,
|
||||
struct ide_atapi_pc *pc,
|
||||
int __user *arg)
|
||||
{
|
||||
struct ide_disk_obj *floppy = drive->driver_data;
|
||||
struct ide_atapi_pc pc;
|
||||
u8 header_len, desc_cnt;
|
||||
int i, blocks, length, u_array_size, u_index;
|
||||
int __user *argp;
|
||||
|
@ -45,13 +46,13 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
|
|||
if (u_array_size <= 0)
|
||||
return -EINVAL;
|
||||
|
||||
ide_floppy_create_read_capacity_cmd(&pc);
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, &pc)) {
|
||||
ide_floppy_create_read_capacity_cmd(pc);
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, pc)) {
|
||||
printk(KERN_ERR "ide-floppy: Can't get floppy parameters\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
header_len = pc.buf[3];
|
||||
header_len = pc->buf[3];
|
||||
desc_cnt = header_len / 8; /* capacity descriptor of 8 bytes */
|
||||
|
||||
u_index = 0;
|
||||
|
@ -68,8 +69,8 @@ static int ide_floppy_get_format_capacities(ide_drive_t *drive, int __user *arg)
|
|||
if (u_index >= u_array_size)
|
||||
break; /* User-supplied buffer too small */
|
||||
|
||||
blocks = be32_to_cpup((__be32 *)&pc.buf[desc_start]);
|
||||
length = be16_to_cpup((__be16 *)&pc.buf[desc_start + 6]);
|
||||
blocks = be32_to_cpup((__be32 *)&pc->buf[desc_start]);
|
||||
length = be16_to_cpup((__be16 *)&pc->buf[desc_start + 6]);
|
||||
|
||||
if (put_user(blocks, argp))
|
||||
return -EFAULT;
|
||||
|
@ -111,29 +112,28 @@ static void ide_floppy_create_format_unit_cmd(struct ide_atapi_pc *pc, int b,
|
|||
pc->flags |= PC_FLAG_WRITING;
|
||||
}
|
||||
|
||||
static int ide_floppy_get_sfrp_bit(ide_drive_t *drive)
|
||||
static int ide_floppy_get_sfrp_bit(ide_drive_t *drive, struct ide_atapi_pc *pc)
|
||||
{
|
||||
struct ide_disk_obj *floppy = drive->driver_data;
|
||||
struct ide_atapi_pc pc;
|
||||
|
||||
drive->atapi_flags &= ~IDE_AFLAG_SRFP;
|
||||
|
||||
ide_floppy_create_mode_sense_cmd(&pc, IDEFLOPPY_CAPABILITIES_PAGE);
|
||||
pc.flags |= PC_FLAG_SUPPRESS_ERROR;
|
||||
ide_floppy_create_mode_sense_cmd(pc, IDEFLOPPY_CAPABILITIES_PAGE);
|
||||
pc->flags |= PC_FLAG_SUPPRESS_ERROR;
|
||||
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, &pc))
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, pc))
|
||||
return 1;
|
||||
|
||||
if (pc.buf[8 + 2] & 0x40)
|
||||
if (pc->buf[8 + 2] & 0x40)
|
||||
drive->atapi_flags |= IDE_AFLAG_SRFP;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
|
||||
static int ide_floppy_format_unit(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
||||
int __user *arg)
|
||||
{
|
||||
struct ide_disk_obj *floppy = drive->driver_data;
|
||||
struct ide_atapi_pc pc;
|
||||
int blocks, length, flags, err = 0;
|
||||
|
||||
if (floppy->openers > 1) {
|
||||
|
@ -166,10 +166,10 @@ static int ide_floppy_format_unit(ide_drive_t *drive, int __user *arg)
|
|||
goto out;
|
||||
}
|
||||
|
||||
(void)ide_floppy_get_sfrp_bit(drive);
|
||||
ide_floppy_create_format_unit_cmd(&pc, blocks, length, flags);
|
||||
ide_floppy_get_sfrp_bit(drive, pc);
|
||||
ide_floppy_create_format_unit_cmd(pc, blocks, length, flags);
|
||||
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, &pc))
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, pc))
|
||||
err = -EIO;
|
||||
|
||||
out:
|
||||
|
@ -188,15 +188,16 @@ out:
|
|||
* the dsc bit, and return either 0 or 65536.
|
||||
*/
|
||||
|
||||
static int ide_floppy_get_format_progress(ide_drive_t *drive, int __user *arg)
|
||||
static int ide_floppy_get_format_progress(ide_drive_t *drive,
|
||||
struct ide_atapi_pc *pc,
|
||||
int __user *arg)
|
||||
{
|
||||
struct ide_disk_obj *floppy = drive->driver_data;
|
||||
struct ide_atapi_pc pc;
|
||||
int progress_indication = 0x10000;
|
||||
|
||||
if (drive->atapi_flags & IDE_AFLAG_SRFP) {
|
||||
ide_create_request_sense_cmd(drive, &pc);
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, &pc))
|
||||
ide_create_request_sense_cmd(drive, pc);
|
||||
if (ide_queue_pc_tail(drive, floppy->disk, pc))
|
||||
return -EIO;
|
||||
|
||||
if (floppy->sense_key == 2 &&
|
||||
|
@ -241,20 +242,21 @@ static int ide_floppy_lockdoor(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int ide_floppy_format_ioctl(ide_drive_t *drive, fmode_t mode,
|
||||
unsigned int cmd, void __user *argp)
|
||||
static int ide_floppy_format_ioctl(ide_drive_t *drive, struct ide_atapi_pc *pc,
|
||||
fmode_t mode, unsigned int cmd,
|
||||
void __user *argp)
|
||||
{
|
||||
switch (cmd) {
|
||||
case IDEFLOPPY_IOCTL_FORMAT_SUPPORTED:
|
||||
return 0;
|
||||
case IDEFLOPPY_IOCTL_FORMAT_GET_CAPACITY:
|
||||
return ide_floppy_get_format_capacities(drive, argp);
|
||||
return ide_floppy_get_format_capacities(drive, pc, argp);
|
||||
case IDEFLOPPY_IOCTL_FORMAT_START:
|
||||
if (!(mode & FMODE_WRITE))
|
||||
return -EPERM;
|
||||
return ide_floppy_format_unit(drive, (int __user *)argp);
|
||||
return ide_floppy_format_unit(drive, pc, (int __user *)argp);
|
||||
case IDEFLOPPY_IOCTL_FORMAT_GET_PROGRESS:
|
||||
return ide_floppy_get_format_progress(drive, argp);
|
||||
return ide_floppy_get_format_progress(drive, pc, argp);
|
||||
default:
|
||||
return -ENOTTY;
|
||||
}
|
||||
|
@ -270,7 +272,7 @@ int ide_floppy_ioctl(ide_drive_t *drive, struct block_device *bdev,
|
|||
if (cmd == CDROMEJECT || cmd == CDROM_LOCKDOOR)
|
||||
return ide_floppy_lockdoor(drive, &pc, arg, cmd);
|
||||
|
||||
err = ide_floppy_format_ioctl(drive, mode, cmd, argp);
|
||||
err = ide_floppy_format_ioctl(drive, &pc, mode, cmd, argp);
|
||||
if (err != -ENOTTY)
|
||||
return err;
|
||||
|
||||
|
|
|
@ -426,9 +426,6 @@ void ide_map_sg(ide_drive_t *drive, struct request *rq)
|
|||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct scatterlist *sg = hwif->sg_table;
|
||||
|
||||
if (hwif->sg_mapped) /* needed by ide-scsi */
|
||||
return;
|
||||
|
||||
if (rq->cmd_type != REQ_TYPE_ATA_TASKFILE) {
|
||||
hwif->sg_nents = blk_rq_map_sg(drive->queue, rq, sg);
|
||||
} else {
|
||||
|
@ -667,85 +664,10 @@ void ide_stall_queue (ide_drive_t *drive, unsigned long timeout)
|
|||
drive->sleep = timeout + jiffies;
|
||||
drive->dev_flags |= IDE_DFLAG_SLEEPING;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(ide_stall_queue);
|
||||
|
||||
#define WAKEUP(drive) ((drive)->service_start + 2 * (drive)->service_time)
|
||||
|
||||
/**
|
||||
* choose_drive - select a drive to service
|
||||
* @hwgroup: hardware group to select on
|
||||
*
|
||||
* choose_drive() selects the next drive which will be serviced.
|
||||
* This is necessary because the IDE layer can't issue commands
|
||||
* to both drives on the same cable, unlike SCSI.
|
||||
*/
|
||||
|
||||
static inline ide_drive_t *choose_drive (ide_hwgroup_t *hwgroup)
|
||||
{
|
||||
ide_drive_t *drive, *best;
|
||||
|
||||
repeat:
|
||||
best = NULL;
|
||||
drive = hwgroup->drive;
|
||||
|
||||
/*
|
||||
* drive is doing pre-flush, ordered write, post-flush sequence. even
|
||||
* though that is 3 requests, it must be seen as a single transaction.
|
||||
* we must not preempt this drive until that is complete
|
||||
*/
|
||||
if (blk_queue_flushing(drive->queue)) {
|
||||
/*
|
||||
* small race where queue could get replugged during
|
||||
* the 3-request flush cycle, just yank the plug since
|
||||
* we want it to finish asap
|
||||
*/
|
||||
blk_remove_plug(drive->queue);
|
||||
return drive;
|
||||
}
|
||||
|
||||
do {
|
||||
u8 dev_s = !!(drive->dev_flags & IDE_DFLAG_SLEEPING);
|
||||
u8 best_s = (best && !!(best->dev_flags & IDE_DFLAG_SLEEPING));
|
||||
|
||||
if ((dev_s == 0 || time_after_eq(jiffies, drive->sleep)) &&
|
||||
!elv_queue_empty(drive->queue)) {
|
||||
if (best == NULL ||
|
||||
(dev_s && (best_s == 0 || time_before(drive->sleep, best->sleep))) ||
|
||||
(best_s == 0 && time_before(WAKEUP(drive), WAKEUP(best)))) {
|
||||
if (!blk_queue_plugged(drive->queue))
|
||||
best = drive;
|
||||
}
|
||||
}
|
||||
} while ((drive = drive->next) != hwgroup->drive);
|
||||
|
||||
if (best && (best->dev_flags & IDE_DFLAG_NICE1) &&
|
||||
(best->dev_flags & IDE_DFLAG_SLEEPING) == 0 &&
|
||||
best != hwgroup->drive && best->service_time > WAIT_MIN_SLEEP) {
|
||||
long t = (signed long)(WAKEUP(best) - jiffies);
|
||||
if (t >= WAIT_MIN_SLEEP) {
|
||||
/*
|
||||
* We *may* have some time to spare, but first let's see if
|
||||
* someone can potentially benefit from our nice mood today..
|
||||
*/
|
||||
drive = best->next;
|
||||
do {
|
||||
if ((drive->dev_flags & IDE_DFLAG_SLEEPING) == 0
|
||||
&& time_before(jiffies - best->service_time, WAKEUP(drive))
|
||||
&& time_before(WAKEUP(drive), jiffies + t))
|
||||
{
|
||||
ide_stall_queue(best, min_t(long, t, 10 * WAIT_MIN_SLEEP));
|
||||
goto repeat;
|
||||
}
|
||||
} while ((drive = drive->next) != best);
|
||||
}
|
||||
}
|
||||
return best;
|
||||
}
|
||||
|
||||
/*
|
||||
* Issue a new request to a drive from hwgroup
|
||||
* Caller must have already done spin_lock_irqsave(&hwgroup->lock, ..);
|
||||
*
|
||||
* A hwgroup is a serialized group of IDE interfaces. Usually there is
|
||||
* exactly one hwif (interface) per hwgroup, but buggy controllers (eg. CMD640)
|
||||
|
@ -757,8 +679,7 @@ repeat:
|
|||
* possibly along with many other devices. This is especially common in
|
||||
* PCI-based systems with off-board IDE controller cards.
|
||||
*
|
||||
* The IDE driver uses a per-hwgroup spinlock to protect
|
||||
* access to the request queues, and to protect the hwgroup->busy flag.
|
||||
* The IDE driver uses a per-hwgroup lock to protect the hwgroup->busy flag.
|
||||
*
|
||||
* The first thread into the driver for a particular hwgroup sets the
|
||||
* hwgroup->busy flag to indicate that this hwgroup is now active,
|
||||
|
@ -778,69 +699,41 @@ repeat:
|
|||
* the driver. This makes the driver much more friendlier to shared IRQs
|
||||
* than previous designs, while remaining 100% (?) SMP safe and capable.
|
||||
*/
|
||||
static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
|
||||
void do_ide_request(struct request_queue *q)
|
||||
{
|
||||
ide_drive_t *drive;
|
||||
ide_hwif_t *hwif;
|
||||
ide_drive_t *drive = q->queuedata;
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
ide_hwgroup_t *hwgroup = hwif->hwgroup;
|
||||
struct request *rq;
|
||||
ide_startstop_t startstop;
|
||||
int loops = 0;
|
||||
|
||||
/* caller must own hwgroup->lock */
|
||||
BUG_ON(!irqs_disabled());
|
||||
|
||||
while (!hwgroup->busy) {
|
||||
hwgroup->busy = 1;
|
||||
/* for atari only */
|
||||
ide_get_lock(ide_intr, hwgroup);
|
||||
drive = choose_drive(hwgroup);
|
||||
if (drive == NULL) {
|
||||
int sleeping = 0;
|
||||
unsigned long sleep = 0; /* shut up, gcc */
|
||||
hwgroup->rq = NULL;
|
||||
drive = hwgroup->drive;
|
||||
do {
|
||||
if ((drive->dev_flags & IDE_DFLAG_SLEEPING) &&
|
||||
(sleeping == 0 ||
|
||||
time_before(drive->sleep, sleep))) {
|
||||
sleeping = 1;
|
||||
sleep = drive->sleep;
|
||||
}
|
||||
} while ((drive = drive->next) != hwgroup->drive);
|
||||
if (sleeping) {
|
||||
/*
|
||||
* drive is doing pre-flush, ordered write, post-flush sequence. even
|
||||
* though that is 3 requests, it must be seen as a single transaction.
|
||||
* we must not preempt this drive until that is complete
|
||||
*/
|
||||
if (blk_queue_flushing(q))
|
||||
/*
|
||||
* Take a short snooze, and then wake up this hwgroup again.
|
||||
* This gives other hwgroups on the same a chance to
|
||||
* play fairly with us, just in case there are big differences
|
||||
* in relative throughputs.. don't want to hog the cpu too much.
|
||||
* small race where queue could get replugged during
|
||||
* the 3-request flush cycle, just yank the plug since
|
||||
* we want it to finish asap
|
||||
*/
|
||||
if (time_before(sleep, jiffies + WAIT_MIN_SLEEP))
|
||||
sleep = jiffies + WAIT_MIN_SLEEP;
|
||||
#if 1
|
||||
if (timer_pending(&hwgroup->timer))
|
||||
printk(KERN_CRIT "ide_set_handler: timer already active\n");
|
||||
#endif
|
||||
/* so that ide_timer_expiry knows what to do */
|
||||
hwgroup->sleeping = 1;
|
||||
hwgroup->req_gen_timer = hwgroup->req_gen;
|
||||
mod_timer(&hwgroup->timer, sleep);
|
||||
/* we purposely leave hwgroup->busy==1
|
||||
* while sleeping */
|
||||
} else {
|
||||
/* Ugly, but how can we sleep for the lock
|
||||
* otherwise? perhaps from tq_disk?
|
||||
*/
|
||||
blk_remove_plug(q);
|
||||
|
||||
/* for atari only */
|
||||
ide_release_lock();
|
||||
hwgroup->busy = 0;
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
spin_lock_irq(&hwgroup->lock);
|
||||
|
||||
if (!ide_lock_hwgroup(hwgroup)) {
|
||||
repeat:
|
||||
hwgroup->rq = NULL;
|
||||
|
||||
if (drive->dev_flags & IDE_DFLAG_SLEEPING) {
|
||||
if (time_before(drive->sleep, jiffies)) {
|
||||
ide_unlock_hwgroup(hwgroup);
|
||||
goto plug_device;
|
||||
}
|
||||
|
||||
/* no more work for this hwgroup (for now) */
|
||||
return;
|
||||
}
|
||||
again:
|
||||
hwif = HWIF(drive);
|
||||
|
||||
if (hwif != hwgroup->hwif) {
|
||||
/*
|
||||
* set nIEN for previous hwif, drives in the
|
||||
|
@ -852,16 +745,20 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
|
|||
hwgroup->hwif = hwif;
|
||||
hwgroup->drive = drive;
|
||||
drive->dev_flags &= ~(IDE_DFLAG_SLEEPING | IDE_DFLAG_PARKED);
|
||||
drive->service_start = jiffies;
|
||||
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
spin_lock_irq(q->queue_lock);
|
||||
/*
|
||||
* we know that the queue isn't empty, but this can happen
|
||||
* if the q->prep_rq_fn() decides to kill a request
|
||||
*/
|
||||
rq = elv_next_request(drive->queue);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
spin_lock_irq(&hwgroup->lock);
|
||||
|
||||
if (!rq) {
|
||||
hwgroup->busy = 0;
|
||||
break;
|
||||
ide_unlock_hwgroup(hwgroup);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -876,53 +773,36 @@ static void ide_do_request (ide_hwgroup_t *hwgroup, int masked_irq)
|
|||
* though. I hope that doesn't happen too much, hopefully not
|
||||
* unless the subdriver triggers such a thing in its own PM
|
||||
* state machine.
|
||||
*
|
||||
* We count how many times we loop here to make sure we service
|
||||
* all drives in the hwgroup without looping for ever
|
||||
*/
|
||||
if ((drive->dev_flags & IDE_DFLAG_BLOCKED) &&
|
||||
blk_pm_request(rq) == 0 &&
|
||||
(rq->cmd_flags & REQ_PREEMPT) == 0) {
|
||||
drive = drive->next ? drive->next : hwgroup->drive;
|
||||
if (loops++ < 4 && !blk_queue_plugged(drive->queue))
|
||||
goto again;
|
||||
/* We clear busy, there should be no pending ATA command at this point. */
|
||||
hwgroup->busy = 0;
|
||||
break;
|
||||
/* there should be no pending command at this point */
|
||||
ide_unlock_hwgroup(hwgroup);
|
||||
goto plug_device;
|
||||
}
|
||||
|
||||
hwgroup->rq = rq;
|
||||
|
||||
/*
|
||||
* Some systems have trouble with IDE IRQs arriving while
|
||||
* the driver is still setting things up. So, here we disable
|
||||
* the IRQ used by this interface while the request is being started.
|
||||
* This may look bad at first, but pretty much the same thing
|
||||
* happens anyway when any interrupt comes in, IDE or otherwise
|
||||
* -- the kernel masks the IRQ while it is being handled.
|
||||
*/
|
||||
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
|
||||
disable_irq_nosync(hwif->irq);
|
||||
spin_unlock(&hwgroup->lock);
|
||||
local_irq_enable_in_hardirq();
|
||||
/* allow other IRQs while we start this request */
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
startstop = start_request(drive, rq);
|
||||
spin_lock_irq(&hwgroup->lock);
|
||||
if (masked_irq != IDE_NO_IRQ && hwif->irq != masked_irq)
|
||||
enable_irq(hwif->irq);
|
||||
|
||||
if (startstop == ide_stopped)
|
||||
hwgroup->busy = 0;
|
||||
}
|
||||
}
|
||||
goto repeat;
|
||||
} else
|
||||
goto plug_device;
|
||||
out:
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
spin_lock_irq(q->queue_lock);
|
||||
return;
|
||||
|
||||
/*
|
||||
* Passes the stuff to ide_do_request
|
||||
*/
|
||||
void do_ide_request(struct request_queue *q)
|
||||
{
|
||||
ide_drive_t *drive = q->queuedata;
|
||||
plug_device:
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
spin_lock_irq(q->queue_lock);
|
||||
|
||||
ide_do_request(HWGROUP(drive), IDE_NO_IRQ);
|
||||
if (!elv_queue_empty(q))
|
||||
blk_plug_device(q);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -983,6 +863,17 @@ out:
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void ide_plug_device(ide_drive_t *drive)
|
||||
{
|
||||
struct request_queue *q = drive->queue;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
if (!elv_queue_empty(q))
|
||||
blk_plug_device(q);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_timer_expiry - handle lack of an IDE interrupt
|
||||
* @data: timer callback magic (hwgroup)
|
||||
|
@ -1000,10 +891,12 @@ out:
|
|||
void ide_timer_expiry (unsigned long data)
|
||||
{
|
||||
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *) data;
|
||||
ide_drive_t *uninitialized_var(drive);
|
||||
ide_handler_t *handler;
|
||||
ide_expiry_t *expiry;
|
||||
unsigned long flags;
|
||||
unsigned long wait = -1;
|
||||
int plug_device = 0;
|
||||
|
||||
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||
|
||||
|
@ -1015,22 +908,15 @@ void ide_timer_expiry (unsigned long data)
|
|||
* or we were "sleeping" to give other devices a chance.
|
||||
* Either way, we don't really want to complain about anything.
|
||||
*/
|
||||
if (hwgroup->sleeping) {
|
||||
hwgroup->sleeping = 0;
|
||||
hwgroup->busy = 0;
|
||||
}
|
||||
} else {
|
||||
ide_drive_t *drive = hwgroup->drive;
|
||||
drive = hwgroup->drive;
|
||||
if (!drive) {
|
||||
printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");
|
||||
hwgroup->handler = NULL;
|
||||
} else {
|
||||
ide_hwif_t *hwif;
|
||||
ide_startstop_t startstop = ide_stopped;
|
||||
if (!hwgroup->busy) {
|
||||
hwgroup->busy = 1; /* paranoia */
|
||||
printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);
|
||||
}
|
||||
|
||||
if ((expiry = hwgroup->expiry) != NULL) {
|
||||
/* continue */
|
||||
if ((wait = expiry(drive)) > 0) {
|
||||
|
@ -1071,15 +957,18 @@ void ide_timer_expiry (unsigned long data)
|
|||
ide_error(drive, "irq timeout",
|
||||
hwif->tp_ops->read_status(hwif));
|
||||
}
|
||||
drive->service_time = jiffies - drive->service_start;
|
||||
spin_lock_irq(&hwgroup->lock);
|
||||
enable_irq(hwif->irq);
|
||||
if (startstop == ide_stopped)
|
||||
hwgroup->busy = 0;
|
||||
if (startstop == ide_stopped) {
|
||||
ide_unlock_hwgroup(hwgroup);
|
||||
plug_device = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
ide_do_request(hwgroup, IDE_NO_IRQ);
|
||||
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||
|
||||
if (plug_device)
|
||||
ide_plug_device(drive);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1173,10 +1062,11 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
|||
unsigned long flags;
|
||||
ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;
|
||||
ide_hwif_t *hwif = hwgroup->hwif;
|
||||
ide_drive_t *drive;
|
||||
ide_drive_t *uninitialized_var(drive);
|
||||
ide_handler_t *handler;
|
||||
ide_startstop_t startstop;
|
||||
irqreturn_t irq_ret = IRQ_NONE;
|
||||
int plug_device = 0;
|
||||
|
||||
spin_lock_irqsave(&hwgroup->lock, flags);
|
||||
|
||||
|
@ -1241,10 +1131,6 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
|||
*/
|
||||
goto out;
|
||||
|
||||
if (!hwgroup->busy) {
|
||||
hwgroup->busy = 1; /* paranoia */
|
||||
printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);
|
||||
}
|
||||
hwgroup->handler = NULL;
|
||||
hwgroup->req_gen++;
|
||||
del_timer(&hwgroup->timer);
|
||||
|
@ -1267,20 +1153,22 @@ irqreturn_t ide_intr (int irq, void *dev_id)
|
|||
* same irq as is currently being serviced here, and Linux
|
||||
* won't allow another of the same (on any CPU) until we return.
|
||||
*/
|
||||
drive->service_time = jiffies - drive->service_start;
|
||||
if (startstop == ide_stopped) {
|
||||
if (hwgroup->handler == NULL) { /* paranoia */
|
||||
hwgroup->busy = 0;
|
||||
ide_do_request(hwgroup, hwif->irq);
|
||||
} else {
|
||||
printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler "
|
||||
"on exit\n", drive->name);
|
||||
}
|
||||
ide_unlock_hwgroup(hwgroup);
|
||||
plug_device = 1;
|
||||
} else
|
||||
printk(KERN_ERR "%s: %s: huh? expected NULL handler "
|
||||
"on exit\n", __func__, drive->name);
|
||||
}
|
||||
out_handled:
|
||||
irq_ret = IRQ_HANDLED;
|
||||
out:
|
||||
spin_unlock_irqrestore(&hwgroup->lock, flags);
|
||||
|
||||
if (plug_device)
|
||||
ide_plug_device(drive);
|
||||
|
||||
return irq_ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -95,8 +95,7 @@ static int ide_set_nice_ioctl(ide_drive_t *drive, unsigned long arg)
|
|||
return -EPERM;
|
||||
|
||||
if (((arg >> IDE_NICE_DSC_OVERLAP) & 1) &&
|
||||
(drive->media != ide_tape ||
|
||||
(drive->dev_flags & IDE_DFLAG_SCSI)))
|
||||
(drive->media != ide_tape))
|
||||
return -EPERM;
|
||||
|
||||
if ((arg >> IDE_NICE_DSC_OVERLAP) & 1)
|
||||
|
|
|
@ -16,16 +16,19 @@ static void issue_park_cmd(ide_drive_t *drive, unsigned long timeout)
|
|||
spin_lock_irq(&hwgroup->lock);
|
||||
if (drive->dev_flags & IDE_DFLAG_PARKED) {
|
||||
int reset_timer = time_before(timeout, drive->sleep);
|
||||
int start_queue = 0;
|
||||
|
||||
drive->sleep = timeout;
|
||||
wake_up_all(&ide_park_wq);
|
||||
if (reset_timer && hwgroup->sleeping &&
|
||||
del_timer(&hwgroup->timer)) {
|
||||
hwgroup->sleeping = 0;
|
||||
hwgroup->busy = 0;
|
||||
blk_start_queueing(q);
|
||||
}
|
||||
if (reset_timer && del_timer(&hwgroup->timer))
|
||||
start_queue = 1;
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
|
||||
if (start_queue) {
|
||||
spin_lock_irq(q->queue_lock);
|
||||
blk_start_queueing(q);
|
||||
spin_unlock_irq(q->queue_lock);
|
||||
}
|
||||
return;
|
||||
}
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
|
|
|
@ -101,6 +101,82 @@ static void ide_disk_init_mult_count(ide_drive_t *drive)
|
|||
}
|
||||
}
|
||||
|
||||
static void ide_classify_ata_dev(ide_drive_t *drive)
|
||||
{
|
||||
u16 *id = drive->id;
|
||||
char *m = (char *)&id[ATA_ID_PROD];
|
||||
int is_cfa = ata_id_is_cfa(id);
|
||||
|
||||
/* CF devices are *not* removable in Linux definition of the term */
|
||||
if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
|
||||
drive->media = ide_disk;
|
||||
|
||||
if (!ata_id_has_unload(drive->id))
|
||||
drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
|
||||
|
||||
printk(KERN_INFO "%s: %s, %s DISK drive\n", drive->name, m,
|
||||
is_cfa ? "CFA" : "ATA");
|
||||
}
|
||||
|
||||
static void ide_classify_atapi_dev(ide_drive_t *drive)
|
||||
{
|
||||
u16 *id = drive->id;
|
||||
char *m = (char *)&id[ATA_ID_PROD];
|
||||
u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
|
||||
|
||||
printk(KERN_INFO "%s: %s, ATAPI ", drive->name, m);
|
||||
switch (type) {
|
||||
case ide_floppy:
|
||||
if (!strstr(m, "CD-ROM")) {
|
||||
if (!strstr(m, "oppy") &&
|
||||
!strstr(m, "poyp") &&
|
||||
!strstr(m, "ZIP"))
|
||||
printk(KERN_CONT "cdrom or floppy?, assuming ");
|
||||
if (drive->media != ide_cdrom) {
|
||||
printk(KERN_CONT "FLOPPY");
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Early cdrom models used zero */
|
||||
type = ide_cdrom;
|
||||
case ide_cdrom:
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
#ifdef CONFIG_PPC
|
||||
/* kludge for Apple PowerBook internal zip */
|
||||
if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
|
||||
printk(KERN_CONT "FLOPPY");
|
||||
type = ide_floppy;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
printk(KERN_CONT "CD/DVD-ROM");
|
||||
break;
|
||||
case ide_tape:
|
||||
printk(KERN_CONT "TAPE");
|
||||
break;
|
||||
case ide_optical:
|
||||
printk(KERN_CONT "OPTICAL");
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_CONT "UNKNOWN (type %d)", type);
|
||||
break;
|
||||
}
|
||||
|
||||
printk(KERN_CONT " drive\n");
|
||||
drive->media = type;
|
||||
/* an ATAPI device ignores DRDY */
|
||||
drive->ready_stat = 0;
|
||||
if (ata_id_cdb_intr(id))
|
||||
drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
|
||||
drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
|
||||
/* we don't do head unloading on ATAPI devices */
|
||||
drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_identify - identify a drive
|
||||
* @drive: drive to identify
|
||||
|
@ -117,7 +193,7 @@ static void do_identify(ide_drive_t *drive, u8 cmd)
|
|||
u16 *id = drive->id;
|
||||
char *m = (char *)&id[ATA_ID_PROD];
|
||||
unsigned long flags;
|
||||
int bswap = 1, is_cfa;
|
||||
int bswap = 1;
|
||||
|
||||
/* local CPU only; some systems need this */
|
||||
local_irq_save(flags);
|
||||
|
@ -154,91 +230,23 @@ static void do_identify(ide_drive_t *drive, u8 cmd)
|
|||
if (strstr(m, "E X A B Y T E N E S T"))
|
||||
goto err_misc;
|
||||
|
||||
printk(KERN_INFO "%s: %s, ", drive->name, m);
|
||||
|
||||
drive->dev_flags |= IDE_DFLAG_PRESENT;
|
||||
drive->dev_flags &= ~IDE_DFLAG_DEAD;
|
||||
|
||||
/*
|
||||
* Check for an ATAPI device
|
||||
*/
|
||||
if (cmd == ATA_CMD_ID_ATAPI) {
|
||||
u8 type = (id[ATA_ID_CONFIG] >> 8) & 0x1f;
|
||||
|
||||
printk(KERN_CONT "ATAPI ");
|
||||
switch (type) {
|
||||
case ide_floppy:
|
||||
if (!strstr(m, "CD-ROM")) {
|
||||
if (!strstr(m, "oppy") &&
|
||||
!strstr(m, "poyp") &&
|
||||
!strstr(m, "ZIP"))
|
||||
printk(KERN_CONT "cdrom or floppy?, assuming ");
|
||||
if (drive->media != ide_cdrom) {
|
||||
printk(KERN_CONT "FLOPPY");
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/* Early cdrom models used zero */
|
||||
type = ide_cdrom;
|
||||
case ide_cdrom:
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
#ifdef CONFIG_PPC
|
||||
/* kludge for Apple PowerBook internal zip */
|
||||
if (!strstr(m, "CD-ROM") && strstr(m, "ZIP")) {
|
||||
printk(KERN_CONT "FLOPPY");
|
||||
type = ide_floppy;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
printk(KERN_CONT "CD/DVD-ROM");
|
||||
break;
|
||||
case ide_tape:
|
||||
printk(KERN_CONT "TAPE");
|
||||
break;
|
||||
case ide_optical:
|
||||
printk(KERN_CONT "OPTICAL");
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_CONT "UNKNOWN (type %d)", type);
|
||||
break;
|
||||
}
|
||||
printk(KERN_CONT " drive\n");
|
||||
drive->media = type;
|
||||
/* an ATAPI device ignores DRDY */
|
||||
drive->ready_stat = 0;
|
||||
if (ata_id_cdb_intr(id))
|
||||
drive->atapi_flags |= IDE_AFLAG_DRQ_INTERRUPT;
|
||||
drive->dev_flags |= IDE_DFLAG_DOORLOCKING;
|
||||
/* we don't do head unloading on ATAPI devices */
|
||||
drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
|
||||
return;
|
||||
}
|
||||
|
||||
if (cmd == ATA_CMD_ID_ATAPI)
|
||||
ide_classify_atapi_dev(drive);
|
||||
else
|
||||
/*
|
||||
* Not an ATAPI device: looks like a "regular" hard disk
|
||||
*/
|
||||
|
||||
is_cfa = ata_id_is_cfa(id);
|
||||
|
||||
/* CF devices are *not* removable in Linux definition of the term */
|
||||
if (is_cfa == 0 && (id[ATA_ID_CONFIG] & (1 << 7)))
|
||||
drive->dev_flags |= IDE_DFLAG_REMOVABLE;
|
||||
|
||||
drive->media = ide_disk;
|
||||
|
||||
if (!ata_id_has_unload(drive->id))
|
||||
drive->dev_flags |= IDE_DFLAG_NO_UNLOAD;
|
||||
|
||||
printk(KERN_CONT "%s DISK drive\n", is_cfa ? "CFA" : "ATA");
|
||||
|
||||
ide_classify_ata_dev(drive);
|
||||
return;
|
||||
|
||||
err_misc:
|
||||
kfree(id);
|
||||
drive->dev_flags &= ~IDE_DFLAG_PRESENT;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -641,14 +649,9 @@ static int ide_register_port(ide_hwif_t *hwif)
|
|||
/* register with global device tree */
|
||||
dev_set_name(&hwif->gendev, hwif->name);
|
||||
hwif->gendev.driver_data = hwif;
|
||||
if (hwif->gendev.parent == NULL) {
|
||||
if (hwif->dev)
|
||||
hwif->gendev.parent = hwif->dev;
|
||||
else
|
||||
/* Would like to do = &device_legacy */
|
||||
hwif->gendev.parent = NULL;
|
||||
}
|
||||
hwif->gendev.parent = hwif->dev;
|
||||
hwif->gendev.release = hwif_release_dev;
|
||||
|
||||
ret = device_register(&hwif->gendev);
|
||||
if (ret < 0) {
|
||||
printk(KERN_WARNING "IDE: %s: device_register error: %d\n",
|
||||
|
@ -878,8 +881,7 @@ static int ide_init_queue(ide_drive_t *drive)
|
|||
* do not.
|
||||
*/
|
||||
|
||||
q = blk_init_queue_node(do_ide_request, &hwif->hwgroup->lock,
|
||||
hwif_to_node(hwif));
|
||||
q = blk_init_queue_node(do_ide_request, NULL, hwif_to_node(hwif));
|
||||
if (!q)
|
||||
return 1;
|
||||
|
||||
|
@ -1139,8 +1141,6 @@ static struct kobject *ata_probe(dev_t dev, int *part, void *data)
|
|||
|
||||
if (drive->media == ide_disk)
|
||||
request_module("ide-disk");
|
||||
if (drive->dev_flags & IDE_DFLAG_SCSI)
|
||||
request_module("ide-scsi");
|
||||
if (drive->media == ide_cdrom || drive->media == ide_optical)
|
||||
request_module("ide-cd");
|
||||
if (drive->media == ide_tape)
|
||||
|
@ -1417,58 +1417,6 @@ static void ide_port_cable_detect(ide_hwif_t *hwif)
|
|||
}
|
||||
}
|
||||
|
||||
static ssize_t store_delete_devices(struct device *portdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
ide_hwif_t *hwif = dev_get_drvdata(portdev);
|
||||
|
||||
if (strncmp(buf, "1", n))
|
||||
return -EINVAL;
|
||||
|
||||
ide_port_unregister_devices(hwif);
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
|
||||
|
||||
static ssize_t store_scan(struct device *portdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
ide_hwif_t *hwif = dev_get_drvdata(portdev);
|
||||
|
||||
if (strncmp(buf, "1", n))
|
||||
return -EINVAL;
|
||||
|
||||
ide_port_unregister_devices(hwif);
|
||||
ide_port_scan(hwif);
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
|
||||
|
||||
static struct device_attribute *ide_port_attrs[] = {
|
||||
&dev_attr_delete_devices,
|
||||
&dev_attr_scan,
|
||||
NULL
|
||||
};
|
||||
|
||||
static int ide_sysfs_register_port(ide_hwif_t *hwif)
|
||||
{
|
||||
int i, uninitialized_var(rc);
|
||||
|
||||
for (i = 0; ide_port_attrs[i]; i++) {
|
||||
rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static unsigned int ide_indexes;
|
||||
|
||||
/**
|
||||
|
@ -1655,9 +1603,6 @@ int ide_host_register(struct ide_host *host, const struct ide_port_info *d,
|
|||
if (hwif == NULL)
|
||||
continue;
|
||||
|
||||
if (hwif->chipset == ide_unknown)
|
||||
hwif->chipset = ide_generic;
|
||||
|
||||
if (hwif->present)
|
||||
hwif_register_devices(hwif);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
#include <linux/kernel.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
char *ide_media_string(ide_drive_t *drive)
|
||||
{
|
||||
switch (drive->media) {
|
||||
case ide_disk:
|
||||
return "disk";
|
||||
case ide_cdrom:
|
||||
return "cdrom";
|
||||
case ide_tape:
|
||||
return "tape";
|
||||
case ide_floppy:
|
||||
return "floppy";
|
||||
case ide_optical:
|
||||
return "optical";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t media_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", ide_media_string(drive));
|
||||
}
|
||||
|
||||
static ssize_t drivename_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", drive->name);
|
||||
}
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "ide:m-%s\n", ide_media_string(drive));
|
||||
}
|
||||
|
||||
static ssize_t model_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
|
||||
}
|
||||
|
||||
static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
|
||||
}
|
||||
|
||||
static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
|
||||
}
|
||||
|
||||
struct device_attribute ide_dev_attrs[] = {
|
||||
__ATTR_RO(media),
|
||||
__ATTR_RO(drivename),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(model),
|
||||
__ATTR_RO(firmware),
|
||||
__ATTR(serial, 0400, serial_show, NULL),
|
||||
__ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static ssize_t store_delete_devices(struct device *portdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
ide_hwif_t *hwif = dev_get_drvdata(portdev);
|
||||
|
||||
if (strncmp(buf, "1", n))
|
||||
return -EINVAL;
|
||||
|
||||
ide_port_unregister_devices(hwif);
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(delete_devices, S_IWUSR, NULL, store_delete_devices);
|
||||
|
||||
static ssize_t store_scan(struct device *portdev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t n)
|
||||
{
|
||||
ide_hwif_t *hwif = dev_get_drvdata(portdev);
|
||||
|
||||
if (strncmp(buf, "1", n))
|
||||
return -EINVAL;
|
||||
|
||||
ide_port_unregister_devices(hwif);
|
||||
ide_port_scan(hwif);
|
||||
|
||||
return n;
|
||||
};
|
||||
|
||||
static DEVICE_ATTR(scan, S_IWUSR, NULL, store_scan);
|
||||
|
||||
static struct device_attribute *ide_port_attrs[] = {
|
||||
&dev_attr_delete_devices,
|
||||
&dev_attr_scan,
|
||||
NULL
|
||||
};
|
||||
|
||||
int ide_sysfs_register_port(ide_hwif_t *hwif)
|
||||
{
|
||||
int i, uninitialized_var(rc);
|
||||
|
||||
for (i = 0; ide_port_attrs[i]; i++) {
|
||||
rc = device_create_file(hwif->portdev, ide_port_attrs[i]);
|
||||
if (rc)
|
||||
break;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
|
@ -694,7 +694,7 @@ static ide_startstop_t idetape_issue_pc(ide_drive_t *drive,
|
|||
|
||||
pc->retries++;
|
||||
|
||||
return ide_issue_pc(drive, WAIT_TAPE_CMD, NULL);
|
||||
return ide_issue_pc(drive);
|
||||
}
|
||||
|
||||
/* A mode sense command is used to "sense" tape parameters. */
|
||||
|
|
|
@ -440,81 +440,13 @@ static int ide_bus_match(struct device *dev, struct device_driver *drv)
|
|||
return 1;
|
||||
}
|
||||
|
||||
static char *media_string(ide_drive_t *drive)
|
||||
{
|
||||
switch (drive->media) {
|
||||
case ide_disk:
|
||||
return "disk";
|
||||
case ide_cdrom:
|
||||
return "cdrom";
|
||||
case ide_tape:
|
||||
return "tape";
|
||||
case ide_floppy:
|
||||
return "floppy";
|
||||
case ide_optical:
|
||||
return "optical";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t media_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", media_string(drive));
|
||||
}
|
||||
|
||||
static ssize_t drivename_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", drive->name);
|
||||
}
|
||||
|
||||
static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "ide:m-%s\n", media_string(drive));
|
||||
}
|
||||
|
||||
static ssize_t model_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_PROD]);
|
||||
}
|
||||
|
||||
static ssize_t firmware_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_FW_REV]);
|
||||
}
|
||||
|
||||
static ssize_t serial_show(struct device *dev, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
return sprintf(buf, "%s\n", (char *)&drive->id[ATA_ID_SERNO]);
|
||||
}
|
||||
|
||||
static struct device_attribute ide_dev_attrs[] = {
|
||||
__ATTR_RO(media),
|
||||
__ATTR_RO(drivename),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_RO(model),
|
||||
__ATTR_RO(firmware),
|
||||
__ATTR(serial, 0400, serial_show, NULL),
|
||||
__ATTR(unload_heads, 0644, ide_park_show, ide_park_store),
|
||||
__ATTR_NULL
|
||||
};
|
||||
|
||||
static int ide_uevent(struct device *dev, struct kobj_uevent_env *env)
|
||||
{
|
||||
ide_drive_t *drive = to_ide_device(dev);
|
||||
|
||||
add_uevent_var(env, "MEDIA=%s", media_string(drive));
|
||||
add_uevent_var(env, "MEDIA=%s", ide_media_string(drive));
|
||||
add_uevent_var(env, "DRIVENAME=%s", drive->name);
|
||||
add_uevent_var(env, "MODALIAS=ide:m-%s", media_string(drive));
|
||||
add_uevent_var(env, "MODALIAS=ide:m-%s", ide_media_string(drive));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -216,16 +216,17 @@ static const struct ide_tp_ops tx4938ide_tp_ops = {
|
|||
#endif /* __BIG_ENDIAN */
|
||||
|
||||
static const struct ide_port_ops tx4938ide_port_ops = {
|
||||
.set_pio_mode = tx4938ide_set_pio_mode,
|
||||
.set_pio_mode = tx4938ide_set_pio_mode,
|
||||
};
|
||||
|
||||
static const struct ide_port_info tx4938ide_port_info __initdata = {
|
||||
.port_ops = &tx4938ide_port_ops,
|
||||
.port_ops = &tx4938ide_port_ops,
|
||||
#ifdef __BIG_ENDIAN
|
||||
.tp_ops = &tx4938ide_tp_ops,
|
||||
.tp_ops = &tx4938ide_tp_ops,
|
||||
#endif
|
||||
.host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
|
||||
.pio_mask = ATA_PIO5,
|
||||
.host_flags = IDE_HFLAG_MMIO | IDE_HFLAG_NO_DMA,
|
||||
.pio_mask = ATA_PIO5,
|
||||
.chipset = ide_generic,
|
||||
};
|
||||
|
||||
static int __init tx4938ide_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -623,33 +623,34 @@ static const struct ide_tp_ops tx4939ide_tp_ops = {
|
|||
#endif /* __LITTLE_ENDIAN */
|
||||
|
||||
static const struct ide_port_ops tx4939ide_port_ops = {
|
||||
.set_pio_mode = tx4939ide_set_pio_mode,
|
||||
.set_dma_mode = tx4939ide_set_dma_mode,
|
||||
.clear_irq = tx4939ide_clear_irq,
|
||||
.cable_detect = tx4939ide_cable_detect,
|
||||
.set_pio_mode = tx4939ide_set_pio_mode,
|
||||
.set_dma_mode = tx4939ide_set_dma_mode,
|
||||
.clear_irq = tx4939ide_clear_irq,
|
||||
.cable_detect = tx4939ide_cable_detect,
|
||||
};
|
||||
|
||||
static const struct ide_dma_ops tx4939ide_dma_ops = {
|
||||
.dma_host_set = tx4939ide_dma_host_set,
|
||||
.dma_setup = tx4939ide_dma_setup,
|
||||
.dma_exec_cmd = ide_dma_exec_cmd,
|
||||
.dma_start = ide_dma_start,
|
||||
.dma_end = tx4939ide_dma_end,
|
||||
.dma_test_irq = tx4939ide_dma_test_irq,
|
||||
.dma_lost_irq = ide_dma_lost_irq,
|
||||
.dma_timeout = ide_dma_timeout,
|
||||
.dma_host_set = tx4939ide_dma_host_set,
|
||||
.dma_setup = tx4939ide_dma_setup,
|
||||
.dma_exec_cmd = ide_dma_exec_cmd,
|
||||
.dma_start = ide_dma_start,
|
||||
.dma_end = tx4939ide_dma_end,
|
||||
.dma_test_irq = tx4939ide_dma_test_irq,
|
||||
.dma_lost_irq = ide_dma_lost_irq,
|
||||
.dma_timeout = ide_dma_timeout,
|
||||
};
|
||||
|
||||
static const struct ide_port_info tx4939ide_port_info __initdata = {
|
||||
.init_hwif = tx4939ide_init_hwif,
|
||||
.init_dma = tx4939ide_init_dma,
|
||||
.port_ops = &tx4939ide_port_ops,
|
||||
.dma_ops = &tx4939ide_dma_ops,
|
||||
.tp_ops = &tx4939ide_tp_ops,
|
||||
.host_flags = IDE_HFLAG_MMIO,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
.init_hwif = tx4939ide_init_hwif,
|
||||
.init_dma = tx4939ide_init_dma,
|
||||
.port_ops = &tx4939ide_port_ops,
|
||||
.dma_ops = &tx4939ide_dma_ops,
|
||||
.tp_ops = &tx4939ide_tp_ops,
|
||||
.host_flags = IDE_HFLAG_MMIO,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
.chipset = ide_generic,
|
||||
};
|
||||
|
||||
static int __init tx4939ide_probe(struct platform_device *pdev)
|
||||
|
|
|
@ -21,7 +21,7 @@ config SCSI
|
|||
You also need to say Y here if you have a device which speaks
|
||||
the SCSI protocol. Examples of this include the parallel port
|
||||
version of the IOMEGA ZIP drive, USB storage devices, Fibre
|
||||
Channel, FireWire storage and the IDE-SCSI emulation driver.
|
||||
Channel, and FireWire storage.
|
||||
|
||||
To compile this driver as a module, choose M here and read
|
||||
<file:Documentation/scsi/scsi.txt>.
|
||||
|
@ -101,9 +101,9 @@ config CHR_DEV_OSST
|
|||
---help---
|
||||
The OnStream SC-x0 SCSI tape drives cannot be driven by the
|
||||
standard st driver, but instead need this special osst driver and
|
||||
use the /dev/osstX char device nodes (major 206). Via usb-storage
|
||||
and ide-scsi, you may be able to drive the USB-x0 and DI-x0 drives
|
||||
as well. Note that there is also a second generation of OnStream
|
||||
use the /dev/osstX char device nodes (major 206). Via usb-storage,
|
||||
you may be able to drive the USB-x0 and DI-x0 drives as well.
|
||||
Note that there is also a second generation of OnStream
|
||||
tape drives (ADR-x0) that supports the standard SCSI-2 commands for
|
||||
tapes (QIC-157) and can be driven by the standard driver st.
|
||||
For more information, you may have a look at the SCSI-HOWTO
|
||||
|
|
|
@ -105,7 +105,6 @@ obj-$(CONFIG_SCSI_GDTH) += gdth.o
|
|||
obj-$(CONFIG_SCSI_INITIO) += initio.o
|
||||
obj-$(CONFIG_SCSI_INIA100) += a100u2w.o
|
||||
obj-$(CONFIG_SCSI_QLOGICPTI) += qlogicpti.o
|
||||
obj-$(CONFIG_BLK_DEV_IDESCSI) += ide-scsi.o
|
||||
obj-$(CONFIG_SCSI_MESH) += mesh.o
|
||||
obj-$(CONFIG_SCSI_MAC53C94) += mac53c94.o
|
||||
obj-$(CONFIG_BLK_DEV_3W_XXXX_RAID) += 3w-xxxx.o
|
||||
|
|
|
@ -1,840 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 1996-1999 Gadi Oxman <gadio@netvision.net.il>
|
||||
* Copyright (C) 2004-2005 Bartlomiej Zolnierkiewicz
|
||||
*/
|
||||
|
||||
/*
|
||||
* Emulation of a SCSI host adapter for IDE ATAPI devices.
|
||||
*
|
||||
* With this driver, one can use the Linux SCSI drivers instead of the
|
||||
* native IDE ATAPI drivers.
|
||||
*
|
||||
* Ver 0.1 Dec 3 96 Initial version.
|
||||
* Ver 0.2 Jan 26 97 Fixed bug in cleanup_module() and added emulation
|
||||
* of MODE_SENSE_6/MODE_SELECT_6 for cdroms. Thanks
|
||||
* to Janos Farkas for pointing this out.
|
||||
* Avoid using bitfields in structures for m68k.
|
||||
* Added Scatter/Gather and DMA support.
|
||||
* Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives.
|
||||
* Use variable timeout for each command.
|
||||
* Ver 0.5 Jan 2 98 Fix previous PD/CD support.
|
||||
* Allow disabling of SCSI-6 to SCSI-10 transformation.
|
||||
* Ver 0.6 Jan 27 98 Allow disabling of SCSI command translation layer
|
||||
* for access through /dev/sg.
|
||||
* Fix MODE_SENSE_6/MODE_SELECT_6/INQUIRY translation.
|
||||
* Ver 0.7 Dec 04 98 Ignore commands where lun != 0 to avoid multiple
|
||||
* detection of devices with CONFIG_SCSI_MULTI_LUN
|
||||
* Ver 0.8 Feb 05 99 Optical media need translation too. Reverse 0.7.
|
||||
* Ver 0.9 Jul 04 99 Fix a bug in SG_SET_TRANSFORM.
|
||||
* Ver 0.91 Jun 10 02 Fix "off by one" error in transforms
|
||||
* Ver 0.92 Dec 31 02 Implement new SCSI mid level API
|
||||
*/
|
||||
|
||||
#define IDESCSI_VERSION "0.92"
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/ioport.h>
|
||||
#include <linux/blkdev.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/bitops.h>
|
||||
|
||||
#include <asm/io.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
#include <scsi/scsi.h>
|
||||
#include <scsi/scsi_cmnd.h>
|
||||
#include <scsi/scsi_device.h>
|
||||
#include <scsi/scsi_host.h>
|
||||
#include <scsi/scsi_tcq.h>
|
||||
#include <scsi/sg.h>
|
||||
|
||||
#define IDESCSI_DEBUG_LOG 0
|
||||
|
||||
#if IDESCSI_DEBUG_LOG
|
||||
#define debug_log(fmt, args...) \
|
||||
printk(KERN_INFO "ide-scsi: " fmt, ## args)
|
||||
#else
|
||||
#define debug_log(fmt, args...) do {} while (0)
|
||||
#endif
|
||||
|
||||
/*
|
||||
* SCSI command transformation layer
|
||||
*/
|
||||
#define IDESCSI_SG_TRANSFORM 1 /* /dev/sg transformation */
|
||||
|
||||
/*
|
||||
* Log flags
|
||||
*/
|
||||
#define IDESCSI_LOG_CMD 0 /* Log SCSI commands */
|
||||
|
||||
typedef struct ide_scsi_obj {
|
||||
ide_drive_t *drive;
|
||||
ide_driver_t *driver;
|
||||
struct gendisk *disk;
|
||||
struct Scsi_Host *host;
|
||||
|
||||
unsigned long transform; /* SCSI cmd translation layer */
|
||||
unsigned long log; /* log flags */
|
||||
} idescsi_scsi_t;
|
||||
|
||||
static DEFINE_MUTEX(idescsi_ref_mutex);
|
||||
/* Set by module param to skip cd */
|
||||
static int idescsi_nocd;
|
||||
|
||||
#define ide_scsi_g(disk) \
|
||||
container_of((disk)->private_data, struct ide_scsi_obj, driver)
|
||||
|
||||
static struct ide_scsi_obj *ide_scsi_get(struct gendisk *disk)
|
||||
{
|
||||
struct ide_scsi_obj *scsi = NULL;
|
||||
|
||||
mutex_lock(&idescsi_ref_mutex);
|
||||
scsi = ide_scsi_g(disk);
|
||||
if (scsi) {
|
||||
if (ide_device_get(scsi->drive))
|
||||
scsi = NULL;
|
||||
else
|
||||
scsi_host_get(scsi->host);
|
||||
}
|
||||
mutex_unlock(&idescsi_ref_mutex);
|
||||
return scsi;
|
||||
}
|
||||
|
||||
static void ide_scsi_put(struct ide_scsi_obj *scsi)
|
||||
{
|
||||
ide_drive_t *drive = scsi->drive;
|
||||
|
||||
mutex_lock(&idescsi_ref_mutex);
|
||||
scsi_host_put(scsi->host);
|
||||
ide_device_put(drive);
|
||||
mutex_unlock(&idescsi_ref_mutex);
|
||||
}
|
||||
|
||||
static inline idescsi_scsi_t *scsihost_to_idescsi(struct Scsi_Host *host)
|
||||
{
|
||||
return (idescsi_scsi_t*) (&host[1]);
|
||||
}
|
||||
|
||||
static inline idescsi_scsi_t *drive_to_idescsi(ide_drive_t *ide_drive)
|
||||
{
|
||||
return scsihost_to_idescsi(ide_drive->driver_data);
|
||||
}
|
||||
|
||||
static void ide_scsi_hex_dump(u8 *data, int len)
|
||||
{
|
||||
print_hex_dump(KERN_CONT, "", DUMP_PREFIX_NONE, 16, 1, data, len, 0);
|
||||
}
|
||||
|
||||
static int idescsi_end_request(ide_drive_t *, int, int);
|
||||
|
||||
static void ide_scsi_callback(ide_drive_t *drive, int dsc)
|
||||
{
|
||||
idescsi_scsi_t *scsi = drive_to_idescsi(drive);
|
||||
struct ide_atapi_pc *pc = drive->pc;
|
||||
|
||||
if (pc->flags & PC_FLAG_TIMEDOUT)
|
||||
debug_log("%s: got timed out packet %lu at %lu\n", __func__,
|
||||
pc->scsi_cmd->serial_number, jiffies);
|
||||
/* end this request now - scsi should retry it*/
|
||||
else if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||
printk(KERN_INFO "Packet command completed, %d bytes"
|
||||
" transferred\n", pc->xferred);
|
||||
|
||||
idescsi_end_request(drive, 1, 0);
|
||||
}
|
||||
|
||||
static int idescsi_check_condition(ide_drive_t *drive,
|
||||
struct request *failed_cmd)
|
||||
{
|
||||
idescsi_scsi_t *scsi = drive_to_idescsi(drive);
|
||||
struct ide_atapi_pc *pc;
|
||||
struct request *rq;
|
||||
u8 *buf;
|
||||
|
||||
/* stuff a sense request in front of our current request */
|
||||
pc = kzalloc(sizeof(struct ide_atapi_pc), GFP_ATOMIC);
|
||||
rq = blk_get_request(drive->queue, READ, GFP_ATOMIC);
|
||||
buf = kzalloc(SCSI_SENSE_BUFFERSIZE, GFP_ATOMIC);
|
||||
if (!pc || !rq || !buf) {
|
||||
kfree(buf);
|
||||
if (rq)
|
||||
blk_put_request(rq);
|
||||
kfree(pc);
|
||||
return -ENOMEM;
|
||||
}
|
||||
rq->special = (char *) pc;
|
||||
pc->rq = rq;
|
||||
pc->buf = buf;
|
||||
pc->c[0] = REQUEST_SENSE;
|
||||
pc->c[4] = pc->req_xfer = pc->buf_size = SCSI_SENSE_BUFFERSIZE;
|
||||
rq->cmd_type = REQ_TYPE_SENSE;
|
||||
rq->cmd_flags |= REQ_PREEMPT;
|
||||
pc->timeout = jiffies + WAIT_READY;
|
||||
/* NOTE! Save the failed packet command in "rq->buffer" */
|
||||
rq->buffer = (void *) failed_cmd->special;
|
||||
pc->scsi_cmd = ((struct ide_atapi_pc *) failed_cmd->special)->scsi_cmd;
|
||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
|
||||
printk ("ide-scsi: %s: queue cmd = ", drive->name);
|
||||
ide_scsi_hex_dump(pc->c, 6);
|
||||
}
|
||||
rq->rq_disk = scsi->disk;
|
||||
rq->ref_count++;
|
||||
memcpy(rq->cmd, pc->c, 12);
|
||||
ide_do_drive_cmd(drive, rq);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ide_startstop_t
|
||||
idescsi_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
|
||||
/* force an abort */
|
||||
hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
|
||||
|
||||
rq->errors++;
|
||||
|
||||
idescsi_end_request(drive, 0, 0);
|
||||
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static int idescsi_end_request (ide_drive_t *drive, int uptodate, int nrsecs)
|
||||
{
|
||||
idescsi_scsi_t *scsi = drive_to_idescsi(drive);
|
||||
struct request *rq = HWGROUP(drive)->rq;
|
||||
struct ide_atapi_pc *pc = (struct ide_atapi_pc *) rq->special;
|
||||
int log = test_bit(IDESCSI_LOG_CMD, &scsi->log);
|
||||
struct Scsi_Host *host;
|
||||
int errors = rq->errors;
|
||||
unsigned long flags;
|
||||
|
||||
if (!blk_special_request(rq) && !blk_sense_request(rq)) {
|
||||
ide_end_request(drive, uptodate, nrsecs);
|
||||
return 0;
|
||||
}
|
||||
ide_end_drive_cmd (drive, 0, 0);
|
||||
if (blk_sense_request(rq)) {
|
||||
struct ide_atapi_pc *opc = (struct ide_atapi_pc *) rq->buffer;
|
||||
if (log) {
|
||||
printk ("ide-scsi: %s: wrap up check %lu, rst = ", drive->name, opc->scsi_cmd->serial_number);
|
||||
ide_scsi_hex_dump(pc->buf, 16);
|
||||
}
|
||||
memcpy((void *) opc->scsi_cmd->sense_buffer, pc->buf,
|
||||
SCSI_SENSE_BUFFERSIZE);
|
||||
kfree(pc->buf);
|
||||
kfree(pc);
|
||||
blk_put_request(rq);
|
||||
pc = opc;
|
||||
rq = pc->rq;
|
||||
pc->scsi_cmd->result = (CHECK_CONDITION << 1) |
|
||||
(((pc->flags & PC_FLAG_TIMEDOUT) ?
|
||||
DID_TIME_OUT :
|
||||
DID_OK) << 16);
|
||||
} else if (pc->flags & PC_FLAG_TIMEDOUT) {
|
||||
if (log)
|
||||
printk (KERN_WARNING "ide-scsi: %s: timed out for %lu\n",
|
||||
drive->name, pc->scsi_cmd->serial_number);
|
||||
pc->scsi_cmd->result = DID_TIME_OUT << 16;
|
||||
} else if (errors >= ERROR_MAX) {
|
||||
pc->scsi_cmd->result = DID_ERROR << 16;
|
||||
if (log)
|
||||
printk ("ide-scsi: %s: I/O error for %lu\n", drive->name, pc->scsi_cmd->serial_number);
|
||||
} else if (errors) {
|
||||
if (log)
|
||||
printk ("ide-scsi: %s: check condition for %lu\n", drive->name, pc->scsi_cmd->serial_number);
|
||||
if (!idescsi_check_condition(drive, rq))
|
||||
/* we started a request sense, so we'll be back, exit for now */
|
||||
return 0;
|
||||
pc->scsi_cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16);
|
||||
} else {
|
||||
pc->scsi_cmd->result = DID_OK << 16;
|
||||
}
|
||||
host = pc->scsi_cmd->device->host;
|
||||
spin_lock_irqsave(host->host_lock, flags);
|
||||
pc->done(pc->scsi_cmd);
|
||||
spin_unlock_irqrestore(host->host_lock, flags);
|
||||
kfree(pc);
|
||||
blk_put_request(rq);
|
||||
drive->pc = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int idescsi_set_direction(struct ide_atapi_pc *pc)
|
||||
{
|
||||
switch (pc->c[0]) {
|
||||
case READ_6: case READ_10: case READ_12:
|
||||
pc->flags &= ~PC_FLAG_WRITING;
|
||||
return 0;
|
||||
case WRITE_6: case WRITE_10: case WRITE_12:
|
||||
pc->flags |= PC_FLAG_WRITING;
|
||||
return 0;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
static int idescsi_map_sg(ide_drive_t *drive, struct ide_atapi_pc *pc)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct scatterlist *sg, *scsi_sg;
|
||||
int segments;
|
||||
|
||||
if (!pc->req_xfer || pc->req_xfer % 1024)
|
||||
return 1;
|
||||
|
||||
if (idescsi_set_direction(pc))
|
||||
return 1;
|
||||
|
||||
sg = hwif->sg_table;
|
||||
scsi_sg = scsi_sglist(pc->scsi_cmd);
|
||||
segments = scsi_sg_count(pc->scsi_cmd);
|
||||
|
||||
if (segments > hwif->sg_max_nents)
|
||||
return 1;
|
||||
|
||||
hwif->sg_nents = segments;
|
||||
memcpy(sg, scsi_sg, sizeof(*sg) * segments);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ide_startstop_t idescsi_issue_pc(ide_drive_t *drive,
|
||||
struct ide_atapi_pc *pc)
|
||||
{
|
||||
/* Set the current packet command */
|
||||
drive->pc = pc;
|
||||
|
||||
return ide_issue_pc(drive, ide_scsi_get_timeout(pc), ide_scsi_expiry);
|
||||
}
|
||||
|
||||
/*
|
||||
* idescsi_do_request is our request handling function.
|
||||
*/
|
||||
static ide_startstop_t idescsi_do_request (ide_drive_t *drive, struct request *rq, sector_t block)
|
||||
{
|
||||
debug_log("dev: %s, cmd: %x, errors: %d\n", rq->rq_disk->disk_name,
|
||||
rq->cmd[0], rq->errors);
|
||||
debug_log("sector: %ld, nr_sectors: %ld, current_nr_sectors: %d\n",
|
||||
rq->sector, rq->nr_sectors, rq->current_nr_sectors);
|
||||
|
||||
if (blk_sense_request(rq) || blk_special_request(rq)) {
|
||||
struct ide_atapi_pc *pc = (struct ide_atapi_pc *)rq->special;
|
||||
|
||||
if ((drive->dev_flags & IDE_DFLAG_USING_DMA) &&
|
||||
idescsi_map_sg(drive, pc) == 0)
|
||||
pc->flags |= PC_FLAG_DMA_OK;
|
||||
|
||||
return idescsi_issue_pc(drive, pc);
|
||||
}
|
||||
blk_dump_rq_flags(rq, "ide-scsi: unsup command");
|
||||
idescsi_end_request (drive, 0, 0);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IDE_PROC_FS
|
||||
static ide_proc_entry_t idescsi_proc[] = {
|
||||
{ "capacity", S_IFREG|S_IRUGO, proc_ide_read_capacity, NULL },
|
||||
{ NULL, 0, NULL, NULL }
|
||||
};
|
||||
|
||||
#define ide_scsi_devset_get(name, field) \
|
||||
static int get_##name(ide_drive_t *drive) \
|
||||
{ \
|
||||
idescsi_scsi_t *scsi = drive_to_idescsi(drive); \
|
||||
return scsi->field; \
|
||||
}
|
||||
|
||||
#define ide_scsi_devset_set(name, field) \
|
||||
static int set_##name(ide_drive_t *drive, int arg) \
|
||||
{ \
|
||||
idescsi_scsi_t *scsi = drive_to_idescsi(drive); \
|
||||
scsi->field = arg; \
|
||||
return 0; \
|
||||
}
|
||||
|
||||
#define ide_scsi_devset_rw_field(_name, _field) \
|
||||
ide_scsi_devset_get(_name, _field); \
|
||||
ide_scsi_devset_set(_name, _field); \
|
||||
IDE_DEVSET(_name, DS_SYNC, get_##_name, set_##_name);
|
||||
|
||||
ide_devset_rw_field(bios_cyl, bios_cyl);
|
||||
ide_devset_rw_field(bios_head, bios_head);
|
||||
ide_devset_rw_field(bios_sect, bios_sect);
|
||||
|
||||
ide_scsi_devset_rw_field(transform, transform);
|
||||
ide_scsi_devset_rw_field(log, log);
|
||||
|
||||
static const struct ide_proc_devset idescsi_settings[] = {
|
||||
IDE_PROC_DEVSET(bios_cyl, 0, 1023),
|
||||
IDE_PROC_DEVSET(bios_head, 0, 255),
|
||||
IDE_PROC_DEVSET(bios_sect, 0, 63),
|
||||
IDE_PROC_DEVSET(log, 0, 1),
|
||||
IDE_PROC_DEVSET(transform, 0, 3),
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static ide_proc_entry_t *ide_scsi_proc_entries(ide_drive_t *drive)
|
||||
{
|
||||
return idescsi_proc;
|
||||
}
|
||||
|
||||
static const struct ide_proc_devset *ide_scsi_proc_devsets(ide_drive_t *drive)
|
||||
{
|
||||
return idescsi_settings;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Driver initialization.
|
||||
*/
|
||||
static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi)
|
||||
{
|
||||
clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
|
||||
#if IDESCSI_DEBUG_LOG
|
||||
set_bit(IDESCSI_LOG_CMD, &scsi->log);
|
||||
#endif /* IDESCSI_DEBUG_LOG */
|
||||
|
||||
drive->pc_callback = ide_scsi_callback;
|
||||
drive->pc_update_buffers = NULL;
|
||||
drive->pc_io_buffers = ide_io_buffers;
|
||||
|
||||
ide_proc_register_driver(drive, scsi->driver);
|
||||
}
|
||||
|
||||
static void ide_scsi_remove(ide_drive_t *drive)
|
||||
{
|
||||
struct Scsi_Host *scsihost = drive->driver_data;
|
||||
struct ide_scsi_obj *scsi = scsihost_to_idescsi(scsihost);
|
||||
struct gendisk *g = scsi->disk;
|
||||
|
||||
scsi_remove_host(scsihost);
|
||||
ide_proc_unregister_driver(drive, scsi->driver);
|
||||
|
||||
ide_unregister_region(g);
|
||||
|
||||
drive->driver_data = NULL;
|
||||
g->private_data = NULL;
|
||||
put_disk(g);
|
||||
|
||||
ide_scsi_put(scsi);
|
||||
|
||||
drive->dev_flags &= ~IDE_DFLAG_SCSI;
|
||||
}
|
||||
|
||||
static int ide_scsi_probe(ide_drive_t *);
|
||||
|
||||
static ide_driver_t idescsi_driver = {
|
||||
.gen_driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = "ide-scsi",
|
||||
.bus = &ide_bus_type,
|
||||
},
|
||||
.probe = ide_scsi_probe,
|
||||
.remove = ide_scsi_remove,
|
||||
.version = IDESCSI_VERSION,
|
||||
.do_request = idescsi_do_request,
|
||||
.end_request = idescsi_end_request,
|
||||
.error = idescsi_atapi_error,
|
||||
#ifdef CONFIG_IDE_PROC_FS
|
||||
.proc_entries = ide_scsi_proc_entries,
|
||||
.proc_devsets = ide_scsi_proc_devsets,
|
||||
#endif
|
||||
};
|
||||
|
||||
static int idescsi_ide_open(struct block_device *bdev, fmode_t mode)
|
||||
{
|
||||
struct ide_scsi_obj *scsi = ide_scsi_get(bdev->bd_disk);
|
||||
|
||||
if (!scsi)
|
||||
return -ENXIO;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idescsi_ide_release(struct gendisk *disk, fmode_t mode)
|
||||
{
|
||||
ide_scsi_put(ide_scsi_g(disk));
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idescsi_ide_ioctl(struct block_device *bdev, fmode_t mode,
|
||||
unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
struct ide_scsi_obj *scsi = ide_scsi_g(bdev->bd_disk);
|
||||
return generic_ide_ioctl(scsi->drive, bdev, cmd, arg);
|
||||
}
|
||||
|
||||
static struct block_device_operations idescsi_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = idescsi_ide_open,
|
||||
.release = idescsi_ide_release,
|
||||
.locked_ioctl = idescsi_ide_ioctl,
|
||||
};
|
||||
|
||||
static int idescsi_slave_configure(struct scsi_device * sdp)
|
||||
{
|
||||
/* Configure detected device */
|
||||
sdp->use_10_for_rw = 1;
|
||||
sdp->use_10_for_ms = 1;
|
||||
scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, sdp->host->cmd_per_lun);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *idescsi_info (struct Scsi_Host *host)
|
||||
{
|
||||
return "SCSI host adapter emulation for IDE ATAPI devices";
|
||||
}
|
||||
|
||||
static int idescsi_ioctl (struct scsi_device *dev, int cmd, void __user *arg)
|
||||
{
|
||||
idescsi_scsi_t *scsi = scsihost_to_idescsi(dev->host);
|
||||
|
||||
if (cmd == SG_SET_TRANSFORM) {
|
||||
if (arg)
|
||||
set_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
|
||||
else
|
||||
clear_bit(IDESCSI_SG_TRANSFORM, &scsi->transform);
|
||||
return 0;
|
||||
} else if (cmd == SG_GET_TRANSFORM)
|
||||
return put_user(test_bit(IDESCSI_SG_TRANSFORM, &scsi->transform), (int __user *) arg);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int idescsi_queue (struct scsi_cmnd *cmd,
|
||||
void (*done)(struct scsi_cmnd *))
|
||||
{
|
||||
struct Scsi_Host *host = cmd->device->host;
|
||||
idescsi_scsi_t *scsi = scsihost_to_idescsi(host);
|
||||
ide_drive_t *drive = scsi->drive;
|
||||
struct request *rq = NULL;
|
||||
struct ide_atapi_pc *pc = NULL;
|
||||
int write = cmd->sc_data_direction == DMA_TO_DEVICE;
|
||||
|
||||
if (!drive) {
|
||||
scmd_printk (KERN_ERR, cmd, "drive not present\n");
|
||||
goto abort;
|
||||
}
|
||||
scsi = drive_to_idescsi(drive);
|
||||
pc = kmalloc(sizeof(struct ide_atapi_pc), GFP_ATOMIC);
|
||||
rq = blk_get_request(drive->queue, write, GFP_ATOMIC);
|
||||
if (rq == NULL || pc == NULL) {
|
||||
printk (KERN_ERR "ide-scsi: %s: out of memory\n", drive->name);
|
||||
goto abort;
|
||||
}
|
||||
|
||||
memset (pc->c, 0, 12);
|
||||
pc->flags = 0;
|
||||
if (cmd->sc_data_direction == DMA_TO_DEVICE)
|
||||
pc->flags |= PC_FLAG_WRITING;
|
||||
pc->rq = rq;
|
||||
memcpy (pc->c, cmd->cmnd, cmd->cmd_len);
|
||||
pc->buf = NULL;
|
||||
pc->sg = scsi_sglist(cmd);
|
||||
pc->sg_cnt = scsi_sg_count(cmd);
|
||||
pc->b_count = 0;
|
||||
pc->req_xfer = pc->buf_size = scsi_bufflen(cmd);
|
||||
pc->scsi_cmd = cmd;
|
||||
pc->done = done;
|
||||
pc->timeout = jiffies + cmd->request->timeout;
|
||||
|
||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log)) {
|
||||
printk ("ide-scsi: %s: que %lu, cmd = ", drive->name, cmd->serial_number);
|
||||
ide_scsi_hex_dump(cmd->cmnd, cmd->cmd_len);
|
||||
if (memcmp(pc->c, cmd->cmnd, cmd->cmd_len)) {
|
||||
printk ("ide-scsi: %s: que %lu, tsl = ", drive->name, cmd->serial_number);
|
||||
ide_scsi_hex_dump(pc->c, 12);
|
||||
}
|
||||
}
|
||||
|
||||
rq->special = (char *) pc;
|
||||
rq->cmd_type = REQ_TYPE_SPECIAL;
|
||||
spin_unlock_irq(host->host_lock);
|
||||
rq->ref_count++;
|
||||
memcpy(rq->cmd, pc->c, 12);
|
||||
blk_execute_rq_nowait(drive->queue, scsi->disk, rq, 0, NULL);
|
||||
spin_lock_irq(host->host_lock);
|
||||
return 0;
|
||||
abort:
|
||||
kfree (pc);
|
||||
if (rq)
|
||||
blk_put_request(rq);
|
||||
cmd->result = DID_ERROR << 16;
|
||||
done(cmd);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int idescsi_eh_abort (struct scsi_cmnd *cmd)
|
||||
{
|
||||
idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
|
||||
ide_drive_t *drive = scsi->drive;
|
||||
ide_hwif_t *hwif;
|
||||
ide_hwgroup_t *hwgroup;
|
||||
int busy;
|
||||
int ret = FAILED;
|
||||
|
||||
struct ide_atapi_pc *pc;
|
||||
|
||||
/* In idescsi_eh_abort we try to gently pry our command from the ide subsystem */
|
||||
|
||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||
printk (KERN_WARNING "ide-scsi: abort called for %lu\n", cmd->serial_number);
|
||||
|
||||
if (!drive) {
|
||||
printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_abort\n");
|
||||
WARN_ON(1);
|
||||
goto no_drive;
|
||||
}
|
||||
|
||||
hwif = drive->hwif;
|
||||
hwgroup = hwif->hwgroup;
|
||||
|
||||
/* First give it some more time, how much is "right" is hard to say :-(
|
||||
FIXME - uses mdelay which causes latency? */
|
||||
busy = ide_wait_not_busy(hwif, 100);
|
||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||
printk (KERN_WARNING "ide-scsi: drive did%s become ready\n", busy?" not":"");
|
||||
|
||||
spin_lock_irq(&hwgroup->lock);
|
||||
|
||||
/* If there is no pc running we're done (our interrupt took care of it) */
|
||||
pc = drive->pc;
|
||||
if (pc == NULL) {
|
||||
ret = SUCCESS;
|
||||
goto ide_unlock;
|
||||
}
|
||||
|
||||
/* It's somewhere in flight. Does ide subsystem agree? */
|
||||
if (pc->scsi_cmd->serial_number == cmd->serial_number && !busy &&
|
||||
elv_queue_empty(drive->queue) && HWGROUP(drive)->rq != pc->rq) {
|
||||
/*
|
||||
* FIXME - not sure this condition can ever occur
|
||||
*/
|
||||
printk (KERN_ERR "ide-scsi: cmd aborted!\n");
|
||||
|
||||
if (blk_sense_request(pc->rq))
|
||||
kfree(pc->buf);
|
||||
/* we need to call blk_put_request twice. */
|
||||
blk_put_request(pc->rq);
|
||||
blk_put_request(pc->rq);
|
||||
kfree(pc);
|
||||
drive->pc = NULL;
|
||||
|
||||
ret = SUCCESS;
|
||||
}
|
||||
|
||||
ide_unlock:
|
||||
spin_unlock_irq(&hwgroup->lock);
|
||||
no_drive:
|
||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||
printk (KERN_WARNING "ide-scsi: abort returns %s\n", ret == SUCCESS?"success":"failed");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int idescsi_eh_reset (struct scsi_cmnd *cmd)
|
||||
{
|
||||
struct request *req;
|
||||
idescsi_scsi_t *scsi = scsihost_to_idescsi(cmd->device->host);
|
||||
ide_drive_t *drive = scsi->drive;
|
||||
ide_hwgroup_t *hwgroup;
|
||||
int ready = 0;
|
||||
int ret = SUCCESS;
|
||||
|
||||
struct ide_atapi_pc *pc;
|
||||
|
||||
/* In idescsi_eh_reset we forcefully remove the command from the ide subsystem and reset the device. */
|
||||
|
||||
if (test_bit(IDESCSI_LOG_CMD, &scsi->log))
|
||||
printk (KERN_WARNING "ide-scsi: reset called for %lu\n", cmd->serial_number);
|
||||
|
||||
if (!drive) {
|
||||
printk (KERN_WARNING "ide-scsi: Drive not set in idescsi_eh_reset\n");
|
||||
WARN_ON(1);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
hwgroup = drive->hwif->hwgroup;
|
||||
|
||||
spin_lock_irq(cmd->device->host->host_lock);
|
||||
spin_lock(&hwgroup->lock);
|
||||
|
||||
pc = drive->pc;
|
||||
if (pc)
|
||||
req = pc->rq;
|
||||
|
||||
if (pc == NULL || req != hwgroup->rq || hwgroup->handler == NULL) {
|
||||
printk (KERN_WARNING "ide-scsi: No active request in idescsi_eh_reset\n");
|
||||
spin_unlock(&hwgroup->lock);
|
||||
spin_unlock_irq(cmd->device->host->host_lock);
|
||||
return FAILED;
|
||||
}
|
||||
|
||||
/* kill current request */
|
||||
if (__blk_end_request(req, -EIO, 0))
|
||||
BUG();
|
||||
if (blk_sense_request(req))
|
||||
kfree(pc->buf);
|
||||
kfree(pc);
|
||||
drive->pc = NULL;
|
||||
blk_put_request(req);
|
||||
|
||||
/* now nuke the drive queue */
|
||||
while ((req = elv_next_request(drive->queue))) {
|
||||
if (__blk_end_request(req, -EIO, 0))
|
||||
BUG();
|
||||
}
|
||||
|
||||
hwgroup->rq = NULL;
|
||||
hwgroup->handler = NULL;
|
||||
hwgroup->busy = 1; /* will set this to zero when ide reset finished */
|
||||
spin_unlock(&hwgroup->lock);
|
||||
|
||||
ide_do_reset(drive);
|
||||
|
||||
/* ide_do_reset starts a polling handler which restarts itself every 50ms until the reset finishes */
|
||||
|
||||
do {
|
||||
spin_unlock_irq(cmd->device->host->host_lock);
|
||||
msleep(50);
|
||||
spin_lock_irq(cmd->device->host->host_lock);
|
||||
} while ( HWGROUP(drive)->handler );
|
||||
|
||||
ready = drive_is_ready(drive);
|
||||
HWGROUP(drive)->busy--;
|
||||
if (!ready) {
|
||||
printk (KERN_ERR "ide-scsi: reset failed!\n");
|
||||
ret = FAILED;
|
||||
}
|
||||
|
||||
spin_unlock_irq(cmd->device->host->host_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int idescsi_bios(struct scsi_device *sdev, struct block_device *bdev,
|
||||
sector_t capacity, int *parm)
|
||||
{
|
||||
idescsi_scsi_t *idescsi = scsihost_to_idescsi(sdev->host);
|
||||
ide_drive_t *drive = idescsi->drive;
|
||||
|
||||
if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
|
||||
parm[0] = drive->bios_head;
|
||||
parm[1] = drive->bios_sect;
|
||||
parm[2] = drive->bios_cyl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct scsi_host_template idescsi_template = {
|
||||
.module = THIS_MODULE,
|
||||
.name = "idescsi",
|
||||
.info = idescsi_info,
|
||||
.slave_configure = idescsi_slave_configure,
|
||||
.ioctl = idescsi_ioctl,
|
||||
.queuecommand = idescsi_queue,
|
||||
.eh_abort_handler = idescsi_eh_abort,
|
||||
.eh_host_reset_handler = idescsi_eh_reset,
|
||||
.bios_param = idescsi_bios,
|
||||
.can_queue = 40,
|
||||
.this_id = -1,
|
||||
.sg_tablesize = 256,
|
||||
.cmd_per_lun = 5,
|
||||
.max_sectors = 128,
|
||||
.use_clustering = DISABLE_CLUSTERING,
|
||||
.emulated = 1,
|
||||
.proc_name = "ide-scsi",
|
||||
};
|
||||
|
||||
static int ide_scsi_probe(ide_drive_t *drive)
|
||||
{
|
||||
idescsi_scsi_t *idescsi;
|
||||
struct Scsi_Host *host;
|
||||
struct gendisk *g;
|
||||
static int warned;
|
||||
int err = -ENOMEM;
|
||||
u16 last_lun;
|
||||
|
||||
if (!warned && drive->media == ide_cdrom) {
|
||||
printk(KERN_WARNING "ide-scsi is deprecated for cd burning! Use ide-cd and give dev=/dev/hdX as device\n");
|
||||
warned = 1;
|
||||
}
|
||||
|
||||
if (idescsi_nocd && drive->media == ide_cdrom)
|
||||
return -ENODEV;
|
||||
|
||||
if (!strstr("ide-scsi", drive->driver_req) ||
|
||||
drive->media == ide_disk ||
|
||||
!(host = scsi_host_alloc(&idescsi_template,sizeof(idescsi_scsi_t))))
|
||||
return -ENODEV;
|
||||
|
||||
drive->dev_flags |= IDE_DFLAG_SCSI;
|
||||
|
||||
g = alloc_disk(1 << PARTN_BITS);
|
||||
if (!g)
|
||||
goto out_host_put;
|
||||
|
||||
ide_init_disk(g, drive);
|
||||
|
||||
host->max_id = 1;
|
||||
|
||||
last_lun = drive->id[ATA_ID_LAST_LUN];
|
||||
if (last_lun)
|
||||
debug_log("%s: last_lun=%u\n", drive->name, last_lun);
|
||||
|
||||
if ((last_lun & 7) != 7)
|
||||
host->max_lun = (last_lun & 7) + 1;
|
||||
else
|
||||
host->max_lun = 1;
|
||||
|
||||
drive->driver_data = host;
|
||||
idescsi = scsihost_to_idescsi(host);
|
||||
idescsi->drive = drive;
|
||||
idescsi->driver = &idescsi_driver;
|
||||
idescsi->host = host;
|
||||
idescsi->disk = g;
|
||||
g->private_data = &idescsi->driver;
|
||||
err = 0;
|
||||
idescsi_setup(drive, idescsi);
|
||||
g->fops = &idescsi_ops;
|
||||
ide_register_region(g);
|
||||
err = scsi_add_host(host, &drive->gendev);
|
||||
if (!err) {
|
||||
scsi_scan_host(host);
|
||||
return 0;
|
||||
}
|
||||
/* fall through on error */
|
||||
ide_unregister_region(g);
|
||||
ide_proc_unregister_driver(drive, &idescsi_driver);
|
||||
|
||||
put_disk(g);
|
||||
out_host_put:
|
||||
drive->dev_flags &= ~IDE_DFLAG_SCSI;
|
||||
scsi_host_put(host);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int __init init_idescsi_module(void)
|
||||
{
|
||||
return driver_register(&idescsi_driver.gen_driver);
|
||||
}
|
||||
|
||||
static void __exit exit_idescsi_module(void)
|
||||
{
|
||||
driver_unregister(&idescsi_driver.gen_driver);
|
||||
}
|
||||
|
||||
module_param(idescsi_nocd, int, 0600);
|
||||
MODULE_PARM_DESC(idescsi_nocd, "Disable handling of CD-ROMs so they may be driven by ide-cd");
|
||||
module_init(init_idescsi_module);
|
||||
module_exit(exit_idescsi_module);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -32,13 +32,6 @@
|
|||
# define SUPPORT_VLB_SYNC 1
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Used to indicate "no IRQ", should be a value that cannot be an IRQ
|
||||
* number.
|
||||
*/
|
||||
|
||||
#define IDE_NO_IRQ (-1)
|
||||
|
||||
typedef unsigned char byte; /* used everywhere */
|
||||
|
||||
/*
|
||||
|
@ -403,6 +396,7 @@ enum {
|
|||
* This is used for several packet commands (not for READ/WRITE commands).
|
||||
*/
|
||||
#define IDE_PC_BUFFER_SIZE 256
|
||||
#define ATAPI_WAIT_PC (60 * HZ)
|
||||
|
||||
struct ide_atapi_pc {
|
||||
/* actual packet bytes */
|
||||
|
@ -480,53 +474,53 @@ enum {
|
|||
|
||||
/* ide-cd */
|
||||
/* Drive cannot eject the disc. */
|
||||
IDE_AFLAG_NO_EJECT = (1 << 3),
|
||||
IDE_AFLAG_NO_EJECT = (1 << 1),
|
||||
/* Drive is a pre ATAPI 1.2 drive. */
|
||||
IDE_AFLAG_PRE_ATAPI12 = (1 << 4),
|
||||
IDE_AFLAG_PRE_ATAPI12 = (1 << 2),
|
||||
/* TOC addresses are in BCD. */
|
||||
IDE_AFLAG_TOCADDR_AS_BCD = (1 << 5),
|
||||
IDE_AFLAG_TOCADDR_AS_BCD = (1 << 3),
|
||||
/* TOC track numbers are in BCD. */
|
||||
IDE_AFLAG_TOCTRACKS_AS_BCD = (1 << 6),
|
||||
IDE_AFLAG_TOCTRACKS_AS_BCD = (1 << 4),
|
||||
/*
|
||||
* Drive does not provide data in multiples of SECTOR_SIZE
|
||||
* when more than one interrupt is needed.
|
||||
*/
|
||||
IDE_AFLAG_LIMIT_NFRAMES = (1 << 7),
|
||||
IDE_AFLAG_LIMIT_NFRAMES = (1 << 5),
|
||||
/* Saved TOC information is current. */
|
||||
IDE_AFLAG_TOC_VALID = (1 << 9),
|
||||
IDE_AFLAG_TOC_VALID = (1 << 6),
|
||||
/* We think that the drive door is locked. */
|
||||
IDE_AFLAG_DOOR_LOCKED = (1 << 10),
|
||||
IDE_AFLAG_DOOR_LOCKED = (1 << 7),
|
||||
/* SET_CD_SPEED command is unsupported. */
|
||||
IDE_AFLAG_NO_SPEED_SELECT = (1 << 11),
|
||||
IDE_AFLAG_VERTOS_300_SSD = (1 << 12),
|
||||
IDE_AFLAG_VERTOS_600_ESD = (1 << 13),
|
||||
IDE_AFLAG_SANYO_3CD = (1 << 14),
|
||||
IDE_AFLAG_FULL_CAPS_PAGE = (1 << 15),
|
||||
IDE_AFLAG_PLAY_AUDIO_OK = (1 << 16),
|
||||
IDE_AFLAG_LE_SPEED_FIELDS = (1 << 17),
|
||||
IDE_AFLAG_NO_SPEED_SELECT = (1 << 8),
|
||||
IDE_AFLAG_VERTOS_300_SSD = (1 << 9),
|
||||
IDE_AFLAG_VERTOS_600_ESD = (1 << 10),
|
||||
IDE_AFLAG_SANYO_3CD = (1 << 11),
|
||||
IDE_AFLAG_FULL_CAPS_PAGE = (1 << 12),
|
||||
IDE_AFLAG_PLAY_AUDIO_OK = (1 << 13),
|
||||
IDE_AFLAG_LE_SPEED_FIELDS = (1 << 14),
|
||||
|
||||
/* ide-floppy */
|
||||
/* Avoid commands not supported in Clik drive */
|
||||
IDE_AFLAG_CLIK_DRIVE = (1 << 19),
|
||||
IDE_AFLAG_CLIK_DRIVE = (1 << 15),
|
||||
/* Requires BH algorithm for packets */
|
||||
IDE_AFLAG_ZIP_DRIVE = (1 << 20),
|
||||
IDE_AFLAG_ZIP_DRIVE = (1 << 16),
|
||||
/* Supports format progress report */
|
||||
IDE_AFLAG_SRFP = (1 << 22),
|
||||
IDE_AFLAG_SRFP = (1 << 17),
|
||||
|
||||
/* ide-tape */
|
||||
IDE_AFLAG_IGNORE_DSC = (1 << 23),
|
||||
IDE_AFLAG_IGNORE_DSC = (1 << 18),
|
||||
/* 0 When the tape position is unknown */
|
||||
IDE_AFLAG_ADDRESS_VALID = (1 << 24),
|
||||
IDE_AFLAG_ADDRESS_VALID = (1 << 19),
|
||||
/* Device already opened */
|
||||
IDE_AFLAG_BUSY = (1 << 25),
|
||||
IDE_AFLAG_BUSY = (1 << 20),
|
||||
/* Attempt to auto-detect the current user block size */
|
||||
IDE_AFLAG_DETECT_BS = (1 << 26),
|
||||
IDE_AFLAG_DETECT_BS = (1 << 21),
|
||||
/* Currently on a filemark */
|
||||
IDE_AFLAG_FILEMARK = (1 << 27),
|
||||
IDE_AFLAG_FILEMARK = (1 << 22),
|
||||
/* 0 = no tape is loaded, so we don't rewind after ejecting */
|
||||
IDE_AFLAG_MEDIUM_PRESENT = (1 << 28),
|
||||
IDE_AFLAG_MEDIUM_PRESENT = (1 << 23),
|
||||
|
||||
IDE_AFLAG_NO_AUTOCLOSE = (1 << 29),
|
||||
IDE_AFLAG_NO_AUTOCLOSE = (1 << 24),
|
||||
};
|
||||
|
||||
/* device flags */
|
||||
|
@ -565,28 +559,26 @@ enum {
|
|||
IDE_DFLAG_NODMA = (1 << 16),
|
||||
/* powermanagment told us not to do anything, so sleep nicely */
|
||||
IDE_DFLAG_BLOCKED = (1 << 17),
|
||||
/* ide-scsi emulation */
|
||||
IDE_DFLAG_SCSI = (1 << 18),
|
||||
/* sleeping & sleep field valid */
|
||||
IDE_DFLAG_SLEEPING = (1 << 19),
|
||||
IDE_DFLAG_POST_RESET = (1 << 20),
|
||||
IDE_DFLAG_UDMA33_WARNED = (1 << 21),
|
||||
IDE_DFLAG_LBA48 = (1 << 22),
|
||||
IDE_DFLAG_SLEEPING = (1 << 18),
|
||||
IDE_DFLAG_POST_RESET = (1 << 19),
|
||||
IDE_DFLAG_UDMA33_WARNED = (1 << 20),
|
||||
IDE_DFLAG_LBA48 = (1 << 21),
|
||||
/* status of write cache */
|
||||
IDE_DFLAG_WCACHE = (1 << 23),
|
||||
IDE_DFLAG_WCACHE = (1 << 22),
|
||||
/* used for ignoring ATA_DF */
|
||||
IDE_DFLAG_NOWERR = (1 << 24),
|
||||
IDE_DFLAG_NOWERR = (1 << 23),
|
||||
/* retrying in PIO */
|
||||
IDE_DFLAG_DMA_PIO_RETRY = (1 << 25),
|
||||
IDE_DFLAG_LBA = (1 << 26),
|
||||
IDE_DFLAG_DMA_PIO_RETRY = (1 << 24),
|
||||
IDE_DFLAG_LBA = (1 << 25),
|
||||
/* don't unload heads */
|
||||
IDE_DFLAG_NO_UNLOAD = (1 << 27),
|
||||
IDE_DFLAG_NO_UNLOAD = (1 << 26),
|
||||
/* heads unloaded, please don't reset port */
|
||||
IDE_DFLAG_PARKED = (1 << 28),
|
||||
IDE_DFLAG_MEDIA_CHANGED = (1 << 29),
|
||||
IDE_DFLAG_PARKED = (1 << 27),
|
||||
IDE_DFLAG_MEDIA_CHANGED = (1 << 28),
|
||||
/* write protect */
|
||||
IDE_DFLAG_WP = (1 << 30),
|
||||
IDE_DFLAG_FORMAT_IN_PROGRESS = (1 << 31),
|
||||
IDE_DFLAG_WP = (1 << 29),
|
||||
IDE_DFLAG_FORMAT_IN_PROGRESS = (1 << 30),
|
||||
};
|
||||
|
||||
struct ide_drive_s {
|
||||
|
@ -610,8 +602,6 @@ struct ide_drive_s {
|
|||
unsigned long dev_flags;
|
||||
|
||||
unsigned long sleep; /* sleep until this time */
|
||||
unsigned long service_start; /* time we started last request */
|
||||
unsigned long service_time; /* service time of last request */
|
||||
unsigned long timeout; /* max time to wait for irq */
|
||||
|
||||
special_t special; /* special action flags */
|
||||
|
@ -879,8 +869,6 @@ typedef struct hwgroup_s {
|
|||
|
||||
/* BOOL: protects all fields below */
|
||||
volatile int busy;
|
||||
/* BOOL: wake us up on timer expiry */
|
||||
unsigned int sleeping : 1;
|
||||
/* BOOL: polling active & poll_timeout field valid */
|
||||
unsigned int polling : 1;
|
||||
|
||||
|
@ -1258,14 +1246,11 @@ int ide_set_media_lock(ide_drive_t *, struct gendisk *, int);
|
|||
void ide_create_request_sense_cmd(ide_drive_t *, struct ide_atapi_pc *);
|
||||
void ide_retry_pc(ide_drive_t *, struct gendisk *);
|
||||
|
||||
static inline unsigned long ide_scsi_get_timeout(struct ide_atapi_pc *pc)
|
||||
{
|
||||
return max_t(unsigned long, WAIT_CMD, pc->timeout - jiffies);
|
||||
}
|
||||
int ide_cd_expiry(ide_drive_t *);
|
||||
|
||||
int ide_scsi_expiry(ide_drive_t *);
|
||||
int ide_cd_get_xferlen(struct request *);
|
||||
|
||||
ide_startstop_t ide_issue_pc(ide_drive_t *, unsigned int, ide_expiry_t *);
|
||||
ide_startstop_t ide_issue_pc(ide_drive_t *);
|
||||
|
||||
ide_startstop_t do_rw_taskfile(ide_drive_t *, ide_task_t *);
|
||||
|
||||
|
@ -1287,6 +1272,26 @@ extern void ide_stall_queue(ide_drive_t *drive, unsigned long timeout);
|
|||
|
||||
extern void ide_timer_expiry(unsigned long);
|
||||
extern irqreturn_t ide_intr(int irq, void *dev_id);
|
||||
|
||||
static inline int ide_lock_hwgroup(ide_hwgroup_t *hwgroup)
|
||||
{
|
||||
if (hwgroup->busy)
|
||||
return 1;
|
||||
|
||||
hwgroup->busy = 1;
|
||||
/* for atari only */
|
||||
ide_get_lock(ide_intr, hwgroup);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void ide_unlock_hwgroup(ide_hwgroup_t *hwgroup)
|
||||
{
|
||||
/* for atari only */
|
||||
ide_release_lock();
|
||||
hwgroup->busy = 0;
|
||||
}
|
||||
|
||||
extern void do_ide_request(struct request_queue *);
|
||||
|
||||
void ide_init_disk(struct gendisk *, ide_drive_t *);
|
||||
|
@ -1533,6 +1538,7 @@ void ide_unregister_region(struct gendisk *);
|
|||
void ide_undecoded_slave(ide_drive_t *);
|
||||
|
||||
void ide_port_apply_params(ide_hwif_t *);
|
||||
int ide_sysfs_register_port(ide_hwif_t *);
|
||||
|
||||
struct ide_host *ide_host_alloc(const struct ide_port_info *, hw_regs_t **);
|
||||
void ide_host_free(struct ide_host *);
|
||||
|
@ -1627,6 +1633,9 @@ extern struct mutex ide_cfg_mtx;
|
|||
|
||||
#define local_irq_set(flags) do { local_save_flags((flags)); local_irq_enable_in_hardirq(); } while (0)
|
||||
|
||||
char *ide_media_string(ide_drive_t *);
|
||||
|
||||
extern struct device_attribute ide_dev_attrs[];
|
||||
extern struct bus_type ide_bus_type;
|
||||
extern struct class *ide_port_class;
|
||||
|
||||
|
|
Loading…
Reference in New Issue