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:
Linus Torvalds 2009-01-02 10:32:18 -08:00
Родитель 80618fa83a b16aabc937
Коммит 2640c9a90f
22 изменённых файлов: 618 добавлений и 1613 удалений

Просмотреть файл

@ -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);
}

125
drivers/ide/ide-sysfs.c Normal file
Просмотреть файл

@ -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;