You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
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: (53 commits)
ide: use try_to_identify() in ide_driveid_update()
ide: clear drive IRQ after re-enabling local IRQs in ide_driveid_update()
ide: sanitize SELECT_MASK() usage in ide_driveid_update()
ide: classify device type in do_probe()
ide: remove broken EXABYTENEST support
ide: shorten timeout value in ide_driveid_update()
ide: propagate AltStatus workarounds to ide_driveid_update()
ide: fix kmalloc() failure handling in ide_driveid_update()
mn10300: remove <asm/ide.h>
frv: remove <asm/ide.h>
ide: remove pciirq argument from ide_pci_setup_ports()
ide: fix ->init_chipset method to return 'int' value
ide: remove try_to_identify() wrapper
ide: remove no longer needed IRQ auto-probing from try_to_identify() (v2)
ide: remove no longer needed IRQ fallback code from hwif_init()
amd74xx: remove no longer needed ->init_hwif method
ide: remove no longer needed IDE_HFLAG[_FORCE]_LEGACY_IRQS
ide: use ide_pci_is_in_compatibility_mode() in ide_pci_init_{one,two}()
ide: use pci_get_legacy_ide_irq() in ide_pci_init_{one,two}()
ide: handle IDE_HFLAG[_FORCE]_LEGACY_IRQS in ide_pci_init_{one,two}()
...
This commit is contained in:
@@ -56,8 +56,12 @@ if IDE
|
||||
|
||||
comment "Please see Documentation/ide/ide.txt for help/info on IDE drives"
|
||||
|
||||
config IDE_XFER_MODE
|
||||
bool
|
||||
|
||||
config IDE_TIMINGS
|
||||
bool
|
||||
select IDE_XFER_MODE
|
||||
|
||||
config IDE_ATAPI
|
||||
bool
|
||||
@@ -698,6 +702,7 @@ config BLK_DEV_IDE_PMAC_ATA100FIRST
|
||||
config BLK_DEV_IDE_AU1XXX
|
||||
bool "IDE for AMD Alchemy Au1200"
|
||||
depends on SOC_AU1200
|
||||
select IDE_XFER_MODE
|
||||
choice
|
||||
prompt "IDE Mode for AMD Alchemy Au1200"
|
||||
default CONFIG_BLK_DEV_IDE_AU1XXX_PIO_DBDMA
|
||||
@@ -871,6 +876,7 @@ config BLK_DEV_ALI14XX
|
||||
|
||||
config BLK_DEV_DTC2278
|
||||
tristate "DTC-2278 support"
|
||||
select IDE_XFER_MODE
|
||||
select IDE_LEGACY
|
||||
help
|
||||
This driver is enabled at runtime using the "dtc2278.probe" kernel
|
||||
@@ -902,6 +908,7 @@ config BLK_DEV_QD65XX
|
||||
|
||||
config BLK_DEV_UMC8672
|
||||
tristate "UMC-8672 support"
|
||||
select IDE_XFER_MODE
|
||||
select IDE_LEGACY
|
||||
help
|
||||
This driver is enabled at runtime using the "umc8672.probe" kernel
|
||||
@@ -915,5 +922,6 @@ endif
|
||||
config BLK_DEV_IDEDMA
|
||||
def_bool BLK_DEV_IDEDMA_SFF || \
|
||||
BLK_DEV_IDEDMA_ICS || BLK_DEV_IDE_AU1XXX_MDMA2_DBDMA
|
||||
select IDE_XFER_MODE
|
||||
|
||||
endif # IDE
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
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-sysfs.o
|
||||
ide-taskfile.o ide-pm.o ide-park.o ide-sysfs.o ide-devsets.o \
|
||||
ide-io-std.o ide-eh.o
|
||||
|
||||
# core IDE code
|
||||
ide-core-$(CONFIG_IDE_XFER_MODE) += ide-pio-blacklist.o ide-xfer-mode.o
|
||||
ide-core-$(CONFIG_IDE_TIMINGS) += ide-timings.o
|
||||
ide-core-$(CONFIG_IDE_ATAPI) += ide-atapi.o
|
||||
ide-core-$(CONFIG_BLK_DEV_IDEPCI) += setup-pci.o
|
||||
|
||||
@@ -139,7 +139,7 @@ static void aec_set_pio_mode(ide_drive_t *drive, const u8 pio)
|
||||
drive->hwif->port_ops->set_dma_mode(drive, pio + XFER_PIO_0);
|
||||
}
|
||||
|
||||
static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
|
||||
static int init_chipset_aec62xx(struct pci_dev *dev)
|
||||
{
|
||||
/* These are necessary to get AEC6280 Macintosh cards to work */
|
||||
if ((dev->device == PCI_DEVICE_ID_ARTOP_ATP865) ||
|
||||
@@ -156,7 +156,7 @@ static unsigned int init_chipset_aec62xx(struct pci_dev *dev)
|
||||
pci_write_config_byte(dev, 0x4a, reg4ah | 0x80);
|
||||
}
|
||||
|
||||
return dev->irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 atp86x_cable_detect(ide_hwif_t *hwif)
|
||||
|
||||
@@ -212,7 +212,7 @@ static int ali15x3_dma_setup(ide_drive_t *drive)
|
||||
* appropriate also sets up the 1533 southbridge.
|
||||
*/
|
||||
|
||||
static unsigned int init_chipset_ali15x3(struct pci_dev *dev)
|
||||
static int init_chipset_ali15x3(struct pci_dev *dev)
|
||||
{
|
||||
unsigned long flags;
|
||||
u8 tmpbyte;
|
||||
|
||||
+2
-12
@@ -140,7 +140,7 @@ static void amd7411_cable_detect(struct pci_dev *dev)
|
||||
* The initialization callback. Initialize drive independent registers.
|
||||
*/
|
||||
|
||||
static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
|
||||
static int init_chipset_amd74xx(struct pci_dev *dev)
|
||||
{
|
||||
u8 t = 0, offset = amd_offset(dev);
|
||||
|
||||
@@ -172,7 +172,7 @@ static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
|
||||
t |= 0xf0;
|
||||
pci_write_config_byte(dev, AMD_IDE_CONFIG + offset, t);
|
||||
|
||||
return dev->irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 amd_cable_detect(ide_hwif_t *hwif)
|
||||
@@ -183,14 +183,6 @@ static u8 amd_cable_detect(ide_hwif_t *hwif)
|
||||
return ATA_CBL_PATA40;
|
||||
}
|
||||
|
||||
static void __devinit init_hwif_amd74xx(ide_hwif_t *hwif)
|
||||
{
|
||||
struct pci_dev *dev = to_pci_dev(hwif->dev);
|
||||
|
||||
if (hwif->irq == 0) /* 0 is bogus but will do for now */
|
||||
hwif->irq = pci_get_legacy_ide_irq(dev, hwif->channel);
|
||||
}
|
||||
|
||||
static const struct ide_port_ops amd_port_ops = {
|
||||
.set_pio_mode = amd_set_pio_mode,
|
||||
.set_dma_mode = amd_set_drive,
|
||||
@@ -207,7 +199,6 @@ static const struct ide_port_ops amd_port_ops = {
|
||||
{ \
|
||||
.name = DRV_NAME, \
|
||||
.init_chipset = init_chipset_amd74xx, \
|
||||
.init_hwif = init_hwif_amd74xx, \
|
||||
.enablebits = {{0x40,0x02,0x02}, {0x40,0x01,0x01}}, \
|
||||
.port_ops = &amd_port_ops, \
|
||||
.host_flags = IDE_HFLAGS_AMD, \
|
||||
@@ -221,7 +212,6 @@ static const struct ide_port_ops amd_port_ops = {
|
||||
{ \
|
||||
.name = DRV_NAME, \
|
||||
.init_chipset = init_chipset_amd74xx, \
|
||||
.init_hwif = init_hwif_amd74xx, \
|
||||
.enablebits = {{0x50,0x02,0x02}, {0x50,0x01,0x01}}, \
|
||||
.port_ops = &amd_port_ops, \
|
||||
.host_flags = IDE_HFLAGS_AMD, \
|
||||
|
||||
@@ -142,7 +142,6 @@ static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
|
||||
.name = DRV_NAME,
|
||||
.enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}},
|
||||
.port_ops = &atiixp_port_ops,
|
||||
.host_flags = IDE_HFLAG_LEGACY_IRQS,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
@@ -151,7 +150,7 @@ static const struct ide_port_info atiixp_pci_info[] __devinitdata = {
|
||||
.name = DRV_NAME,
|
||||
.enablebits = {{0x48,0x01,0x00}, {0x00,0x00,0x00}},
|
||||
.port_ops = &atiixp_port_ops,
|
||||
.host_flags = IDE_HFLAG_SINGLE | IDE_HFLAG_LEGACY_IRQS,
|
||||
.host_flags = IDE_HFLAG_SINGLE,
|
||||
.pio_mask = ATA_PIO4,
|
||||
.mwdma_mask = ATA_MWDMA2,
|
||||
.udma_mask = ATA_UDMA5,
|
||||
|
||||
@@ -333,7 +333,7 @@ static int cmd646_1_dma_end(ide_drive_t *drive)
|
||||
return (dma_stat & 7) != 4;
|
||||
}
|
||||
|
||||
static unsigned int init_chipset_cmd64x(struct pci_dev *dev)
|
||||
static int init_chipset_cmd64x(struct pci_dev *dev)
|
||||
{
|
||||
u8 mrdmode = 0;
|
||||
|
||||
|
||||
@@ -133,7 +133,8 @@ static int __devinit cs5520_init_one(struct pci_dev *dev, const struct pci_devic
|
||||
* do all the device setup for us
|
||||
*/
|
||||
|
||||
ide_pci_setup_ports(dev, d, 14, &hw[0], &hws[0]);
|
||||
ide_pci_setup_ports(dev, d, &hw[0], &hws[0]);
|
||||
hw[0].irq = 14;
|
||||
|
||||
return ide_host_add(d, hws, NULL);
|
||||
}
|
||||
|
||||
@@ -135,7 +135,7 @@ static void cs5530_set_dma_mode(ide_drive_t *drive, const u8 mode)
|
||||
* Initialize the cs5530 bridge for reliable IDE DMA operation.
|
||||
*/
|
||||
|
||||
static unsigned int init_chipset_cs5530(struct pci_dev *dev)
|
||||
static int init_chipset_cs5530(struct pci_dev *dev)
|
||||
{
|
||||
struct pci_dev *master_0 = NULL, *cs5530_0 = NULL;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ static const struct ide_port_ops delkin_cb_port_ops = {
|
||||
.quirkproc = ide_undecoded_slave,
|
||||
};
|
||||
|
||||
static unsigned int delkin_cb_init_chipset(struct pci_dev *dev)
|
||||
static int delkin_cb_init_chipset(struct pci_dev *dev)
|
||||
{
|
||||
unsigned long base = pci_resource_start(dev, 0);
|
||||
int i;
|
||||
|
||||
@@ -995,7 +995,7 @@ static void hpt3xx_disable_fast_irq(struct pci_dev *dev, u8 mcr_addr)
|
||||
pci_write_config_byte(dev, mcr_addr + 1, new_mcr);
|
||||
}
|
||||
|
||||
static unsigned int init_chipset_hpt366(struct pci_dev *dev)
|
||||
static int init_chipset_hpt366(struct pci_dev *dev)
|
||||
{
|
||||
unsigned long io_base = pci_resource_start(dev, 4);
|
||||
struct hpt_info *info = hpt3xx_get_info(&dev->dev);
|
||||
@@ -1237,7 +1237,7 @@ static unsigned int init_chipset_hpt366(struct pci_dev *dev)
|
||||
hpt3xx_disable_fast_irq(dev, 0x50);
|
||||
hpt3xx_disable_fast_irq(dev, 0x54);
|
||||
|
||||
return dev->irq;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u8 hpt3xx_cable_detect(ide_hwif_t *hwif)
|
||||
|
||||
+52
-162
@@ -20,9 +20,6 @@
|
||||
#include <acpi/acpi_bus.h>
|
||||
|
||||
#define REGS_PER_GTF 7
|
||||
struct taskfile_array {
|
||||
u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
|
||||
};
|
||||
|
||||
struct GTM_buffer {
|
||||
u32 PIO_speed0;
|
||||
@@ -89,12 +86,8 @@ static const struct dmi_system_id ide_acpi_dmi_table[] = {
|
||||
{ } /* terminate list */
|
||||
};
|
||||
|
||||
static int ide_acpi_blacklist(void)
|
||||
int ide_acpi_init(void)
|
||||
{
|
||||
static int done;
|
||||
if (done)
|
||||
return 0;
|
||||
done = 1;
|
||||
dmi_check_system(ide_acpi_dmi_table);
|
||||
return 0;
|
||||
}
|
||||
@@ -201,40 +194,6 @@ static acpi_handle ide_acpi_hwif_get_handle(ide_hwif_t *hwif)
|
||||
return chan_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_acpi_drive_get_handle - Get ACPI object handle for a given drive
|
||||
* @drive: device to locate
|
||||
*
|
||||
* Retrieves the object handle of a given drive. According to the ACPI
|
||||
* spec the drive is a child of the hwif.
|
||||
*
|
||||
* Returns handle on success, 0 on error.
|
||||
*/
|
||||
static acpi_handle ide_acpi_drive_get_handle(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
int port;
|
||||
acpi_handle drive_handle;
|
||||
|
||||
if (!hwif->acpidata)
|
||||
return NULL;
|
||||
|
||||
if (!hwif->acpidata->obj_handle)
|
||||
return NULL;
|
||||
|
||||
port = hwif->channel ? drive->dn - 2: drive->dn;
|
||||
|
||||
DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
|
||||
drive->name, hwif->channel, port);
|
||||
|
||||
|
||||
/* TBD: could also check ACPI object VALID bits */
|
||||
drive_handle = acpi_get_child(hwif->acpidata->obj_handle, port);
|
||||
DEBPRINT("drive %s handle 0x%p\n", drive->name, drive_handle);
|
||||
|
||||
return drive_handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_drive_get_GTF - get the drive bootup default taskfile settings
|
||||
* @drive: the drive for which the taskfile settings should be retrieved
|
||||
@@ -257,47 +216,15 @@ static int do_drive_get_GTF(ide_drive_t *drive,
|
||||
acpi_status status;
|
||||
struct acpi_buffer output;
|
||||
union acpi_object *out_obj;
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct device *dev = hwif->gendev.parent;
|
||||
int err = -ENODEV;
|
||||
int port;
|
||||
|
||||
*gtf_length = 0;
|
||||
*gtf_address = 0UL;
|
||||
*obj_loc = 0UL;
|
||||
|
||||
if (ide_noacpi)
|
||||
return 0;
|
||||
|
||||
if (!dev) {
|
||||
DEBPRINT("no PCI device for %s\n", hwif->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!hwif->acpidata) {
|
||||
DEBPRINT("no ACPI data for %s\n", hwif->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
port = hwif->channel ? drive->dn - 2: drive->dn;
|
||||
|
||||
DEBPRINT("ENTER: %s at %s, port#: %d, hard_port#: %d\n",
|
||||
hwif->name, dev_name(dev), port, hwif->channel);
|
||||
|
||||
if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0) {
|
||||
DEBPRINT("%s drive %d:%d not present\n",
|
||||
hwif->name, hwif->channel, port);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Get this drive's _ADR info. if not already known. */
|
||||
if (!drive->acpidata->obj_handle) {
|
||||
drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
|
||||
if (!drive->acpidata->obj_handle) {
|
||||
DEBPRINT("No ACPI object found for %s\n",
|
||||
drive->name);
|
||||
goto out;
|
||||
}
|
||||
DEBPRINT("No ACPI object found for %s\n", drive->name);
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* Setting up output buffer */
|
||||
@@ -354,43 +281,6 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* taskfile_load_raw - send taskfile registers to drive
|
||||
* @drive: drive to which output is sent
|
||||
* @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
|
||||
*
|
||||
* Outputs IDE taskfile to the drive.
|
||||
*/
|
||||
static int taskfile_load_raw(ide_drive_t *drive,
|
||||
const struct taskfile_array *gtf)
|
||||
{
|
||||
ide_task_t args;
|
||||
int err = 0;
|
||||
|
||||
DEBPRINT("(0x1f1-1f7): hex: "
|
||||
"%02x %02x %02x %02x %02x %02x %02x\n",
|
||||
gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
|
||||
gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
|
||||
|
||||
memset(&args, 0, sizeof(ide_task_t));
|
||||
|
||||
/* convert gtf to IDE Taskfile */
|
||||
memcpy(&args.tf_array[7], >f->tfa, 7);
|
||||
args.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
|
||||
|
||||
if (!ide_acpigtf) {
|
||||
DEBPRINT("_GTF execution disabled\n");
|
||||
return err;
|
||||
}
|
||||
|
||||
err = ide_no_data_taskfile(drive, &args);
|
||||
if (err)
|
||||
printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
|
||||
__func__, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* do_drive_set_taskfiles - write the drive taskfile settings from _GTF
|
||||
* @drive: the drive to which the taskfile command should be sent
|
||||
@@ -404,43 +294,41 @@ static int do_drive_set_taskfiles(ide_drive_t *drive,
|
||||
unsigned int gtf_length,
|
||||
unsigned long gtf_address)
|
||||
{
|
||||
int rc = -ENODEV, err;
|
||||
int rc = 0, err;
|
||||
int gtf_count = gtf_length / REGS_PER_GTF;
|
||||
int ix;
|
||||
struct taskfile_array *gtf;
|
||||
|
||||
if (ide_noacpi)
|
||||
return 0;
|
||||
|
||||
DEBPRINT("ENTER: %s, hard_port#: %d\n", drive->name, drive->dn);
|
||||
|
||||
if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
|
||||
goto out;
|
||||
|
||||
if (!gtf_count) /* shouldn't be here */
|
||||
goto out;
|
||||
|
||||
DEBPRINT("total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n",
|
||||
gtf_length, gtf_length, gtf_count, gtf_address);
|
||||
|
||||
if (gtf_length % REGS_PER_GTF) {
|
||||
printk(KERN_ERR "%s: unexpected GTF length (%d)\n",
|
||||
__func__, gtf_length);
|
||||
goto out;
|
||||
}
|
||||
|
||||
rc = 0;
|
||||
/* send all taskfile registers (0x1f1-0x1f7) *in*that*order* */
|
||||
for (ix = 0; ix < gtf_count; ix++) {
|
||||
gtf = (struct taskfile_array *)
|
||||
(gtf_address + ix * REGS_PER_GTF);
|
||||
u8 *gtf = (u8 *)(gtf_address + ix * REGS_PER_GTF);
|
||||
ide_task_t task;
|
||||
|
||||
/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
|
||||
err = taskfile_load_raw(drive, gtf);
|
||||
if (err)
|
||||
DEBPRINT("(0x1f1-1f7): "
|
||||
"hex: %02x %02x %02x %02x %02x %02x %02x\n",
|
||||
gtf[0], gtf[1], gtf[2],
|
||||
gtf[3], gtf[4], gtf[5], gtf[6]);
|
||||
|
||||
if (!ide_acpigtf) {
|
||||
DEBPRINT("_GTF execution disabled\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* convert GTF to taskfile */
|
||||
memset(&task, 0, sizeof(ide_task_t));
|
||||
memcpy(&task.tf_array[7], gtf, REGS_PER_GTF);
|
||||
task.tf_flags = IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
|
||||
|
||||
err = ide_no_data_taskfile(drive, &task);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: ide_no_data_taskfile failed: %u\n",
|
||||
__func__, err);
|
||||
rc = err;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -647,26 +535,23 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
|
||||
DEBPRINT("no ACPI data for %s\n", hwif->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* channel first and then drives for power on and verse versa for power off */
|
||||
if (on)
|
||||
acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D0);
|
||||
|
||||
ide_port_for_each_dev(i, drive, hwif) {
|
||||
if (!drive->acpidata->obj_handle)
|
||||
drive->acpidata->obj_handle = ide_acpi_drive_get_handle(drive);
|
||||
|
||||
if (drive->acpidata->obj_handle &&
|
||||
(drive->dev_flags & IDE_DFLAG_PRESENT)) {
|
||||
ide_port_for_each_present_dev(i, drive, hwif) {
|
||||
if (drive->acpidata->obj_handle)
|
||||
acpi_bus_set_power(drive->acpidata->obj_handle,
|
||||
on? ACPI_STATE_D0: ACPI_STATE_D3);
|
||||
}
|
||||
on ? ACPI_STATE_D0 : ACPI_STATE_D3);
|
||||
}
|
||||
|
||||
if (!on)
|
||||
acpi_bus_set_power(hwif->acpidata->obj_handle, ACPI_STATE_D3);
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_acpi_init - initialize the ACPI link for an IDE interface
|
||||
* ide_acpi_init_port - initialize the ACPI link for an IDE interface
|
||||
* @hwif: target IDE interface (channel)
|
||||
*
|
||||
* The ACPI spec is not quite clear when the drive identify buffer
|
||||
@@ -676,10 +561,8 @@ void ide_acpi_set_state(ide_hwif_t *hwif, int on)
|
||||
* So we get the information during startup; but this means that
|
||||
* any changes during run-time will be lost after resume.
|
||||
*/
|
||||
void ide_acpi_init(ide_hwif_t *hwif)
|
||||
void ide_acpi_init_port(ide_hwif_t *hwif)
|
||||
{
|
||||
ide_acpi_blacklist();
|
||||
|
||||
hwif->acpidata = kzalloc(sizeof(struct ide_acpi_hwif_link), GFP_KERNEL);
|
||||
if (!hwif->acpidata)
|
||||
return;
|
||||
@@ -708,15 +591,24 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
|
||||
hwif->devices[0]->acpidata = &hwif->acpidata->master;
|
||||
hwif->devices[1]->acpidata = &hwif->acpidata->slave;
|
||||
|
||||
/*
|
||||
* Send IDENTIFY for each drive
|
||||
*/
|
||||
ide_port_for_each_dev(i, drive, hwif) {
|
||||
memset(drive->acpidata, 0, sizeof(*drive->acpidata));
|
||||
/* get _ADR info for each device */
|
||||
ide_port_for_each_present_dev(i, drive, hwif) {
|
||||
acpi_handle dev_handle;
|
||||
|
||||
if ((drive->dev_flags & IDE_DFLAG_PRESENT) == 0)
|
||||
continue;
|
||||
DEBPRINT("ENTER: %s at channel#: %d port#: %d\n",
|
||||
drive->name, hwif->channel, drive->dn & 1);
|
||||
|
||||
/* TBD: could also check ACPI object VALID bits */
|
||||
dev_handle = acpi_get_child(hwif->acpidata->obj_handle,
|
||||
drive->dn & 1);
|
||||
|
||||
DEBPRINT("drive %s handle 0x%p\n", drive->name, dev_handle);
|
||||
|
||||
drive->acpidata->obj_handle = dev_handle;
|
||||
}
|
||||
|
||||
/* send IDENTIFY for each device */
|
||||
ide_port_for_each_present_dev(i, drive, hwif) {
|
||||
err = taskfile_lib_get_identify(drive, drive->acpidata->idbuff);
|
||||
if (err)
|
||||
DEBPRINT("identify device %s failed (%d)\n",
|
||||
@@ -736,9 +628,7 @@ void ide_acpi_port_init_devices(ide_hwif_t *hwif)
|
||||
ide_acpi_get_timing(hwif);
|
||||
ide_acpi_push_timing(hwif);
|
||||
|
||||
ide_port_for_each_dev(i, drive, hwif) {
|
||||
if (drive->dev_flags & IDE_DFLAG_PRESENT)
|
||||
/* Execute ACPI startup code */
|
||||
ide_acpi_exec_tfs(drive);
|
||||
ide_port_for_each_present_dev(i, drive, hwif) {
|
||||
ide_acpi_exec_tfs(drive);
|
||||
}
|
||||
}
|
||||
|
||||
+39
-2
@@ -149,7 +149,10 @@ static void ide_queue_pc_head(ide_drive_t *drive, struct gendisk *disk,
|
||||
memcpy(rq->cmd, pc->c, 12);
|
||||
if (drive->media == ide_tape)
|
||||
rq->cmd[13] = REQ_IDETAPE_PC1;
|
||||
ide_do_drive_cmd(drive, rq);
|
||||
|
||||
drive->hwif->rq = NULL;
|
||||
|
||||
elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -297,6 +300,21 @@ int ide_cd_get_xferlen(struct request *rq)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_cd_get_xferlen);
|
||||
|
||||
void ide_read_bcount_and_ireason(ide_drive_t *drive, u16 *bcount, u8 *ireason)
|
||||
{
|
||||
ide_task_t task;
|
||||
|
||||
memset(&task, 0, sizeof(task));
|
||||
task.tf_flags = IDE_TFLAG_IN_LBAH | IDE_TFLAG_IN_LBAM |
|
||||
IDE_TFLAG_IN_NSECT;
|
||||
|
||||
drive->hwif->tp_ops->tf_read(drive, &task);
|
||||
|
||||
*bcount = (task.tf.lbah << 8) | task.tf.lbam;
|
||||
*ireason = task.tf.nsect & 3;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_read_bcount_and_ireason);
|
||||
|
||||
/*
|
||||
* This is the usual interrupt handler which will be called during a packet
|
||||
* command. We will transfer some of the data (as requested by the drive)
|
||||
@@ -456,6 +474,25 @@ next_irq:
|
||||
return ide_started;
|
||||
}
|
||||
|
||||
static void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
ide_task_t task;
|
||||
u8 dma = drive->dma;
|
||||
|
||||
memset(&task, 0, sizeof(task));
|
||||
task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
|
||||
IDE_TFLAG_OUT_FEATURE | tf_flags;
|
||||
task.tf.feature = dma; /* Use PIO/DMA */
|
||||
task.tf.lbam = bcount & 0xff;
|
||||
task.tf.lbah = (bcount >> 8) & 0xff;
|
||||
|
||||
ide_tf_dump(drive->name, &task.tf);
|
||||
hwif->tp_ops->set_irq(hwif, 1);
|
||||
SELECT_MASK(drive, 0);
|
||||
hwif->tp_ops->tf_load(drive, &task);
|
||||
}
|
||||
|
||||
static u8 ide_read_ireason(ide_drive_t *drive)
|
||||
{
|
||||
ide_task_t task;
|
||||
@@ -629,7 +666,7 @@ ide_startstop_t ide_issue_pc(ide_drive_t *drive)
|
||||
: WAIT_TAPE_CMD;
|
||||
}
|
||||
|
||||
ide_pktcmd_tf_load(drive, tf_flags, bcount, drive->dma);
|
||||
ide_pktcmd_tf_load(drive, tf_flags, bcount);
|
||||
|
||||
/* Issue the packet command */
|
||||
if (drive->atapi_flags & IDE_AFLAG_DRQ_INTERRUPT) {
|
||||
|
||||
@@ -242,7 +242,9 @@ static void cdrom_queue_request_sense(ide_drive_t *drive, void *sense,
|
||||
ide_debug_log(IDE_DBG_SENSE, "failed_cmd: 0x%x\n",
|
||||
failed_command->cmd[0]);
|
||||
|
||||
ide_do_drive_cmd(drive, rq);
|
||||
drive->hwif->rq = NULL;
|
||||
|
||||
elv_add_request(drive->queue, rq, ELEVATOR_INSERT_FRONT, 0);
|
||||
}
|
||||
|
||||
static void cdrom_end_request(ide_drive_t *drive, int uptodate)
|
||||
|
||||
@@ -0,0 +1,190 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
DEFINE_MUTEX(ide_setting_mtx);
|
||||
|
||||
ide_devset_get(io_32bit, io_32bit);
|
||||
|
||||
static int set_io_32bit(ide_drive_t *drive, int arg)
|
||||
{
|
||||
if (drive->dev_flags & IDE_DFLAG_NO_IO_32BIT)
|
||||
return -EPERM;
|
||||
|
||||
if (arg < 0 || arg > 1 + (SUPPORT_VLB_SYNC << 1))
|
||||
return -EINVAL;
|
||||
|
||||
drive->io_32bit = arg;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ide_devset_get_flag(ksettings, IDE_DFLAG_KEEP_SETTINGS);
|
||||
|
||||
static int set_ksettings(ide_drive_t *drive, int arg)
|
||||
{
|
||||
if (arg < 0 || arg > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (arg)
|
||||
drive->dev_flags |= IDE_DFLAG_KEEP_SETTINGS;
|
||||
else
|
||||
drive->dev_flags &= ~IDE_DFLAG_KEEP_SETTINGS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ide_devset_get_flag(using_dma, IDE_DFLAG_USING_DMA);
|
||||
|
||||
static int set_using_dma(ide_drive_t *drive, int arg)
|
||||
{
|
||||
#ifdef CONFIG_BLK_DEV_IDEDMA
|
||||
int err = -EPERM;
|
||||
|
||||
if (arg < 0 || arg > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (ata_id_has_dma(drive->id) == 0)
|
||||
goto out;
|
||||
|
||||
if (drive->hwif->dma_ops == NULL)
|
||||
goto out;
|
||||
|
||||
err = 0;
|
||||
|
||||
if (arg) {
|
||||
if (ide_set_dma(drive))
|
||||
err = -EIO;
|
||||
} else
|
||||
ide_dma_off(drive);
|
||||
|
||||
out:
|
||||
return err;
|
||||
#else
|
||||
if (arg < 0 || arg > 1)
|
||||
return -EINVAL;
|
||||
|
||||
return -EPERM;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* handle HDIO_SET_PIO_MODE ioctl abusers here, eventually it will go away
|
||||
*/
|
||||
static int set_pio_mode_abuse(ide_hwif_t *hwif, u8 req_pio)
|
||||
{
|
||||
switch (req_pio) {
|
||||
case 202:
|
||||
case 201:
|
||||
case 200:
|
||||
case 102:
|
||||
case 101:
|
||||
case 100:
|
||||
return (hwif->host_flags & IDE_HFLAG_ABUSE_DMA_MODES) ? 1 : 0;
|
||||
case 9:
|
||||
case 8:
|
||||
return (hwif->host_flags & IDE_HFLAG_ABUSE_PREFETCH) ? 1 : 0;
|
||||
case 7:
|
||||
case 6:
|
||||
return (hwif->host_flags & IDE_HFLAG_ABUSE_FAST_DEVSEL) ? 1 : 0;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int set_pio_mode(ide_drive_t *drive, int arg)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
const struct ide_port_ops *port_ops = hwif->port_ops;
|
||||
|
||||
if (arg < 0 || arg > 255)
|
||||
return -EINVAL;
|
||||
|
||||
if (port_ops == NULL || port_ops->set_pio_mode == NULL ||
|
||||
(hwif->host_flags & IDE_HFLAG_NO_SET_MODE))
|
||||
return -ENOSYS;
|
||||
|
||||
if (set_pio_mode_abuse(drive->hwif, arg)) {
|
||||
if (arg == 8 || arg == 9) {
|
||||
unsigned long flags;
|
||||
|
||||
/* take lock for IDE_DFLAG_[NO_]UNMASK/[NO_]IO_32BIT */
|
||||
spin_lock_irqsave(&hwif->lock, flags);
|
||||
port_ops->set_pio_mode(drive, arg);
|
||||
spin_unlock_irqrestore(&hwif->lock, flags);
|
||||
} else
|
||||
port_ops->set_pio_mode(drive, arg);
|
||||
} else {
|
||||
int keep_dma = !!(drive->dev_flags & IDE_DFLAG_USING_DMA);
|
||||
|
||||
ide_set_pio(drive, arg);
|
||||
|
||||
if (hwif->host_flags & IDE_HFLAG_SET_PIO_MODE_KEEP_DMA) {
|
||||
if (keep_dma)
|
||||
ide_dma_on(drive);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ide_devset_get_flag(unmaskirq, IDE_DFLAG_UNMASK);
|
||||
|
||||
static int set_unmaskirq(ide_drive_t *drive, int arg)
|
||||
{
|
||||
if (drive->dev_flags & IDE_DFLAG_NO_UNMASK)
|
||||
return -EPERM;
|
||||
|
||||
if (arg < 0 || arg > 1)
|
||||
return -EINVAL;
|
||||
|
||||
if (arg)
|
||||
drive->dev_flags |= IDE_DFLAG_UNMASK;
|
||||
else
|
||||
drive->dev_flags &= ~IDE_DFLAG_UNMASK;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
ide_ext_devset_rw_sync(io_32bit, io_32bit);
|
||||
ide_ext_devset_rw_sync(keepsettings, ksettings);
|
||||
ide_ext_devset_rw_sync(unmaskirq, unmaskirq);
|
||||
ide_ext_devset_rw_sync(using_dma, using_dma);
|
||||
__IDE_DEVSET(pio_mode, DS_SYNC, NULL, set_pio_mode);
|
||||
|
||||
int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
|
||||
int arg)
|
||||
{
|
||||
struct request_queue *q = drive->queue;
|
||||
struct request *rq;
|
||||
int ret = 0;
|
||||
|
||||
if (!(setting->flags & DS_SYNC))
|
||||
return setting->set(drive, arg);
|
||||
|
||||
rq = blk_get_request(q, READ, __GFP_WAIT);
|
||||
rq->cmd_type = REQ_TYPE_SPECIAL;
|
||||
rq->cmd_len = 5;
|
||||
rq->cmd[0] = REQ_DEVSET_EXEC;
|
||||
*(int *)&rq->cmd[1] = arg;
|
||||
rq->special = setting->set;
|
||||
|
||||
if (blk_execute_rq(q, NULL, rq, 0))
|
||||
ret = rq->errors;
|
||||
blk_put_request(rq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
ide_startstop_t ide_do_devset(ide_drive_t *drive, struct request *rq)
|
||||
{
|
||||
int err, (*setfunc)(ide_drive_t *, int) = rq->special;
|
||||
|
||||
err = setfunc(drive, *(int *)&rq->cmd[1]);
|
||||
if (err)
|
||||
rq->errors = err;
|
||||
else
|
||||
err = 1;
|
||||
ide_end_request(drive, err, 0);
|
||||
return ide_stopped;
|
||||
}
|
||||
@@ -470,6 +470,63 @@ void ide_dma_timeout(ide_drive_t *drive)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_dma_timeout);
|
||||
|
||||
/*
|
||||
* un-busy the port etc, and clear any pending DMA status. we want to
|
||||
* retry the current request in pio mode instead of risking tossing it
|
||||
* all away
|
||||
*/
|
||||
ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct request *rq;
|
||||
ide_startstop_t ret = ide_stopped;
|
||||
|
||||
/*
|
||||
* end current dma transaction
|
||||
*/
|
||||
|
||||
if (error < 0) {
|
||||
printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
|
||||
(void)hwif->dma_ops->dma_end(drive);
|
||||
ret = ide_error(drive, "dma timeout error",
|
||||
hwif->tp_ops->read_status(hwif));
|
||||
} else {
|
||||
printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
|
||||
hwif->dma_ops->dma_timeout(drive);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable dma for now, but remember that we did so because of
|
||||
* a timeout -- we'll reenable after we finish this next request
|
||||
* (or rather the first chunk of it) in pio.
|
||||
*/
|
||||
drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
|
||||
drive->retry_pio++;
|
||||
ide_dma_off_quietly(drive);
|
||||
|
||||
/*
|
||||
* un-busy drive etc and make sure request is sane
|
||||
*/
|
||||
|
||||
rq = hwif->rq;
|
||||
if (!rq)
|
||||
goto out;
|
||||
|
||||
hwif->rq = NULL;
|
||||
|
||||
rq->errors = 0;
|
||||
|
||||
if (!rq->bio)
|
||||
goto out;
|
||||
|
||||
rq->sector = rq->bio->bi_sector;
|
||||
rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
|
||||
rq->hard_cur_sectors = rq->current_nr_sectors;
|
||||
rq->buffer = bio_data(rq->bio);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ide_release_dma_engine(ide_hwif_t *hwif)
|
||||
{
|
||||
if (hwif->dmatable_cpu) {
|
||||
|
||||
@@ -0,0 +1,428 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ide.h>
|
||||
#include <linux/delay.h>
|
||||
|
||||
static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq,
|
||||
u8 stat, u8 err)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
if ((stat & ATA_BUSY) ||
|
||||
((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
|
||||
/* other bits are useless when BUSY */
|
||||
rq->errors |= ERROR_RESET;
|
||||
} else if (stat & ATA_ERR) {
|
||||
/* err has different meaning on cdrom and tape */
|
||||
if (err == ATA_ABORTED) {
|
||||
if ((drive->dev_flags & IDE_DFLAG_LBA) &&
|
||||
/* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
|
||||
hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
|
||||
return ide_stopped;
|
||||
} else if ((err & BAD_CRC) == BAD_CRC) {
|
||||
/* UDMA crc error, just retry the operation */
|
||||
drive->crc_count++;
|
||||
} else if (err & (ATA_BBK | ATA_UNC)) {
|
||||
/* retries won't help these */
|
||||
rq->errors = ERROR_MAX;
|
||||
} else if (err & ATA_TRK0NF) {
|
||||
/* help it find track zero */
|
||||
rq->errors |= ERROR_RECAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
|
||||
(hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
|
||||
int nsect = drive->mult_count ? drive->mult_count : 1;
|
||||
|
||||
ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
|
||||
}
|
||||
|
||||
if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
|
||||
ide_kill_rq(drive, rq);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
|
||||
rq->errors |= ERROR_RESET;
|
||||
|
||||
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
|
||||
++rq->errors;
|
||||
return ide_do_reset(drive);
|
||||
}
|
||||
|
||||
if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
|
||||
drive->special.b.recalibrate = 1;
|
||||
|
||||
++rq->errors;
|
||||
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq,
|
||||
u8 stat, u8 err)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
if ((stat & ATA_BUSY) ||
|
||||
((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
|
||||
/* other bits are useless when BUSY */
|
||||
rq->errors |= ERROR_RESET;
|
||||
} else {
|
||||
/* add decoding error stuff */
|
||||
}
|
||||
|
||||
if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
|
||||
/* force an abort */
|
||||
hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
|
||||
|
||||
if (rq->errors >= ERROR_MAX) {
|
||||
ide_kill_rq(drive, rq);
|
||||
} else {
|
||||
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
|
||||
++rq->errors;
|
||||
return ide_do_reset(drive);
|
||||
}
|
||||
++rq->errors;
|
||||
}
|
||||
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static ide_startstop_t __ide_error(ide_drive_t *drive, struct request *rq,
|
||||
u8 stat, u8 err)
|
||||
{
|
||||
if (drive->media == ide_disk)
|
||||
return ide_ata_error(drive, rq, stat, err);
|
||||
return ide_atapi_error(drive, rq, stat, err);
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_error - handle an error on the IDE
|
||||
* @drive: drive the error occurred on
|
||||
* @msg: message to report
|
||||
* @stat: status bits
|
||||
*
|
||||
* ide_error() takes action based on the error returned by the drive.
|
||||
* For normal I/O that may well include retries. We deal with
|
||||
* both new-style (taskfile) and old style command handling here.
|
||||
* In the case of taskfile command handling there is work left to
|
||||
* do
|
||||
*/
|
||||
|
||||
ide_startstop_t ide_error(ide_drive_t *drive, const char *msg, u8 stat)
|
||||
{
|
||||
struct request *rq;
|
||||
u8 err;
|
||||
|
||||
err = ide_dump_status(drive, msg, stat);
|
||||
|
||||
rq = drive->hwif->rq;
|
||||
if (rq == NULL)
|
||||
return ide_stopped;
|
||||
|
||||
/* retry only "normal" I/O: */
|
||||
if (!blk_fs_request(rq)) {
|
||||
rq->errors = 1;
|
||||
ide_end_drive_cmd(drive, stat, err);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
return __ide_error(drive, rq, stat, err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_error);
|
||||
|
||||
static inline void ide_complete_drive_reset(ide_drive_t *drive, int err)
|
||||
{
|
||||
struct request *rq = drive->hwif->rq;
|
||||
|
||||
if (rq && blk_special_request(rq) && rq->cmd[0] == REQ_DRIVE_RESET)
|
||||
ide_end_request(drive, err ? err : 1, 0);
|
||||
}
|
||||
|
||||
/* needed below */
|
||||
static ide_startstop_t do_reset1(ide_drive_t *, int);
|
||||
|
||||
/*
|
||||
* atapi_reset_pollfunc() gets invoked to poll the interface for completion
|
||||
* every 50ms during an atapi drive reset operation. If the drive has not yet
|
||||
* responded, and we have not yet hit our maximum waiting time, then the timer
|
||||
* is restarted for another 50ms.
|
||||
*/
|
||||
static ide_startstop_t atapi_reset_pollfunc(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
u8 stat;
|
||||
|
||||
SELECT_DRIVE(drive);
|
||||
udelay(10);
|
||||
stat = hwif->tp_ops->read_status(hwif);
|
||||
|
||||
if (OK_STAT(stat, 0, ATA_BUSY))
|
||||
printk(KERN_INFO "%s: ATAPI reset complete\n", drive->name);
|
||||
else {
|
||||
if (time_before(jiffies, hwif->poll_timeout)) {
|
||||
ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20,
|
||||
NULL);
|
||||
/* continue polling */
|
||||
return ide_started;
|
||||
}
|
||||
/* end of polling */
|
||||
hwif->polling = 0;
|
||||
printk(KERN_ERR "%s: ATAPI reset timed-out, status=0x%02x\n",
|
||||
drive->name, stat);
|
||||
/* do it the old fashioned way */
|
||||
return do_reset1(drive, 1);
|
||||
}
|
||||
/* done polling */
|
||||
hwif->polling = 0;
|
||||
ide_complete_drive_reset(drive, 0);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static void ide_reset_report_error(ide_hwif_t *hwif, u8 err)
|
||||
{
|
||||
static const char *err_master_vals[] =
|
||||
{ NULL, "passed", "formatter device error",
|
||||
"sector buffer error", "ECC circuitry error",
|
||||
"controlling MPU error" };
|
||||
|
||||
u8 err_master = err & 0x7f;
|
||||
|
||||
printk(KERN_ERR "%s: reset: master: ", hwif->name);
|
||||
if (err_master && err_master < 6)
|
||||
printk(KERN_CONT "%s", err_master_vals[err_master]);
|
||||
else
|
||||
printk(KERN_CONT "error (0x%02x?)", err);
|
||||
if (err & 0x80)
|
||||
printk(KERN_CONT "; slave: failed");
|
||||
printk(KERN_CONT "\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* reset_pollfunc() gets invoked to poll the interface for completion every 50ms
|
||||
* during an ide reset operation. If the drives have not yet responded,
|
||||
* and we have not yet hit our maximum waiting time, then the timer is restarted
|
||||
* for another 50ms.
|
||||
*/
|
||||
static ide_startstop_t reset_pollfunc(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
const struct ide_port_ops *port_ops = hwif->port_ops;
|
||||
u8 tmp;
|
||||
int err = 0;
|
||||
|
||||
if (port_ops && port_ops->reset_poll) {
|
||||
err = port_ops->reset_poll(drive);
|
||||
if (err) {
|
||||
printk(KERN_ERR "%s: host reset_poll failure for %s.\n",
|
||||
hwif->name, drive->name);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
tmp = hwif->tp_ops->read_status(hwif);
|
||||
|
||||
if (!OK_STAT(tmp, 0, ATA_BUSY)) {
|
||||
if (time_before(jiffies, hwif->poll_timeout)) {
|
||||
ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
|
||||
/* continue polling */
|
||||
return ide_started;
|
||||
}
|
||||
printk(KERN_ERR "%s: reset timed-out, status=0x%02x\n",
|
||||
hwif->name, tmp);
|
||||
drive->failures++;
|
||||
err = -EIO;
|
||||
} else {
|
||||
tmp = ide_read_error(drive);
|
||||
|
||||
if (tmp == 1) {
|
||||
printk(KERN_INFO "%s: reset: success\n", hwif->name);
|
||||
drive->failures = 0;
|
||||
} else {
|
||||
ide_reset_report_error(hwif, tmp);
|
||||
drive->failures++;
|
||||
err = -EIO;
|
||||
}
|
||||
}
|
||||
out:
|
||||
hwif->polling = 0; /* done polling */
|
||||
ide_complete_drive_reset(drive, err);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static void ide_disk_pre_reset(ide_drive_t *drive)
|
||||
{
|
||||
int legacy = (drive->id[ATA_ID_CFS_ENABLE_2] & 0x0400) ? 0 : 1;
|
||||
|
||||
drive->special.all = 0;
|
||||
drive->special.b.set_geometry = legacy;
|
||||
drive->special.b.recalibrate = legacy;
|
||||
|
||||
drive->mult_count = 0;
|
||||
drive->dev_flags &= ~IDE_DFLAG_PARKED;
|
||||
|
||||
if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0 &&
|
||||
(drive->dev_flags & IDE_DFLAG_USING_DMA) == 0)
|
||||
drive->mult_req = 0;
|
||||
|
||||
if (drive->mult_req != drive->mult_count)
|
||||
drive->special.b.set_multmode = 1;
|
||||
}
|
||||
|
||||
static void pre_reset(ide_drive_t *drive)
|
||||
{
|
||||
const struct ide_port_ops *port_ops = drive->hwif->port_ops;
|
||||
|
||||
if (drive->media == ide_disk)
|
||||
ide_disk_pre_reset(drive);
|
||||
else
|
||||
drive->dev_flags |= IDE_DFLAG_POST_RESET;
|
||||
|
||||
if (drive->dev_flags & IDE_DFLAG_USING_DMA) {
|
||||
if (drive->crc_count)
|
||||
ide_check_dma_crc(drive);
|
||||
else
|
||||
ide_dma_off(drive);
|
||||
}
|
||||
|
||||
if ((drive->dev_flags & IDE_DFLAG_KEEP_SETTINGS) == 0) {
|
||||
if ((drive->dev_flags & IDE_DFLAG_USING_DMA) == 0) {
|
||||
drive->dev_flags &= ~IDE_DFLAG_UNMASK;
|
||||
drive->io_32bit = 0;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (port_ops && port_ops->pre_reset)
|
||||
port_ops->pre_reset(drive);
|
||||
|
||||
if (drive->current_speed != 0xff)
|
||||
drive->desired_speed = drive->current_speed;
|
||||
drive->current_speed = 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* do_reset1() attempts to recover a confused drive by resetting it.
|
||||
* Unfortunately, resetting a disk drive actually resets all devices on
|
||||
* the same interface, so it can really be thought of as resetting the
|
||||
* interface rather than resetting the drive.
|
||||
*
|
||||
* ATAPI devices have their own reset mechanism which allows them to be
|
||||
* individually reset without clobbering other devices on the same interface.
|
||||
*
|
||||
* Unfortunately, the IDE interface does not generate an interrupt to let
|
||||
* us know when the reset operation has finished, so we must poll for this.
|
||||
* Equally poor, though, is the fact that this may a very long time to complete,
|
||||
* (up to 30 seconds worstcase). So, instead of busy-waiting here for it,
|
||||
* we set a timer to poll at 50ms intervals.
|
||||
*/
|
||||
static ide_startstop_t do_reset1(ide_drive_t *drive, int do_not_try_atapi)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct ide_io_ports *io_ports = &hwif->io_ports;
|
||||
const struct ide_tp_ops *tp_ops = hwif->tp_ops;
|
||||
const struct ide_port_ops *port_ops;
|
||||
ide_drive_t *tdrive;
|
||||
unsigned long flags, timeout;
|
||||
int i;
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
spin_lock_irqsave(&hwif->lock, flags);
|
||||
|
||||
/* We must not reset with running handlers */
|
||||
BUG_ON(hwif->handler != NULL);
|
||||
|
||||
/* For an ATAPI device, first try an ATAPI SRST. */
|
||||
if (drive->media != ide_disk && !do_not_try_atapi) {
|
||||
pre_reset(drive);
|
||||
SELECT_DRIVE(drive);
|
||||
udelay(20);
|
||||
tp_ops->exec_command(hwif, ATA_CMD_DEV_RESET);
|
||||
ndelay(400);
|
||||
hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
|
||||
hwif->polling = 1;
|
||||
__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);
|
||||
spin_unlock_irqrestore(&hwif->lock, flags);
|
||||
return ide_started;
|
||||
}
|
||||
|
||||
/* We must not disturb devices in the IDE_DFLAG_PARKED state. */
|
||||
do {
|
||||
unsigned long now;
|
||||
|
||||
prepare_to_wait(&ide_park_wq, &wait, TASK_UNINTERRUPTIBLE);
|
||||
timeout = jiffies;
|
||||
ide_port_for_each_present_dev(i, tdrive, hwif) {
|
||||
if ((tdrive->dev_flags & IDE_DFLAG_PARKED) &&
|
||||
time_after(tdrive->sleep, timeout))
|
||||
timeout = tdrive->sleep;
|
||||
}
|
||||
|
||||
now = jiffies;
|
||||
if (time_before_eq(timeout, now))
|
||||
break;
|
||||
|
||||
spin_unlock_irqrestore(&hwif->lock, flags);
|
||||
timeout = schedule_timeout_uninterruptible(timeout - now);
|
||||
spin_lock_irqsave(&hwif->lock, flags);
|
||||
} while (timeout);
|
||||
finish_wait(&ide_park_wq, &wait);
|
||||
|
||||
/*
|
||||
* First, reset any device state data we were maintaining
|
||||
* for any of the drives on this interface.
|
||||
*/
|
||||
ide_port_for_each_dev(i, tdrive, hwif)
|
||||
pre_reset(tdrive);
|
||||
|
||||
if (io_ports->ctl_addr == 0) {
|
||||
spin_unlock_irqrestore(&hwif->lock, flags);
|
||||
ide_complete_drive_reset(drive, -ENXIO);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
/*
|
||||
* Note that we also set nIEN while resetting the device,
|
||||
* to mask unwanted interrupts from the interface during the reset.
|
||||
* However, due to the design of PC hardware, this will cause an
|
||||
* immediate interrupt due to the edge transition it produces.
|
||||
* This single interrupt gives us a "fast poll" for drives that
|
||||
* recover from reset very quickly, saving us the first 50ms wait time.
|
||||
*
|
||||
* TODO: add ->softreset method and stop abusing ->set_irq
|
||||
*/
|
||||
/* set SRST and nIEN */
|
||||
tp_ops->set_irq(hwif, 4);
|
||||
/* more than enough time */
|
||||
udelay(10);
|
||||
/* clear SRST, leave nIEN (unless device is on the quirk list) */
|
||||
tp_ops->set_irq(hwif, drive->quirk_list == 2);
|
||||
/* more than enough time */
|
||||
udelay(10);
|
||||
hwif->poll_timeout = jiffies + WAIT_WORSTCASE;
|
||||
hwif->polling = 1;
|
||||
__ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);
|
||||
|
||||
/*
|
||||
* Some weird controller like resetting themselves to a strange
|
||||
* state when the disks are reset this way. At least, the Winbond
|
||||
* 553 documentation says that
|
||||
*/
|
||||
port_ops = hwif->port_ops;
|
||||
if (port_ops && port_ops->resetproc)
|
||||
port_ops->resetproc(drive);
|
||||
|
||||
spin_unlock_irqrestore(&hwif->lock, flags);
|
||||
return ide_started;
|
||||
}
|
||||
|
||||
/*
|
||||
* ide_do_reset() is the entry point to the drive/interface reset code.
|
||||
*/
|
||||
|
||||
ide_startstop_t ide_do_reset(ide_drive_t *drive)
|
||||
{
|
||||
return do_reset1(drive, 0);
|
||||
}
|
||||
EXPORT_SYMBOL(ide_do_reset);
|
||||
@@ -0,0 +1,316 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/ide.h>
|
||||
|
||||
/*
|
||||
* Conventional PIO operations for ATA devices
|
||||
*/
|
||||
|
||||
static u8 ide_inb(unsigned long port)
|
||||
{
|
||||
return (u8) inb(port);
|
||||
}
|
||||
|
||||
static void ide_outb(u8 val, unsigned long port)
|
||||
{
|
||||
outb(val, port);
|
||||
}
|
||||
|
||||
/*
|
||||
* MMIO operations, typically used for SATA controllers
|
||||
*/
|
||||
|
||||
static u8 ide_mm_inb(unsigned long port)
|
||||
{
|
||||
return (u8) readb((void __iomem *) port);
|
||||
}
|
||||
|
||||
static void ide_mm_outb(u8 value, unsigned long port)
|
||||
{
|
||||
writeb(value, (void __iomem *) port);
|
||||
}
|
||||
|
||||
void ide_exec_command(ide_hwif_t *hwif, u8 cmd)
|
||||
{
|
||||
if (hwif->host_flags & IDE_HFLAG_MMIO)
|
||||
writeb(cmd, (void __iomem *)hwif->io_ports.command_addr);
|
||||
else
|
||||
outb(cmd, hwif->io_ports.command_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_exec_command);
|
||||
|
||||
u8 ide_read_status(ide_hwif_t *hwif)
|
||||
{
|
||||
if (hwif->host_flags & IDE_HFLAG_MMIO)
|
||||
return readb((void __iomem *)hwif->io_ports.status_addr);
|
||||
else
|
||||
return inb(hwif->io_ports.status_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_read_status);
|
||||
|
||||
u8 ide_read_altstatus(ide_hwif_t *hwif)
|
||||
{
|
||||
if (hwif->host_flags & IDE_HFLAG_MMIO)
|
||||
return readb((void __iomem *)hwif->io_ports.ctl_addr);
|
||||
else
|
||||
return inb(hwif->io_ports.ctl_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_read_altstatus);
|
||||
|
||||
void ide_set_irq(ide_hwif_t *hwif, int on)
|
||||
{
|
||||
u8 ctl = ATA_DEVCTL_OBS;
|
||||
|
||||
if (on == 4) { /* hack for SRST */
|
||||
ctl |= 4;
|
||||
on &= ~4;
|
||||
}
|
||||
|
||||
ctl |= on ? 0 : 2;
|
||||
|
||||
if (hwif->host_flags & IDE_HFLAG_MMIO)
|
||||
writeb(ctl, (void __iomem *)hwif->io_ports.ctl_addr);
|
||||
else
|
||||
outb(ctl, hwif->io_ports.ctl_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_set_irq);
|
||||
|
||||
void ide_tf_load(ide_drive_t *drive, ide_task_t *task)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct ide_io_ports *io_ports = &hwif->io_ports;
|
||||
struct ide_taskfile *tf = &task->tf;
|
||||
void (*tf_outb)(u8 addr, unsigned long port);
|
||||
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
|
||||
u8 HIHI = (task->tf_flags & IDE_TFLAG_LBA48) ? 0xE0 : 0xEF;
|
||||
|
||||
if (mmio)
|
||||
tf_outb = ide_mm_outb;
|
||||
else
|
||||
tf_outb = ide_outb;
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_FLAGGED)
|
||||
HIHI = 0xFF;
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_DATA) {
|
||||
u16 data = (tf->hob_data << 8) | tf->data;
|
||||
|
||||
if (mmio)
|
||||
writew(data, (void __iomem *)io_ports->data_addr);
|
||||
else
|
||||
outw(data, io_ports->data_addr);
|
||||
}
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_HOB_FEATURE)
|
||||
tf_outb(tf->hob_feature, io_ports->feature_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_HOB_NSECT)
|
||||
tf_outb(tf->hob_nsect, io_ports->nsect_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAL)
|
||||
tf_outb(tf->hob_lbal, io_ports->lbal_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAM)
|
||||
tf_outb(tf->hob_lbam, io_ports->lbam_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_HOB_LBAH)
|
||||
tf_outb(tf->hob_lbah, io_ports->lbah_addr);
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_FEATURE)
|
||||
tf_outb(tf->feature, io_ports->feature_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_NSECT)
|
||||
tf_outb(tf->nsect, io_ports->nsect_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_LBAL)
|
||||
tf_outb(tf->lbal, io_ports->lbal_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_LBAM)
|
||||
tf_outb(tf->lbam, io_ports->lbam_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_LBAH)
|
||||
tf_outb(tf->lbah, io_ports->lbah_addr);
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_OUT_DEVICE)
|
||||
tf_outb((tf->device & HIHI) | drive->select,
|
||||
io_ports->device_addr);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_tf_load);
|
||||
|
||||
void ide_tf_read(ide_drive_t *drive, ide_task_t *task)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct ide_io_ports *io_ports = &hwif->io_ports;
|
||||
struct ide_taskfile *tf = &task->tf;
|
||||
void (*tf_outb)(u8 addr, unsigned long port);
|
||||
u8 (*tf_inb)(unsigned long port);
|
||||
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
|
||||
|
||||
if (mmio) {
|
||||
tf_outb = ide_mm_outb;
|
||||
tf_inb = ide_mm_inb;
|
||||
} else {
|
||||
tf_outb = ide_outb;
|
||||
tf_inb = ide_inb;
|
||||
}
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_IN_DATA) {
|
||||
u16 data;
|
||||
|
||||
if (mmio)
|
||||
data = readw((void __iomem *)io_ports->data_addr);
|
||||
else
|
||||
data = inw(io_ports->data_addr);
|
||||
|
||||
tf->data = data & 0xff;
|
||||
tf->hob_data = (data >> 8) & 0xff;
|
||||
}
|
||||
|
||||
/* be sure we're looking at the low order bits */
|
||||
tf_outb(ATA_DEVCTL_OBS & ~0x80, io_ports->ctl_addr);
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_IN_FEATURE)
|
||||
tf->feature = tf_inb(io_ports->feature_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_NSECT)
|
||||
tf->nsect = tf_inb(io_ports->nsect_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_LBAL)
|
||||
tf->lbal = tf_inb(io_ports->lbal_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_LBAM)
|
||||
tf->lbam = tf_inb(io_ports->lbam_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_LBAH)
|
||||
tf->lbah = tf_inb(io_ports->lbah_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_DEVICE)
|
||||
tf->device = tf_inb(io_ports->device_addr);
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_LBA48) {
|
||||
tf_outb(ATA_DEVCTL_OBS | 0x80, io_ports->ctl_addr);
|
||||
|
||||
if (task->tf_flags & IDE_TFLAG_IN_HOB_FEATURE)
|
||||
tf->hob_feature = tf_inb(io_ports->feature_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_HOB_NSECT)
|
||||
tf->hob_nsect = tf_inb(io_ports->nsect_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAL)
|
||||
tf->hob_lbal = tf_inb(io_ports->lbal_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAM)
|
||||
tf->hob_lbam = tf_inb(io_ports->lbam_addr);
|
||||
if (task->tf_flags & IDE_TFLAG_IN_HOB_LBAH)
|
||||
tf->hob_lbah = tf_inb(io_ports->lbah_addr);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_tf_read);
|
||||
|
||||
/*
|
||||
* Some localbus EIDE interfaces require a special access sequence
|
||||
* when using 32-bit I/O instructions to transfer data. We call this
|
||||
* the "vlb_sync" sequence, which consists of three successive reads
|
||||
* of the sector count register location, with interrupts disabled
|
||||
* to ensure that the reads all happen together.
|
||||
*/
|
||||
static void ata_vlb_sync(unsigned long port)
|
||||
{
|
||||
(void)inb(port);
|
||||
(void)inb(port);
|
||||
(void)inb(port);
|
||||
}
|
||||
|
||||
/*
|
||||
* This is used for most PIO data transfers *from* the IDE interface
|
||||
*
|
||||
* These routines will round up any request for an odd number of bytes,
|
||||
* so if an odd len is specified, be sure that there's at least one
|
||||
* extra byte allocated for the buffer.
|
||||
*/
|
||||
void ide_input_data(ide_drive_t *drive, struct request *rq, void *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct ide_io_ports *io_ports = &hwif->io_ports;
|
||||
unsigned long data_addr = io_ports->data_addr;
|
||||
u8 io_32bit = drive->io_32bit;
|
||||
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
|
||||
|
||||
len++;
|
||||
|
||||
if (io_32bit) {
|
||||
unsigned long uninitialized_var(flags);
|
||||
|
||||
if ((io_32bit & 2) && !mmio) {
|
||||
local_irq_save(flags);
|
||||
ata_vlb_sync(io_ports->nsect_addr);
|
||||
}
|
||||
|
||||
if (mmio)
|
||||
__ide_mm_insl((void __iomem *)data_addr, buf, len / 4);
|
||||
else
|
||||
insl(data_addr, buf, len / 4);
|
||||
|
||||
if ((io_32bit & 2) && !mmio)
|
||||
local_irq_restore(flags);
|
||||
|
||||
if ((len & 3) >= 2) {
|
||||
if (mmio)
|
||||
__ide_mm_insw((void __iomem *)data_addr,
|
||||
(u8 *)buf + (len & ~3), 1);
|
||||
else
|
||||
insw(data_addr, (u8 *)buf + (len & ~3), 1);
|
||||
}
|
||||
} else {
|
||||
if (mmio)
|
||||
__ide_mm_insw((void __iomem *)data_addr, buf, len / 2);
|
||||
else
|
||||
insw(data_addr, buf, len / 2);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_input_data);
|
||||
|
||||
/*
|
||||
* This is used for most PIO data transfers *to* the IDE interface
|
||||
*/
|
||||
void ide_output_data(ide_drive_t *drive, struct request *rq, void *buf,
|
||||
unsigned int len)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct ide_io_ports *io_ports = &hwif->io_ports;
|
||||
unsigned long data_addr = io_ports->data_addr;
|
||||
u8 io_32bit = drive->io_32bit;
|
||||
u8 mmio = (hwif->host_flags & IDE_HFLAG_MMIO) ? 1 : 0;
|
||||
|
||||
len++;
|
||||
|
||||
if (io_32bit) {
|
||||
unsigned long uninitialized_var(flags);
|
||||
|
||||
if ((io_32bit & 2) && !mmio) {
|
||||
local_irq_save(flags);
|
||||
ata_vlb_sync(io_ports->nsect_addr);
|
||||
}
|
||||
|
||||
if (mmio)
|
||||
__ide_mm_outsl((void __iomem *)data_addr, buf, len / 4);
|
||||
else
|
||||
outsl(data_addr, buf, len / 4);
|
||||
|
||||
if ((io_32bit & 2) && !mmio)
|
||||
local_irq_restore(flags);
|
||||
|
||||
if ((len & 3) >= 2) {
|
||||
if (mmio)
|
||||
__ide_mm_outsw((void __iomem *)data_addr,
|
||||
(u8 *)buf + (len & ~3), 1);
|
||||
else
|
||||
outsw(data_addr, (u8 *)buf + (len & ~3), 1);
|
||||
}
|
||||
} else {
|
||||
if (mmio)
|
||||
__ide_mm_outsw((void __iomem *)data_addr, buf, len / 2);
|
||||
else
|
||||
outsw(data_addr, buf, len / 2);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_output_data);
|
||||
|
||||
const struct ide_tp_ops default_tp_ops = {
|
||||
.exec_command = ide_exec_command,
|
||||
.read_status = ide_read_status,
|
||||
.read_altstatus = ide_read_altstatus,
|
||||
|
||||
.set_irq = ide_set_irq,
|
||||
|
||||
.tf_load = ide_tf_load,
|
||||
.tf_read = ide_tf_read,
|
||||
|
||||
.input_data = ide_input_data,
|
||||
.output_data = ide_output_data,
|
||||
};
|
||||
+28
-292
@@ -196,7 +196,7 @@ void ide_end_drive_cmd (ide_drive_t *drive, u8 stat, u8 err)
|
||||
}
|
||||
EXPORT_SYMBOL(ide_end_drive_cmd);
|
||||
|
||||
static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
|
||||
void ide_kill_rq(ide_drive_t *drive, struct request *rq)
|
||||
{
|
||||
if (rq->rq_disk) {
|
||||
struct ide_driver *drv;
|
||||
@@ -207,133 +207,6 @@ static void ide_kill_rq(ide_drive_t *drive, struct request *rq)
|
||||
ide_end_request(drive, 0, 0);
|
||||
}
|
||||
|
||||
static ide_startstop_t ide_ata_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
if ((stat & ATA_BUSY) ||
|
||||
((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
|
||||
/* other bits are useless when BUSY */
|
||||
rq->errors |= ERROR_RESET;
|
||||
} else if (stat & ATA_ERR) {
|
||||
/* err has different meaning on cdrom and tape */
|
||||
if (err == ATA_ABORTED) {
|
||||
if ((drive->dev_flags & IDE_DFLAG_LBA) &&
|
||||
/* some newer drives don't support ATA_CMD_INIT_DEV_PARAMS */
|
||||
hwif->tp_ops->read_status(hwif) == ATA_CMD_INIT_DEV_PARAMS)
|
||||
return ide_stopped;
|
||||
} else if ((err & BAD_CRC) == BAD_CRC) {
|
||||
/* UDMA crc error, just retry the operation */
|
||||
drive->crc_count++;
|
||||
} else if (err & (ATA_BBK | ATA_UNC)) {
|
||||
/* retries won't help these */
|
||||
rq->errors = ERROR_MAX;
|
||||
} else if (err & ATA_TRK0NF) {
|
||||
/* help it find track zero */
|
||||
rq->errors |= ERROR_RECAL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((stat & ATA_DRQ) && rq_data_dir(rq) == READ &&
|
||||
(hwif->host_flags & IDE_HFLAG_ERROR_STOPS_FIFO) == 0) {
|
||||
int nsect = drive->mult_count ? drive->mult_count : 1;
|
||||
|
||||
ide_pad_transfer(drive, READ, nsect * SECTOR_SIZE);
|
||||
}
|
||||
|
||||
if (rq->errors >= ERROR_MAX || blk_noretry_request(rq)) {
|
||||
ide_kill_rq(drive, rq);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
|
||||
rq->errors |= ERROR_RESET;
|
||||
|
||||
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
|
||||
++rq->errors;
|
||||
return ide_do_reset(drive);
|
||||
}
|
||||
|
||||
if ((rq->errors & ERROR_RECAL) == ERROR_RECAL)
|
||||
drive->special.b.recalibrate = 1;
|
||||
|
||||
++rq->errors;
|
||||
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static ide_startstop_t ide_atapi_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
if ((stat & ATA_BUSY) ||
|
||||
((stat & ATA_DF) && (drive->dev_flags & IDE_DFLAG_NOWERR) == 0)) {
|
||||
/* other bits are useless when BUSY */
|
||||
rq->errors |= ERROR_RESET;
|
||||
} else {
|
||||
/* add decoding error stuff */
|
||||
}
|
||||
|
||||
if (hwif->tp_ops->read_status(hwif) & (ATA_BUSY | ATA_DRQ))
|
||||
/* force an abort */
|
||||
hwif->tp_ops->exec_command(hwif, ATA_CMD_IDLEIMMEDIATE);
|
||||
|
||||
if (rq->errors >= ERROR_MAX) {
|
||||
ide_kill_rq(drive, rq);
|
||||
} else {
|
||||
if ((rq->errors & ERROR_RESET) == ERROR_RESET) {
|
||||
++rq->errors;
|
||||
return ide_do_reset(drive);
|
||||
}
|
||||
++rq->errors;
|
||||
}
|
||||
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
static ide_startstop_t
|
||||
__ide_error(ide_drive_t *drive, struct request *rq, u8 stat, u8 err)
|
||||
{
|
||||
if (drive->media == ide_disk)
|
||||
return ide_ata_error(drive, rq, stat, err);
|
||||
return ide_atapi_error(drive, rq, stat, err);
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_error - handle an error on the IDE
|
||||
* @drive: drive the error occurred on
|
||||
* @msg: message to report
|
||||
* @stat: status bits
|
||||
*
|
||||
* ide_error() takes action based on the error returned by the drive.
|
||||
* For normal I/O that may well include retries. We deal with
|
||||
* both new-style (taskfile) and old style command handling here.
|
||||
* In the case of taskfile command handling there is work left to
|
||||
* do
|
||||
*/
|
||||
|
||||
ide_startstop_t ide_error (ide_drive_t *drive, const char *msg, u8 stat)
|
||||
{
|
||||
struct request *rq;
|
||||
u8 err;
|
||||
|
||||
err = ide_dump_status(drive, msg, stat);
|
||||
|
||||
rq = drive->hwif->rq;
|
||||
if (rq == NULL)
|
||||
return ide_stopped;
|
||||
|
||||
/* retry only "normal" I/O: */
|
||||
if (!blk_fs_request(rq)) {
|
||||
rq->errors = 1;
|
||||
ide_end_drive_cmd(drive, stat, err);
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
return __ide_error(drive, rq, stat, err);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_error);
|
||||
|
||||
static void ide_tf_set_specify_cmd(ide_drive_t *drive, struct ide_taskfile *tf)
|
||||
{
|
||||
tf->nsect = drive->sect;
|
||||
@@ -490,71 +363,16 @@ static ide_startstop_t execute_drive_cmd (ide_drive_t *drive,
|
||||
return ide_stopped;
|
||||
}
|
||||
|
||||
int ide_devset_execute(ide_drive_t *drive, const struct ide_devset *setting,
|
||||
int arg)
|
||||
{
|
||||
struct request_queue *q = drive->queue;
|
||||
struct request *rq;
|
||||
int ret = 0;
|
||||
|
||||
if (!(setting->flags & DS_SYNC))
|
||||
return setting->set(drive, arg);
|
||||
|
||||
rq = blk_get_request(q, READ, __GFP_WAIT);
|
||||
rq->cmd_type = REQ_TYPE_SPECIAL;
|
||||
rq->cmd_len = 5;
|
||||
rq->cmd[0] = REQ_DEVSET_EXEC;
|
||||
*(int *)&rq->cmd[1] = arg;
|
||||
rq->special = setting->set;
|
||||
|
||||
if (blk_execute_rq(q, NULL, rq, 0))
|
||||
ret = rq->errors;
|
||||
blk_put_request(rq);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_devset_execute);
|
||||
|
||||
static ide_startstop_t ide_special_rq(ide_drive_t *drive, struct request *rq)
|
||||
{
|
||||
u8 cmd = rq->cmd[0];
|
||||
|
||||
if (cmd == REQ_PARK_HEADS || cmd == REQ_UNPARK_HEADS) {
|
||||
ide_task_t task;
|
||||
struct ide_taskfile *tf = &task.tf;
|
||||
|
||||
memset(&task, 0, sizeof(task));
|
||||
if (cmd == REQ_PARK_HEADS) {
|
||||
drive->sleep = *(unsigned long *)rq->special;
|
||||
drive->dev_flags |= IDE_DFLAG_SLEEPING;
|
||||
tf->command = ATA_CMD_IDLEIMMEDIATE;
|
||||
tf->feature = 0x44;
|
||||
tf->lbal = 0x4c;
|
||||
tf->lbam = 0x4e;
|
||||
tf->lbah = 0x55;
|
||||
task.tf_flags |= IDE_TFLAG_CUSTOM_HANDLER;
|
||||
} else /* cmd == REQ_UNPARK_HEADS */
|
||||
tf->command = ATA_CMD_CHK_POWER;
|
||||
|
||||
task.tf_flags |= IDE_TFLAG_TF | IDE_TFLAG_DEVICE;
|
||||
task.rq = rq;
|
||||
drive->hwif->data_phase = task.data_phase = TASKFILE_NO_DATA;
|
||||
return do_rw_taskfile(drive, &task);
|
||||
}
|
||||
|
||||
switch (cmd) {
|
||||
case REQ_PARK_HEADS:
|
||||
case REQ_UNPARK_HEADS:
|
||||
return ide_do_park_unpark(drive, rq);
|
||||
case REQ_DEVSET_EXEC:
|
||||
{
|
||||
int err, (*setfunc)(ide_drive_t *, int) = rq->special;
|
||||
|
||||
err = setfunc(drive, *(int *)&rq->cmd[1]);
|
||||
if (err)
|
||||
rq->errors = err;
|
||||
else
|
||||
err = 1;
|
||||
ide_end_request(drive, err, 0);
|
||||
return ide_stopped;
|
||||
}
|
||||
return ide_do_devset(drive, rq);
|
||||
case REQ_DRIVE_RESET:
|
||||
return ide_do_reset(drive);
|
||||
default:
|
||||
@@ -820,63 +638,6 @@ plug_device_2:
|
||||
blk_plug_device(q);
|
||||
}
|
||||
|
||||
/*
|
||||
* un-busy the port etc, and clear any pending DMA status. we want to
|
||||
* retry the current request in pio mode instead of risking tossing it
|
||||
* all away
|
||||
*/
|
||||
static ide_startstop_t ide_dma_timeout_retry(ide_drive_t *drive, int error)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
struct request *rq;
|
||||
ide_startstop_t ret = ide_stopped;
|
||||
|
||||
/*
|
||||
* end current dma transaction
|
||||
*/
|
||||
|
||||
if (error < 0) {
|
||||
printk(KERN_WARNING "%s: DMA timeout error\n", drive->name);
|
||||
(void)hwif->dma_ops->dma_end(drive);
|
||||
ret = ide_error(drive, "dma timeout error",
|
||||
hwif->tp_ops->read_status(hwif));
|
||||
} else {
|
||||
printk(KERN_WARNING "%s: DMA timeout retry\n", drive->name);
|
||||
hwif->dma_ops->dma_timeout(drive);
|
||||
}
|
||||
|
||||
/*
|
||||
* disable dma for now, but remember that we did so because of
|
||||
* a timeout -- we'll reenable after we finish this next request
|
||||
* (or rather the first chunk of it) in pio.
|
||||
*/
|
||||
drive->dev_flags |= IDE_DFLAG_DMA_PIO_RETRY;
|
||||
drive->retry_pio++;
|
||||
ide_dma_off_quietly(drive);
|
||||
|
||||
/*
|
||||
* un-busy drive etc and make sure request is sane
|
||||
*/
|
||||
|
||||
rq = hwif->rq;
|
||||
if (!rq)
|
||||
goto out;
|
||||
|
||||
hwif->rq = NULL;
|
||||
|
||||
rq->errors = 0;
|
||||
|
||||
if (!rq->bio)
|
||||
goto out;
|
||||
|
||||
rq->sector = rq->bio->bi_sector;
|
||||
rq->current_nr_sectors = bio_iovec(rq->bio)->bv_len >> 9;
|
||||
rq->hard_cur_sectors = rq->current_nr_sectors;
|
||||
rq->buffer = bio_data(rq->bio);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ide_plug_device(ide_drive_t *drive)
|
||||
{
|
||||
struct request_queue *q = drive->queue;
|
||||
@@ -888,6 +649,29 @@ static void ide_plug_device(ide_drive_t *drive)
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
}
|
||||
|
||||
static int drive_is_ready(ide_drive_t *drive)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
u8 stat = 0;
|
||||
|
||||
if (drive->waiting_for_dma)
|
||||
return hwif->dma_ops->dma_test_irq(drive);
|
||||
|
||||
if (hwif->io_ports.ctl_addr &&
|
||||
(hwif->host_flags & IDE_HFLAG_BROKEN_ALTSTATUS) == 0)
|
||||
stat = hwif->tp_ops->read_altstatus(hwif);
|
||||
else
|
||||
/* Note: this may clear a pending IRQ!! */
|
||||
stat = hwif->tp_ops->read_status(hwif);
|
||||
|
||||
if (stat & ATA_BUSY)
|
||||
/* drive busy: definitely not interrupting */
|
||||
return 0;
|
||||
|
||||
/* drive ready: *might* be interrupting */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* ide_timer_expiry - handle lack of an IDE interrupt
|
||||
* @data: timer callback magic (hwif)
|
||||
@@ -1164,54 +948,6 @@ out_early:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(ide_intr);
|
||||
|
||||
/**
|
||||
* ide_do_drive_cmd - issue IDE special command
|
||||
* @drive: device to issue command
|
||||
* @rq: request to issue
|
||||
*
|
||||
* This function issues a special IDE device request
|
||||
* onto the request queue.
|
||||
*
|
||||
* the rq is queued at the head of the request queue, displacing
|
||||
* the currently-being-processed request and this function
|
||||
* returns immediately without waiting for the new rq to be
|
||||
* completed. This is VERY DANGEROUS, and is intended for
|
||||
* careful use by the ATAPI tape/cdrom driver code.
|
||||
*/
|
||||
|
||||
void ide_do_drive_cmd(ide_drive_t *drive, struct request *rq)
|
||||
{
|
||||
struct request_queue *q = drive->queue;
|
||||
unsigned long flags;
|
||||
|
||||
drive->hwif->rq = NULL;
|
||||
|
||||
spin_lock_irqsave(q->queue_lock, flags);
|
||||
__elv_add_request(q, rq, ELEVATOR_INSERT_FRONT, 0);
|
||||
spin_unlock_irqrestore(q->queue_lock, flags);
|
||||
}
|
||||
EXPORT_SYMBOL(ide_do_drive_cmd);
|
||||
|
||||
void ide_pktcmd_tf_load(ide_drive_t *drive, u32 tf_flags, u16 bcount, u8 dma)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
ide_task_t task;
|
||||
|
||||
memset(&task, 0, sizeof(task));
|
||||
task.tf_flags = IDE_TFLAG_OUT_LBAH | IDE_TFLAG_OUT_LBAM |
|
||||
IDE_TFLAG_OUT_FEATURE | tf_flags;
|
||||
task.tf.feature = dma; /* Use PIO/DMA */
|
||||
task.tf.lbam = bcount & 0xff;
|
||||
task.tf.lbah = (bcount >> 8) & 0xff;
|
||||
|
||||
ide_tf_dump(drive->name, &task.tf);
|
||||
hwif->tp_ops->set_irq(hwif, 1);
|
||||
SELECT_MASK(drive, 0);
|
||||
hwif->tp_ops->tf_load(drive, &task);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL_GPL(ide_pktcmd_tf_load);
|
||||
|
||||
void ide_pad_transfer(ide_drive_t *drive, int write, int len)
|
||||
{
|
||||
ide_hwif_t *hwif = drive->hwif;
|
||||
|
||||
+29
-713
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user