Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
1fdffbce
Commit
1fdffbce
authored
Feb 09, 2006
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[libata] Move PCI IDE BMDMA-related code to new file libata-bmdma.c.
parent
389984cb
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
724 additions
and
674 deletions
+724
-674
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-1
drivers/scsi/libata-bmdma.c
drivers/scsi/libata-bmdma.c
+703
-0
drivers/scsi/libata-core.c
drivers/scsi/libata-core.c
+20
-673
No files found.
drivers/scsi/Makefile
View file @
1fdffbce
...
...
@@ -163,7 +163,7 @@ ncr53c8xx-flags-$(CONFIG_SCSI_ZALON) \
CFLAGS_ncr53c8xx.o
:=
$
(
ncr53c8xx-flags-y
)
$
(
ncr53c8xx-flags-m
)
zalon7xx-objs
:=
zalon.o ncr53c8xx.o
NCR_Q720_mod-objs
:=
NCR_Q720.o ncr53c8xx.o
libata-objs
:=
libata-core.o libata-scsi.o
libata-objs
:=
libata-core.o libata-scsi.o
libata-bmdma.o
oktagon_esp_mod-objs
:=
oktagon_esp.o oktagon_io.o
# Files generated that shall be removed upon make clean
...
...
drivers/scsi/libata-bmdma.c
0 → 100644
View file @
1fdffbce
/*
* libata-bmdma.c - helper library for PCI IDE BMDMA
*
* Maintained by: Jeff Garzik <jgarzik@pobox.com>
* Please ALWAYS copy linux-ide@vger.kernel.org
* on emails.
*
* Copyright 2003-2006 Red Hat, Inc. All rights reserved.
* Copyright 2003-2006 Jeff Garzik
*
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*
* libata documentation is available via 'make {ps|pdf}docs',
* as Documentation/DocBook/libata.*
*
* Hardware documentation available from http://www.t13.org/ and
* http://www.sata-io.org/
*
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/pci.h>
#include <linux/libata.h>
#include "libata.h"
/**
* ata_tf_load_pio - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Outputs ATA taskfile to standard ATA host controller.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_load_pio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
unsigned
int
is_addr
=
tf
->
flags
&
ATA_TFLAG_ISADDR
;
if
(
tf
->
ctl
!=
ap
->
last_ctl
)
{
outb
(
tf
->
ctl
,
ioaddr
->
ctl_addr
);
ap
->
last_ctl
=
tf
->
ctl
;
ata_wait_idle
(
ap
);
}
if
(
is_addr
&&
(
tf
->
flags
&
ATA_TFLAG_LBA48
))
{
outb
(
tf
->
hob_feature
,
ioaddr
->
feature_addr
);
outb
(
tf
->
hob_nsect
,
ioaddr
->
nsect_addr
);
outb
(
tf
->
hob_lbal
,
ioaddr
->
lbal_addr
);
outb
(
tf
->
hob_lbam
,
ioaddr
->
lbam_addr
);
outb
(
tf
->
hob_lbah
,
ioaddr
->
lbah_addr
);
VPRINTK
(
"hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
hob_feature
,
tf
->
hob_nsect
,
tf
->
hob_lbal
,
tf
->
hob_lbam
,
tf
->
hob_lbah
);
}
if
(
is_addr
)
{
outb
(
tf
->
feature
,
ioaddr
->
feature_addr
);
outb
(
tf
->
nsect
,
ioaddr
->
nsect_addr
);
outb
(
tf
->
lbal
,
ioaddr
->
lbal_addr
);
outb
(
tf
->
lbam
,
ioaddr
->
lbam_addr
);
outb
(
tf
->
lbah
,
ioaddr
->
lbah_addr
);
VPRINTK
(
"feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
feature
,
tf
->
nsect
,
tf
->
lbal
,
tf
->
lbam
,
tf
->
lbah
);
}
if
(
tf
->
flags
&
ATA_TFLAG_DEVICE
)
{
outb
(
tf
->
device
,
ioaddr
->
device_addr
);
VPRINTK
(
"device 0x%X
\n
"
,
tf
->
device
);
}
ata_wait_idle
(
ap
);
}
/**
* ata_tf_load_mmio - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Outputs ATA taskfile to standard ATA host controller using MMIO.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_load_mmio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
unsigned
int
is_addr
=
tf
->
flags
&
ATA_TFLAG_ISADDR
;
if
(
tf
->
ctl
!=
ap
->
last_ctl
)
{
writeb
(
tf
->
ctl
,
(
void
__iomem
*
)
ap
->
ioaddr
.
ctl_addr
);
ap
->
last_ctl
=
tf
->
ctl
;
ata_wait_idle
(
ap
);
}
if
(
is_addr
&&
(
tf
->
flags
&
ATA_TFLAG_LBA48
))
{
writeb
(
tf
->
hob_feature
,
(
void
__iomem
*
)
ioaddr
->
feature_addr
);
writeb
(
tf
->
hob_nsect
,
(
void
__iomem
*
)
ioaddr
->
nsect_addr
);
writeb
(
tf
->
hob_lbal
,
(
void
__iomem
*
)
ioaddr
->
lbal_addr
);
writeb
(
tf
->
hob_lbam
,
(
void
__iomem
*
)
ioaddr
->
lbam_addr
);
writeb
(
tf
->
hob_lbah
,
(
void
__iomem
*
)
ioaddr
->
lbah_addr
);
VPRINTK
(
"hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
hob_feature
,
tf
->
hob_nsect
,
tf
->
hob_lbal
,
tf
->
hob_lbam
,
tf
->
hob_lbah
);
}
if
(
is_addr
)
{
writeb
(
tf
->
feature
,
(
void
__iomem
*
)
ioaddr
->
feature_addr
);
writeb
(
tf
->
nsect
,
(
void
__iomem
*
)
ioaddr
->
nsect_addr
);
writeb
(
tf
->
lbal
,
(
void
__iomem
*
)
ioaddr
->
lbal_addr
);
writeb
(
tf
->
lbam
,
(
void
__iomem
*
)
ioaddr
->
lbam_addr
);
writeb
(
tf
->
lbah
,
(
void
__iomem
*
)
ioaddr
->
lbah_addr
);
VPRINTK
(
"feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
feature
,
tf
->
nsect
,
tf
->
lbal
,
tf
->
lbam
,
tf
->
lbah
);
}
if
(
tf
->
flags
&
ATA_TFLAG_DEVICE
)
{
writeb
(
tf
->
device
,
(
void
__iomem
*
)
ioaddr
->
device_addr
);
VPRINTK
(
"device 0x%X
\n
"
,
tf
->
device
);
}
ata_wait_idle
(
ap
);
}
/**
* ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Outputs ATA taskfile to standard ATA host controller using MMIO
* or PIO as indicated by the ATA_FLAG_MMIO flag.
* Writes the control, feature, nsect, lbal, lbam, and lbah registers.
* Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
* hob_lbal, hob_lbam, and hob_lbah.
*
* This function waits for idle (!BUSY and !DRQ) after writing
* registers. If the control register has a new value, this
* function also waits for idle after writing control and before
* writing the remaining registers.
*
* May be used as the tf_load() entry in ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
void
ata_tf_load
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
ata_tf_load_mmio
(
ap
,
tf
);
else
ata_tf_load_pio
(
ap
,
tf
);
}
/**
* ata_exec_command_pio - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues PIO write to ATA command register, with proper
* synchronization with interrupt handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
static
void
ata_exec_command_pio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
DPRINTK
(
"ata%u: cmd 0x%X
\n
"
,
ap
->
id
,
tf
->
command
);
outb
(
tf
->
command
,
ap
->
ioaddr
.
command_addr
);
ata_pause
(
ap
);
}
/**
* ata_exec_command_mmio - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues MMIO write to ATA command register, with proper
* synchronization with interrupt handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
static
void
ata_exec_command_mmio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
DPRINTK
(
"ata%u: cmd 0x%X
\n
"
,
ap
->
id
,
tf
->
command
);
writeb
(
tf
->
command
,
(
void
__iomem
*
)
ap
->
ioaddr
.
command_addr
);
ata_pause
(
ap
);
}
/**
* ata_exec_command - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues PIO/MMIO write to ATA command register, with proper
* synchronization with interrupt handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
void
ata_exec_command
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
ata_exec_command_mmio
(
ap
,
tf
);
else
ata_exec_command_pio
(
ap
,
tf
);
}
/**
* ata_tf_read_pio - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Reads ATA taskfile registers for currently-selected device
* into @tf.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_read_pio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
tf
->
command
=
ata_check_status
(
ap
);
tf
->
feature
=
inb
(
ioaddr
->
error_addr
);
tf
->
nsect
=
inb
(
ioaddr
->
nsect_addr
);
tf
->
lbal
=
inb
(
ioaddr
->
lbal_addr
);
tf
->
lbam
=
inb
(
ioaddr
->
lbam_addr
);
tf
->
lbah
=
inb
(
ioaddr
->
lbah_addr
);
tf
->
device
=
inb
(
ioaddr
->
device_addr
);
if
(
tf
->
flags
&
ATA_TFLAG_LBA48
)
{
outb
(
tf
->
ctl
|
ATA_HOB
,
ioaddr
->
ctl_addr
);
tf
->
hob_feature
=
inb
(
ioaddr
->
error_addr
);
tf
->
hob_nsect
=
inb
(
ioaddr
->
nsect_addr
);
tf
->
hob_lbal
=
inb
(
ioaddr
->
lbal_addr
);
tf
->
hob_lbam
=
inb
(
ioaddr
->
lbam_addr
);
tf
->
hob_lbah
=
inb
(
ioaddr
->
lbah_addr
);
}
}
/**
* ata_tf_read_mmio - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Reads ATA taskfile registers for currently-selected device
* into @tf via MMIO.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_read_mmio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
tf
->
command
=
ata_check_status
(
ap
);
tf
->
feature
=
readb
((
void
__iomem
*
)
ioaddr
->
error_addr
);
tf
->
nsect
=
readb
((
void
__iomem
*
)
ioaddr
->
nsect_addr
);
tf
->
lbal
=
readb
((
void
__iomem
*
)
ioaddr
->
lbal_addr
);
tf
->
lbam
=
readb
((
void
__iomem
*
)
ioaddr
->
lbam_addr
);
tf
->
lbah
=
readb
((
void
__iomem
*
)
ioaddr
->
lbah_addr
);
tf
->
device
=
readb
((
void
__iomem
*
)
ioaddr
->
device_addr
);
if
(
tf
->
flags
&
ATA_TFLAG_LBA48
)
{
writeb
(
tf
->
ctl
|
ATA_HOB
,
(
void
__iomem
*
)
ap
->
ioaddr
.
ctl_addr
);
tf
->
hob_feature
=
readb
((
void
__iomem
*
)
ioaddr
->
error_addr
);
tf
->
hob_nsect
=
readb
((
void
__iomem
*
)
ioaddr
->
nsect_addr
);
tf
->
hob_lbal
=
readb
((
void
__iomem
*
)
ioaddr
->
lbal_addr
);
tf
->
hob_lbam
=
readb
((
void
__iomem
*
)
ioaddr
->
lbam_addr
);
tf
->
hob_lbah
=
readb
((
void
__iomem
*
)
ioaddr
->
lbah_addr
);
}
}
/**
* ata_tf_read - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Reads ATA taskfile registers for currently-selected device
* into @tf.
*
* Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
* is set, also reads the hob registers.
*
* May be used as the tf_read() entry in ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
void
ata_tf_read
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
ata_tf_read_mmio
(
ap
,
tf
);
else
ata_tf_read_pio
(
ap
,
tf
);
}
/**
* ata_check_status_pio - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* and return its value. This also clears pending interrupts
* from this device
*
* LOCKING:
* Inherited from caller.
*/
static
u8
ata_check_status_pio
(
struct
ata_port
*
ap
)
{
return
inb
(
ap
->
ioaddr
.
status_addr
);
}
/**
* ata_check_status_mmio - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* via MMIO and return its value. This also clears pending interrupts
* from this device
*
* LOCKING:
* Inherited from caller.
*/
static
u8
ata_check_status_mmio
(
struct
ata_port
*
ap
)
{
return
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
status_addr
);
}
/**
* ata_check_status - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* and return its value. This also clears pending interrupts
* from this device
*
* May be used as the check_status() entry in ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
u8
ata_check_status
(
struct
ata_port
*
ap
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
return
ata_check_status_mmio
(
ap
);
return
ata_check_status_pio
(
ap
);
}
/**
* ata_altstatus - Read device alternate status reg
* @ap: port where the device is
*
* Reads ATA taskfile alternate status register for
* currently-selected device and return its value.
*
* Note: may NOT be used as the check_altstatus() entry in
* ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
u8
ata_altstatus
(
struct
ata_port
*
ap
)
{
if
(
ap
->
ops
->
check_altstatus
)
return
ap
->
ops
->
check_altstatus
(
ap
);
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
return
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
altstatus_addr
);
return
inb
(
ap
->
ioaddr
.
altstatus_addr
);
}
#ifdef CONFIG_PCI
static
struct
ata_probe_ent
*
ata_probe_ent_alloc
(
struct
device
*
dev
,
const
struct
ata_port_info
*
port
)
{
struct
ata_probe_ent
*
probe_ent
;
probe_ent
=
kzalloc
(
sizeof
(
*
probe_ent
),
GFP_KERNEL
);
if
(
!
probe_ent
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): out of memory
\n
"
,
kobject_name
(
&
(
dev
->
kobj
)));
return
NULL
;
}
INIT_LIST_HEAD
(
&
probe_ent
->
node
);
probe_ent
->
dev
=
dev
;
probe_ent
->
sht
=
port
->
sht
;
probe_ent
->
host_flags
=
port
->
host_flags
;
probe_ent
->
pio_mask
=
port
->
pio_mask
;
probe_ent
->
mwdma_mask
=
port
->
mwdma_mask
;
probe_ent
->
udma_mask
=
port
->
udma_mask
;
probe_ent
->
port_ops
=
port
->
port_ops
;
return
probe_ent
;
}
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
* @port: array[2] of pointers to port info structures.
* @ports: bitmap of ports present
*
* Utility function which allocates and initializes an
* ata_probe_ent structure for a standard dual-port
* PIO-based IDE controller. The returned ata_probe_ent
* structure can be passed to ata_device_add(). The returned
* ata_probe_ent structure should then be freed with kfree().
*
* The caller need only pass the address of the primary port, the
* secondary will be deduced automatically. If the device has non
* standard secondary port mappings this function can be called twice,
* once for each interface.
*/
struct
ata_probe_ent
*
ata_pci_init_native_mode
(
struct
pci_dev
*
pdev
,
struct
ata_port_info
**
port
,
int
ports
)
{
struct
ata_probe_ent
*
probe_ent
=
ata_probe_ent_alloc
(
pci_dev_to_dev
(
pdev
),
port
[
0
]);
int
p
=
0
;
if
(
!
probe_ent
)
return
NULL
;
probe_ent
->
irq
=
pdev
->
irq
;
probe_ent
->
irq_flags
=
SA_SHIRQ
;
probe_ent
->
private_data
=
port
[
0
]
->
private_data
;
if
(
ports
&
ATA_PORT_PRIMARY
)
{
probe_ent
->
port
[
p
].
cmd_addr
=
pci_resource_start
(
pdev
,
0
);
probe_ent
->
port
[
p
].
altstatus_addr
=
probe_ent
->
port
[
p
].
ctl_addr
=
pci_resource_start
(
pdev
,
1
)
|
ATA_PCI_CTL_OFS
;
probe_ent
->
port
[
p
].
bmdma_addr
=
pci_resource_start
(
pdev
,
4
);
ata_std_ports
(
&
probe_ent
->
port
[
p
]);
p
++
;
}
if
(
ports
&
ATA_PORT_SECONDARY
)
{
probe_ent
->
port
[
p
].
cmd_addr
=
pci_resource_start
(
pdev
,
2
);
probe_ent
->
port
[
p
].
altstatus_addr
=
probe_ent
->
port
[
p
].
ctl_addr
=
pci_resource_start
(
pdev
,
3
)
|
ATA_PCI_CTL_OFS
;
probe_ent
->
port
[
p
].
bmdma_addr
=
pci_resource_start
(
pdev
,
4
)
+
8
;
ata_std_ports
(
&
probe_ent
->
port
[
p
]);
p
++
;
}
probe_ent
->
n_ports
=
p
;
return
probe_ent
;
}
static
struct
ata_probe_ent
*
ata_pci_init_legacy_port
(
struct
pci_dev
*
pdev
,
struct
ata_port_info
*
port
,
int
port_num
)
{
struct
ata_probe_ent
*
probe_ent
;
probe_ent
=
ata_probe_ent_alloc
(
pci_dev_to_dev
(
pdev
),
port
);
if
(
!
probe_ent
)
return
NULL
;
probe_ent
->
legacy_mode
=
1
;
probe_ent
->
n_ports
=
1
;
probe_ent
->
hard_port_no
=
port_num
;
probe_ent
->
private_data
=
port
->
private_data
;
switch
(
port_num
)
{
case
0
:
probe_ent
->
irq
=
14
;
probe_ent
->
port
[
0
].
cmd_addr
=
0x1f0
;
probe_ent
->
port
[
0
].
altstatus_addr
=
probe_ent
->
port
[
0
].
ctl_addr
=
0x3f6
;
break
;
case
1
:
probe_ent
->
irq
=
15
;
probe_ent
->
port
[
0
].
cmd_addr
=
0x170
;
probe_ent
->
port
[
0
].
altstatus_addr
=
probe_ent
->
port
[
0
].
ctl_addr
=
0x376
;
break
;
}
probe_ent
->
port
[
0
].
bmdma_addr
=
pci_resource_start
(
pdev
,
4
)
+
8
*
port_num
;
ata_std_ports
(
&
probe_ent
->
port
[
0
]);
return
probe_ent
;
}
/**
* ata_pci_init_one - Initialize/register PCI IDE host controller
* @pdev: Controller to be initialized
* @port_info: Information from low-level host driver
* @n_ports: Number of ports attached to host controller
*
* This is a helper function which can be called from a driver's
* xxx_init_one() probe function if the hardware uses traditional
* IDE taskfile registers.
*
* This function calls pci_enable_device(), reserves its register
* regions, sets the dma mask, enables bus master mode, and calls
* ata_device_add()
*
* LOCKING:
* Inherited from PCI layer (may sleep).
*
* RETURNS:
* Zero on success, negative on errno-based value on error.
*/
int
ata_pci_init_one
(
struct
pci_dev
*
pdev
,
struct
ata_port_info
**
port_info
,
unsigned
int
n_ports
)
{
struct
ata_probe_ent
*
probe_ent
=
NULL
,
*
probe_ent2
=
NULL
;
struct
ata_port_info
*
port
[
2
];
u8
tmp8
,
mask
;
unsigned
int
legacy_mode
=
0
;
int
disable_dev_on_err
=
1
;
int
rc
;
DPRINTK
(
"ENTER
\n
"
);
port
[
0
]
=
port_info
[
0
];
if
(
n_ports
>
1
)
port
[
1
]
=
port_info
[
1
];
else
port
[
1
]
=
port
[
0
];
if
((
port
[
0
]
->
host_flags
&
ATA_FLAG_NO_LEGACY
)
==
0
&&
(
pdev
->
class
>>
8
)
==
PCI_CLASS_STORAGE_IDE
)
{
/* TODO: What if one channel is in native mode ... */
pci_read_config_byte
(
pdev
,
PCI_CLASS_PROG
,
&
tmp8
);
mask
=
(
1
<<
2
)
|
(
1
<<
0
);
if
((
tmp8
&
mask
)
!=
mask
)
legacy_mode
=
(
1
<<
3
);
}
/* FIXME... */
if
((
!
legacy_mode
)
&&
(
n_ports
>
2
))
{
printk
(
KERN_ERR
"ata: BUG: native mode, n_ports > 2
\n
"
);
n_ports
=
2
;
/* For now */
}
/* FIXME: Really for ATA it isn't safe because the device may be
multi-purpose and we want to leave it alone if it was already
enabled. Secondly for shared use as Arjan says we want refcounting
Checking dev->is_enabled is insufficient as this is not set at
boot for the primary video which is BIOS enabled
*/
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
return
rc
;
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
{
disable_dev_on_err
=
0
;
goto
err_out
;
}
/* FIXME: Should use platform specific mappers for legacy port ranges */
if
(
legacy_mode
)
{
if
(
!
request_region
(
0x1f0
,
8
,
"libata"
))
{
struct
resource
*
conflict
,
res
;
res
.
start
=
0x1f0
;
res
.
end
=
0x1f0
+
8
-
1
;
conflict
=
____request_resource
(
&
ioport_resource
,
&
res
);
if
(
!
strcmp
(
conflict
->
name
,
"libata"
))
legacy_mode
|=
(
1
<<
0
);
else
{
disable_dev_on_err
=
0
;
printk
(
KERN_WARNING
"ata: 0x1f0 IDE port busy
\n
"
);
}
}
else
legacy_mode
|=
(
1
<<
0
);
if
(
!
request_region
(
0x170
,
8
,
"libata"
))
{
struct
resource
*
conflict
,
res
;
res
.
start
=
0x170
;
res
.
end
=
0x170
+
8
-
1
;
conflict
=
____request_resource
(
&
ioport_resource
,
&
res
);
if
(
!
strcmp
(
conflict
->
name
,
"libata"
))
legacy_mode
|=
(
1
<<
1
);
else
{
disable_dev_on_err
=
0
;
printk
(
KERN_WARNING
"ata: 0x170 IDE port busy
\n
"
);
}
}
else
legacy_mode
|=
(
1
<<
1
);
}
/* we have legacy mode, but all ports are unavailable */
if
(
legacy_mode
==
(
1
<<
3
))
{
rc
=
-
EBUSY
;
goto
err_out_regions
;
}
rc
=
pci_set_dma_mask
(
pdev
,
ATA_DMA_MASK
);
if
(
rc
)
goto
err_out_regions
;
rc
=
pci_set_consistent_dma_mask
(
pdev
,
ATA_DMA_MASK
);
if
(
rc
)
goto
err_out_regions
;
if
(
legacy_mode
)
{
if
(
legacy_mode
&
(
1
<<
0
))
probe_ent
=
ata_pci_init_legacy_port
(
pdev
,
port
[
0
],
0
);
if
(
legacy_mode
&
(
1
<<
1
))
probe_ent2
=
ata_pci_init_legacy_port
(
pdev
,
port
[
1
],
1
);
}
else
{
if
(
n_ports
==
2
)
probe_ent
=
ata_pci_init_native_mode
(
pdev
,
port
,
ATA_PORT_PRIMARY
|
ATA_PORT_SECONDARY
);
else
probe_ent
=
ata_pci_init_native_mode
(
pdev
,
port
,
ATA_PORT_PRIMARY
);
}
if
(
!
probe_ent
&&
!
probe_ent2
)
{
rc
=
-
ENOMEM
;
goto
err_out_regions
;
}
pci_set_master
(
pdev
);
/* FIXME: check ata_device_add return */
if
(
legacy_mode
)
{
if
(
legacy_mode
&
(
1
<<
0
))
ata_device_add
(
probe_ent
);
if
(
legacy_mode
&
(
1
<<
1
))
ata_device_add
(
probe_ent2
);
}
else
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
kfree
(
probe_ent2
);
return
0
;
err_out_regions:
if
(
legacy_mode
&
(
1
<<
0
))
release_region
(
0x1f0
,
8
);
if
(
legacy_mode
&
(
1
<<
1
))
release_region
(
0x170
,
8
);
pci_release_regions
(
pdev
);
err_out:
if
(
disable_dev_on_err
)
pci_disable_device
(
pdev
);
return
rc
;
}
#endif
/* CONFIG_PCI */
drivers/scsi/libata-core.c
View file @
1fdffbce
...
...
@@ -83,403 +83,6 @@ MODULE_DESCRIPTION("Library module for ATA devices");
MODULE_LICENSE
(
"GPL"
);
MODULE_VERSION
(
DRV_VERSION
);
/**
* ata_tf_load_pio - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Outputs ATA taskfile to standard ATA host controller.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_load_pio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
unsigned
int
is_addr
=
tf
->
flags
&
ATA_TFLAG_ISADDR
;
if
(
tf
->
ctl
!=
ap
->
last_ctl
)
{
outb
(
tf
->
ctl
,
ioaddr
->
ctl_addr
);
ap
->
last_ctl
=
tf
->
ctl
;
ata_wait_idle
(
ap
);
}
if
(
is_addr
&&
(
tf
->
flags
&
ATA_TFLAG_LBA48
))
{
outb
(
tf
->
hob_feature
,
ioaddr
->
feature_addr
);
outb
(
tf
->
hob_nsect
,
ioaddr
->
nsect_addr
);
outb
(
tf
->
hob_lbal
,
ioaddr
->
lbal_addr
);
outb
(
tf
->
hob_lbam
,
ioaddr
->
lbam_addr
);
outb
(
tf
->
hob_lbah
,
ioaddr
->
lbah_addr
);
VPRINTK
(
"hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
hob_feature
,
tf
->
hob_nsect
,
tf
->
hob_lbal
,
tf
->
hob_lbam
,
tf
->
hob_lbah
);
}
if
(
is_addr
)
{
outb
(
tf
->
feature
,
ioaddr
->
feature_addr
);
outb
(
tf
->
nsect
,
ioaddr
->
nsect_addr
);
outb
(
tf
->
lbal
,
ioaddr
->
lbal_addr
);
outb
(
tf
->
lbam
,
ioaddr
->
lbam_addr
);
outb
(
tf
->
lbah
,
ioaddr
->
lbah_addr
);
VPRINTK
(
"feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
feature
,
tf
->
nsect
,
tf
->
lbal
,
tf
->
lbam
,
tf
->
lbah
);
}
if
(
tf
->
flags
&
ATA_TFLAG_DEVICE
)
{
outb
(
tf
->
device
,
ioaddr
->
device_addr
);
VPRINTK
(
"device 0x%X
\n
"
,
tf
->
device
);
}
ata_wait_idle
(
ap
);
}
/**
* ata_tf_load_mmio - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Outputs ATA taskfile to standard ATA host controller using MMIO.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_load_mmio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
unsigned
int
is_addr
=
tf
->
flags
&
ATA_TFLAG_ISADDR
;
if
(
tf
->
ctl
!=
ap
->
last_ctl
)
{
writeb
(
tf
->
ctl
,
(
void
__iomem
*
)
ap
->
ioaddr
.
ctl_addr
);
ap
->
last_ctl
=
tf
->
ctl
;
ata_wait_idle
(
ap
);
}
if
(
is_addr
&&
(
tf
->
flags
&
ATA_TFLAG_LBA48
))
{
writeb
(
tf
->
hob_feature
,
(
void
__iomem
*
)
ioaddr
->
feature_addr
);
writeb
(
tf
->
hob_nsect
,
(
void
__iomem
*
)
ioaddr
->
nsect_addr
);
writeb
(
tf
->
hob_lbal
,
(
void
__iomem
*
)
ioaddr
->
lbal_addr
);
writeb
(
tf
->
hob_lbam
,
(
void
__iomem
*
)
ioaddr
->
lbam_addr
);
writeb
(
tf
->
hob_lbah
,
(
void
__iomem
*
)
ioaddr
->
lbah_addr
);
VPRINTK
(
"hob: feat 0x%X nsect 0x%X, lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
hob_feature
,
tf
->
hob_nsect
,
tf
->
hob_lbal
,
tf
->
hob_lbam
,
tf
->
hob_lbah
);
}
if
(
is_addr
)
{
writeb
(
tf
->
feature
,
(
void
__iomem
*
)
ioaddr
->
feature_addr
);
writeb
(
tf
->
nsect
,
(
void
__iomem
*
)
ioaddr
->
nsect_addr
);
writeb
(
tf
->
lbal
,
(
void
__iomem
*
)
ioaddr
->
lbal_addr
);
writeb
(
tf
->
lbam
,
(
void
__iomem
*
)
ioaddr
->
lbam_addr
);
writeb
(
tf
->
lbah
,
(
void
__iomem
*
)
ioaddr
->
lbah_addr
);
VPRINTK
(
"feat 0x%X nsect 0x%X lba 0x%X 0x%X 0x%X
\n
"
,
tf
->
feature
,
tf
->
nsect
,
tf
->
lbal
,
tf
->
lbam
,
tf
->
lbah
);
}
if
(
tf
->
flags
&
ATA_TFLAG_DEVICE
)
{
writeb
(
tf
->
device
,
(
void
__iomem
*
)
ioaddr
->
device_addr
);
VPRINTK
(
"device 0x%X
\n
"
,
tf
->
device
);
}
ata_wait_idle
(
ap
);
}
/**
* ata_tf_load - send taskfile registers to host controller
* @ap: Port to which output is sent
* @tf: ATA taskfile register set
*
* Outputs ATA taskfile to standard ATA host controller using MMIO
* or PIO as indicated by the ATA_FLAG_MMIO flag.
* Writes the control, feature, nsect, lbal, lbam, and lbah registers.
* Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
* hob_lbal, hob_lbam, and hob_lbah.
*
* This function waits for idle (!BUSY and !DRQ) after writing
* registers. If the control register has a new value, this
* function also waits for idle after writing control and before
* writing the remaining registers.
*
* May be used as the tf_load() entry in ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
void
ata_tf_load
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
ata_tf_load_mmio
(
ap
,
tf
);
else
ata_tf_load_pio
(
ap
,
tf
);
}
/**
* ata_exec_command_pio - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues PIO write to ATA command register, with proper
* synchronization with interrupt handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
static
void
ata_exec_command_pio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
DPRINTK
(
"ata%u: cmd 0x%X
\n
"
,
ap
->
id
,
tf
->
command
);
outb
(
tf
->
command
,
ap
->
ioaddr
.
command_addr
);
ata_pause
(
ap
);
}
/**
* ata_exec_command_mmio - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues MMIO write to ATA command register, with proper
* synchronization with interrupt handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
static
void
ata_exec_command_mmio
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
DPRINTK
(
"ata%u: cmd 0x%X
\n
"
,
ap
->
id
,
tf
->
command
);
writeb
(
tf
->
command
,
(
void
__iomem
*
)
ap
->
ioaddr
.
command_addr
);
ata_pause
(
ap
);
}
/**
* ata_exec_command - issue ATA command to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues PIO/MMIO write to ATA command register, with proper
* synchronization with interrupt handler / other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
void
ata_exec_command
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
ata_exec_command_mmio
(
ap
,
tf
);
else
ata_exec_command_pio
(
ap
,
tf
);
}
/**
* ata_tf_to_host - issue ATA taskfile to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues ATA taskfile register set to ATA host controller,
* with proper synchronization with interrupt handler and
* other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
static
inline
void
ata_tf_to_host
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
ap
->
ops
->
tf_load
(
ap
,
tf
);
ap
->
ops
->
exec_command
(
ap
,
tf
);
}
/**
* ata_tf_read_pio - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Reads ATA taskfile registers for currently-selected device
* into @tf.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_read_pio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
tf
->
command
=
ata_check_status
(
ap
);
tf
->
feature
=
inb
(
ioaddr
->
error_addr
);
tf
->
nsect
=
inb
(
ioaddr
->
nsect_addr
);
tf
->
lbal
=
inb
(
ioaddr
->
lbal_addr
);
tf
->
lbam
=
inb
(
ioaddr
->
lbam_addr
);
tf
->
lbah
=
inb
(
ioaddr
->
lbah_addr
);
tf
->
device
=
inb
(
ioaddr
->
device_addr
);
if
(
tf
->
flags
&
ATA_TFLAG_LBA48
)
{
outb
(
tf
->
ctl
|
ATA_HOB
,
ioaddr
->
ctl_addr
);
tf
->
hob_feature
=
inb
(
ioaddr
->
error_addr
);
tf
->
hob_nsect
=
inb
(
ioaddr
->
nsect_addr
);
tf
->
hob_lbal
=
inb
(
ioaddr
->
lbal_addr
);
tf
->
hob_lbam
=
inb
(
ioaddr
->
lbam_addr
);
tf
->
hob_lbah
=
inb
(
ioaddr
->
lbah_addr
);
}
}
/**
* ata_tf_read_mmio - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Reads ATA taskfile registers for currently-selected device
* into @tf via MMIO.
*
* LOCKING:
* Inherited from caller.
*/
static
void
ata_tf_read_mmio
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
tf
->
command
=
ata_check_status
(
ap
);
tf
->
feature
=
readb
((
void
__iomem
*
)
ioaddr
->
error_addr
);
tf
->
nsect
=
readb
((
void
__iomem
*
)
ioaddr
->
nsect_addr
);
tf
->
lbal
=
readb
((
void
__iomem
*
)
ioaddr
->
lbal_addr
);
tf
->
lbam
=
readb
((
void
__iomem
*
)
ioaddr
->
lbam_addr
);
tf
->
lbah
=
readb
((
void
__iomem
*
)
ioaddr
->
lbah_addr
);
tf
->
device
=
readb
((
void
__iomem
*
)
ioaddr
->
device_addr
);
if
(
tf
->
flags
&
ATA_TFLAG_LBA48
)
{
writeb
(
tf
->
ctl
|
ATA_HOB
,
(
void
__iomem
*
)
ap
->
ioaddr
.
ctl_addr
);
tf
->
hob_feature
=
readb
((
void
__iomem
*
)
ioaddr
->
error_addr
);
tf
->
hob_nsect
=
readb
((
void
__iomem
*
)
ioaddr
->
nsect_addr
);
tf
->
hob_lbal
=
readb
((
void
__iomem
*
)
ioaddr
->
lbal_addr
);
tf
->
hob_lbam
=
readb
((
void
__iomem
*
)
ioaddr
->
lbam_addr
);
tf
->
hob_lbah
=
readb
((
void
__iomem
*
)
ioaddr
->
lbah_addr
);
}
}
/**
* ata_tf_read - input device's ATA taskfile shadow registers
* @ap: Port from which input is read
* @tf: ATA taskfile register set for storing input
*
* Reads ATA taskfile registers for currently-selected device
* into @tf.
*
* Reads nsect, lbal, lbam, lbah, and device. If ATA_TFLAG_LBA48
* is set, also reads the hob registers.
*
* May be used as the tf_read() entry in ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
void
ata_tf_read
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
ata_tf_read_mmio
(
ap
,
tf
);
else
ata_tf_read_pio
(
ap
,
tf
);
}
/**
* ata_check_status_pio - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* and return its value. This also clears pending interrupts
* from this device
*
* LOCKING:
* Inherited from caller.
*/
static
u8
ata_check_status_pio
(
struct
ata_port
*
ap
)
{
return
inb
(
ap
->
ioaddr
.
status_addr
);
}
/**
* ata_check_status_mmio - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* via MMIO and return its value. This also clears pending interrupts
* from this device
*
* LOCKING:
* Inherited from caller.
*/
static
u8
ata_check_status_mmio
(
struct
ata_port
*
ap
)
{
return
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
status_addr
);
}
/**
* ata_check_status - Read device status reg & clear interrupt
* @ap: port where the device is
*
* Reads ATA taskfile status register for currently-selected device
* and return its value. This also clears pending interrupts
* from this device
*
* May be used as the check_status() entry in ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
u8
ata_check_status
(
struct
ata_port
*
ap
)
{
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
return
ata_check_status_mmio
(
ap
);
return
ata_check_status_pio
(
ap
);
}
/**
* ata_altstatus - Read device alternate status reg
* @ap: port where the device is
*
* Reads ATA taskfile alternate status register for
* currently-selected device and return its value.
*
* Note: may NOT be used as the check_altstatus() entry in
* ata_port_operations.
*
* LOCKING:
* Inherited from caller.
*/
u8
ata_altstatus
(
struct
ata_port
*
ap
)
{
if
(
ap
->
ops
->
check_altstatus
)
return
ap
->
ops
->
check_altstatus
(
ap
);
if
(
ap
->
flags
&
ATA_FLAG_MMIO
)
return
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
altstatus_addr
);
return
inb
(
ap
->
ioaddr
.
altstatus_addr
);
}
/**
* ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure
...
...
@@ -2008,6 +1611,26 @@ static void ata_set_mode(struct ata_port *ap)
ata_port_disable
(
ap
);
}
/**
* ata_tf_to_host - issue ATA taskfile to host controller
* @ap: port to which command is being issued
* @tf: ATA taskfile register set
*
* Issues ATA taskfile register set to ATA host controller,
* with proper synchronization with interrupt handler and
* other threads.
*
* LOCKING:
* spin_lock_irqsave(host_set lock)
*/
static
inline
void
ata_tf_to_host
(
struct
ata_port
*
ap
,
const
struct
ata_taskfile
*
tf
)
{
ap
->
ops
->
tf_load
(
ap
,
tf
);
ap
->
ops
->
exec_command
(
ap
,
tf
);
}
/**
* ata_busy_sleep - sleep until BSY clears, or timeout
* @ap: port containing status register to be polled
...
...
@@ -5106,32 +4729,6 @@ void ata_std_ports(struct ata_ioports *ioaddr)
ioaddr
->
command_addr
=
ioaddr
->
cmd_addr
+
ATA_REG_CMD
;
}
static
struct
ata_probe_ent
*
ata_probe_ent_alloc
(
struct
device
*
dev
,
const
struct
ata_port_info
*
port
)
{
struct
ata_probe_ent
*
probe_ent
;
probe_ent
=
kzalloc
(
sizeof
(
*
probe_ent
),
GFP_KERNEL
);
if
(
!
probe_ent
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): out of memory
\n
"
,
kobject_name
(
&
(
dev
->
kobj
)));
return
NULL
;
}
INIT_LIST_HEAD
(
&
probe_ent
->
node
);
probe_ent
->
dev
=
dev
;
probe_ent
->
sht
=
port
->
sht
;
probe_ent
->
host_flags
=
port
->
host_flags
;
probe_ent
->
pio_mask
=
port
->
pio_mask
;
probe_ent
->
mwdma_mask
=
port
->
mwdma_mask
;
probe_ent
->
udma_mask
=
port
->
udma_mask
;
probe_ent
->
port_ops
=
port
->
port_ops
;
return
probe_ent
;
}
#ifdef CONFIG_PCI
...
...
@@ -5142,256 +4739,6 @@ void ata_pci_host_stop (struct ata_host_set *host_set)
pci_iounmap
(
pdev
,
host_set
->
mmio_base
);
}
/**
* ata_pci_init_native_mode - Initialize native-mode driver
* @pdev: pci device to be initialized
* @port: array[2] of pointers to port info structures.
* @ports: bitmap of ports present
*
* Utility function which allocates and initializes an
* ata_probe_ent structure for a standard dual-port
* PIO-based IDE controller. The returned ata_probe_ent
* structure can be passed to ata_device_add(). The returned
* ata_probe_ent structure should then be freed with kfree().
*
* The caller need only pass the address of the primary port, the
* secondary will be deduced automatically. If the device has non
* standard secondary port mappings this function can be called twice,
* once for each interface.
*/
struct
ata_probe_ent
*
ata_pci_init_native_mode
(
struct
pci_dev
*
pdev
,
struct
ata_port_info
**
port
,
int
ports
)
{
struct
ata_probe_ent
*
probe_ent
=
ata_probe_ent_alloc
(
pci_dev_to_dev
(
pdev
),
port
[
0
]);
int
p
=
0
;
if
(
!
probe_ent
)
return
NULL
;
probe_ent
->
irq
=
pdev
->
irq
;
probe_ent
->
irq_flags
=
SA_SHIRQ
;
probe_ent
->
private_data
=
port
[
0
]
->
private_data
;
if
(
ports
&
ATA_PORT_PRIMARY
)
{
probe_ent
->
port
[
p
].
cmd_addr
=
pci_resource_start
(
pdev
,
0
);
probe_ent
->
port
[
p
].
altstatus_addr
=
probe_ent
->
port
[
p
].
ctl_addr
=
pci_resource_start
(
pdev
,
1
)
|
ATA_PCI_CTL_OFS
;
probe_ent
->
port
[
p
].
bmdma_addr
=
pci_resource_start
(
pdev
,
4
);
ata_std_ports
(
&
probe_ent
->
port
[
p
]);
p
++
;
}
if
(
ports
&
ATA_PORT_SECONDARY
)
{
probe_ent
->
port
[
p
].
cmd_addr
=
pci_resource_start
(
pdev
,
2
);
probe_ent
->
port
[
p
].
altstatus_addr
=
probe_ent
->
port
[
p
].
ctl_addr
=
pci_resource_start
(
pdev
,
3
)
|
ATA_PCI_CTL_OFS
;
probe_ent
->
port
[
p
].
bmdma_addr
=
pci_resource_start
(
pdev
,
4
)
+
8
;
ata_std_ports
(
&
probe_ent
->
port
[
p
]);
p
++
;
}
probe_ent
->
n_ports
=
p
;
return
probe_ent
;
}
static
struct
ata_probe_ent
*
ata_pci_init_legacy_port
(
struct
pci_dev
*
pdev
,
struct
ata_port_info
*
port
,
int
port_num
)
{
struct
ata_probe_ent
*
probe_ent
;
probe_ent
=
ata_probe_ent_alloc
(
pci_dev_to_dev
(
pdev
),
port
);
if
(
!
probe_ent
)
return
NULL
;
probe_ent
->
legacy_mode
=
1
;
probe_ent
->
n_ports
=
1
;
probe_ent
->
hard_port_no
=
port_num
;
probe_ent
->
private_data
=
port
->
private_data
;
switch
(
port_num
)
{
case
0
:
probe_ent
->
irq
=
14
;
probe_ent
->
port
[
0
].
cmd_addr
=
0x1f0
;
probe_ent
->
port
[
0
].
altstatus_addr
=
probe_ent
->
port
[
0
].
ctl_addr
=
0x3f6
;
break
;
case
1
:
probe_ent
->
irq
=
15
;
probe_ent
->
port
[
0
].
cmd_addr
=
0x170
;
probe_ent
->
port
[
0
].
altstatus_addr
=
probe_ent
->
port
[
0
].
ctl_addr
=
0x376
;
break
;
}
probe_ent
->
port
[
0
].
bmdma_addr
=
pci_resource_start
(
pdev
,
4
)
+
8
*
port_num
;
ata_std_ports
(
&
probe_ent
->
port
[
0
]);
return
probe_ent
;
}
/**
* ata_pci_init_one - Initialize/register PCI IDE host controller
* @pdev: Controller to be initialized
* @port_info: Information from low-level host driver
* @n_ports: Number of ports attached to host controller
*
* This is a helper function which can be called from a driver's
* xxx_init_one() probe function if the hardware uses traditional
* IDE taskfile registers.
*
* This function calls pci_enable_device(), reserves its register
* regions, sets the dma mask, enables bus master mode, and calls
* ata_device_add()
*
* LOCKING:
* Inherited from PCI layer (may sleep).
*
* RETURNS:
* Zero on success, negative on errno-based value on error.
*/
int
ata_pci_init_one
(
struct
pci_dev
*
pdev
,
struct
ata_port_info
**
port_info
,
unsigned
int
n_ports
)
{
struct
ata_probe_ent
*
probe_ent
=
NULL
,
*
probe_ent2
=
NULL
;
struct
ata_port_info
*
port
[
2
];
u8
tmp8
,
mask
;
unsigned
int
legacy_mode
=
0
;
int
disable_dev_on_err
=
1
;
int
rc
;
DPRINTK
(
"ENTER
\n
"
);
port
[
0
]
=
port_info
[
0
];
if
(
n_ports
>
1
)
port
[
1
]
=
port_info
[
1
];
else
port
[
1
]
=
port
[
0
];
if
((
port
[
0
]
->
host_flags
&
ATA_FLAG_NO_LEGACY
)
==
0
&&
(
pdev
->
class
>>
8
)
==
PCI_CLASS_STORAGE_IDE
)
{
/* TODO: What if one channel is in native mode ... */
pci_read_config_byte
(
pdev
,
PCI_CLASS_PROG
,
&
tmp8
);
mask
=
(
1
<<
2
)
|
(
1
<<
0
);
if
((
tmp8
&
mask
)
!=
mask
)
legacy_mode
=
(
1
<<
3
);
}
/* FIXME... */
if
((
!
legacy_mode
)
&&
(
n_ports
>
2
))
{
printk
(
KERN_ERR
"ata: BUG: native mode, n_ports > 2
\n
"
);
n_ports
=
2
;
/* For now */
}
/* FIXME: Really for ATA it isn't safe because the device may be
multi-purpose and we want to leave it alone if it was already
enabled. Secondly for shared use as Arjan says we want refcounting
Checking dev->is_enabled is insufficient as this is not set at
boot for the primary video which is BIOS enabled
*/
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
return
rc
;
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
{
disable_dev_on_err
=
0
;
goto
err_out
;
}
/* FIXME: Should use platform specific mappers for legacy port ranges */
if
(
legacy_mode
)
{
if
(
!
request_region
(
0x1f0
,
8
,
"libata"
))
{
struct
resource
*
conflict
,
res
;
res
.
start
=
0x1f0
;
res
.
end
=
0x1f0
+
8
-
1
;
conflict
=
____request_resource
(
&
ioport_resource
,
&
res
);
if
(
!
strcmp
(
conflict
->
name
,
"libata"
))
legacy_mode
|=
(
1
<<
0
);
else
{
disable_dev_on_err
=
0
;
printk
(
KERN_WARNING
"ata: 0x1f0 IDE port busy
\n
"
);
}
}
else
legacy_mode
|=
(
1
<<
0
);
if
(
!
request_region
(
0x170
,
8
,
"libata"
))
{
struct
resource
*
conflict
,
res
;
res
.
start
=
0x170
;
res
.
end
=
0x170
+
8
-
1
;
conflict
=
____request_resource
(
&
ioport_resource
,
&
res
);
if
(
!
strcmp
(
conflict
->
name
,
"libata"
))
legacy_mode
|=
(
1
<<
1
);
else
{
disable_dev_on_err
=
0
;
printk
(
KERN_WARNING
"ata: 0x170 IDE port busy
\n
"
);
}
}
else
legacy_mode
|=
(
1
<<
1
);
}
/* we have legacy mode, but all ports are unavailable */
if
(
legacy_mode
==
(
1
<<
3
))
{
rc
=
-
EBUSY
;
goto
err_out_regions
;
}
rc
=
pci_set_dma_mask
(
pdev
,
ATA_DMA_MASK
);
if
(
rc
)
goto
err_out_regions
;
rc
=
pci_set_consistent_dma_mask
(
pdev
,
ATA_DMA_MASK
);
if
(
rc
)
goto
err_out_regions
;
if
(
legacy_mode
)
{
if
(
legacy_mode
&
(
1
<<
0
))
probe_ent
=
ata_pci_init_legacy_port
(
pdev
,
port
[
0
],
0
);
if
(
legacy_mode
&
(
1
<<
1
))
probe_ent2
=
ata_pci_init_legacy_port
(
pdev
,
port
[
1
],
1
);
}
else
{
if
(
n_ports
==
2
)
probe_ent
=
ata_pci_init_native_mode
(
pdev
,
port
,
ATA_PORT_PRIMARY
|
ATA_PORT_SECONDARY
);
else
probe_ent
=
ata_pci_init_native_mode
(
pdev
,
port
,
ATA_PORT_PRIMARY
);
}
if
(
!
probe_ent
&&
!
probe_ent2
)
{
rc
=
-
ENOMEM
;
goto
err_out_regions
;
}
pci_set_master
(
pdev
);
/* FIXME: check ata_device_add return */
if
(
legacy_mode
)
{
if
(
legacy_mode
&
(
1
<<
0
))
ata_device_add
(
probe_ent
);
if
(
legacy_mode
&
(
1
<<
1
))
ata_device_add
(
probe_ent2
);
}
else
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
kfree
(
probe_ent2
);
return
0
;
err_out_regions:
if
(
legacy_mode
&
(
1
<<
0
))
release_region
(
0x1f0
,
8
);
if
(
legacy_mode
&
(
1
<<
1
))
release_region
(
0x170
,
8
);
pci_release_regions
(
pdev
);
err_out:
if
(
disable_dev_on_err
)
pci_disable_device
(
pdev
);
return
rc
;
}
/**
* ata_pci_remove_one - PCI layer callback for device removal
* @pdev: PCI device that was removed
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment