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
nexedi
linux
Commits
cc896f08
Commit
cc896f08
authored
Sep 07, 2005
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev
parents
87129d96
ca20aa69
Changes
5
Show whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
856 additions
and
3 deletions
+856
-3
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+9
-0
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-0
drivers/scsi/ahci.c
drivers/scsi/ahci.c
+1
-1
drivers/scsi/sata_mv.c
drivers/scsi/sata_mv.c
+843
-0
drivers/scsi/sata_uli.c
drivers/scsi/sata_uli.c
+2
-2
No files found.
drivers/scsi/Kconfig
View file @
cc896f08
...
...
@@ -459,6 +459,15 @@ config SCSI_ATA_PIIX
If
unsure
,
say
N
.
config
SCSI_SATA_MV
tristate
"Marvell SATA support"
depends
on
SCSI_SATA
&&
PCI
&&
EXPERIMENTAL
help
This
option
enables
support
for
the
Marvell
Serial
ATA
family
.
Currently
supports
88
SX
[
56
]
0
[
48
][
01
]
chips
.
If
unsure
,
say
N
.
config
SCSI_SATA_NV
tristate
"NVIDIA SATA support"
depends
on
SCSI_SATA
&&
PCI
&&
EXPERIMENTAL
...
...
drivers/scsi/Makefile
View file @
cc896f08
...
...
@@ -132,6 +132,7 @@ obj-$(CONFIG_SCSI_SATA_SIS) += libata.o sata_sis.o
obj-$(CONFIG_SCSI_SATA_SX4)
+=
libata.o sata_sx4.o
obj-$(CONFIG_SCSI_SATA_NV)
+=
libata.o sata_nv.o
obj-$(CONFIG_SCSI_SATA_ULI)
+=
libata.o sata_uli.o
obj-$(CONFIG_SCSI_SATA_MV)
+=
libata.o sata_mv.o
obj-$(CONFIG_ARM)
+=
arm/
...
...
drivers/scsi/ahci.c
View file @
cc896f08
...
...
@@ -250,7 +250,7 @@ static struct ata_port_info ahci_port_info[] = {
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
ATA_FLAG_PIO_DMA
,
.
pio_mask
=
0x
03
,
/* pio3
-4 */
.
pio_mask
=
0x
1f
,
/* pio0
-4 */
.
udma_mask
=
0x7f
,
/* udma0-6 ; FIXME */
.
port_ops
=
&
ahci_ops
,
},
...
...
drivers/scsi/sata_mv.c
0 → 100644
View file @
cc896f08
/*
* sata_mv.c - Marvell SATA support
*
* Copyright 2005: EMC Corporation, all rights reserved.
*
* Please ALWAYS copy linux-ide@vger.kernel.org on emails.
*
* 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; version 2 of the License.
*
* 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; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/dma-mapping.h>
#include "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/io.h>
#define DRV_NAME "sata_mv"
#define DRV_VERSION "0.12"
enum
{
/* BAR's are enumerated in terms of pci_resource_start() terms */
MV_PRIMARY_BAR
=
0
,
/* offset 0x10: memory space */
MV_IO_BAR
=
2
,
/* offset 0x18: IO space */
MV_MISC_BAR
=
3
,
/* offset 0x1c: FLASH, NVRAM, SRAM */
MV_MAJOR_REG_AREA_SZ
=
0x10000
,
/* 64KB */
MV_MINOR_REG_AREA_SZ
=
0x2000
,
/* 8KB */
MV_PCI_REG_BASE
=
0
,
MV_IRQ_COAL_REG_BASE
=
0x18000
,
/* 6xxx part only */
MV_SATAHC0_REG_BASE
=
0x20000
,
MV_PCI_REG_SZ
=
MV_MAJOR_REG_AREA_SZ
,
MV_SATAHC_REG_SZ
=
MV_MAJOR_REG_AREA_SZ
,
MV_SATAHC_ARBTR_REG_SZ
=
MV_MINOR_REG_AREA_SZ
,
/* arbiter */
MV_PORT_REG_SZ
=
MV_MINOR_REG_AREA_SZ
,
MV_Q_CT
=
32
,
MV_CRQB_SZ
=
32
,
MV_CRPB_SZ
=
8
,
MV_DMA_BOUNDARY
=
0xffffffffU
,
SATAHC_MASK
=
(
~
(
MV_SATAHC_REG_SZ
-
1
)),
MV_PORTS_PER_HC
=
4
,
/* == (port / MV_PORTS_PER_HC) to determine HC from 0-7 port */
MV_PORT_HC_SHIFT
=
2
,
/* == (port % MV_PORTS_PER_HC) to determine port from 0-7 port */
MV_PORT_MASK
=
3
,
/* Host Flags */
MV_FLAG_DUAL_HC
=
(
1
<<
30
),
/* two SATA Host Controllers */
MV_FLAG_IRQ_COALESCE
=
(
1
<<
29
),
/* IRQ coalescing capability */
MV_FLAG_BDMA
=
(
1
<<
28
),
/* Basic DMA */
chip_504x
=
0
,
chip_508x
=
1
,
chip_604x
=
2
,
chip_608x
=
3
,
/* PCI interface registers */
PCI_MAIN_CMD_STS_OFS
=
0xd30
,
STOP_PCI_MASTER
=
(
1
<<
2
),
PCI_MASTER_EMPTY
=
(
1
<<
3
),
GLOB_SFT_RST
=
(
1
<<
4
),
PCI_IRQ_CAUSE_OFS
=
0x1d58
,
PCI_IRQ_MASK_OFS
=
0x1d5c
,
PCI_UNMASK_ALL_IRQS
=
0x7fffff
,
/* bits 22-0 */
HC_MAIN_IRQ_CAUSE_OFS
=
0x1d60
,
HC_MAIN_IRQ_MASK_OFS
=
0x1d64
,
PORT0_ERR
=
(
1
<<
0
),
/* shift by port # */
PORT0_DONE
=
(
1
<<
1
),
/* shift by port # */
HC0_IRQ_PEND
=
0x1ff
,
/* bits 0-8 = HC0's ports */
HC_SHIFT
=
9
,
/* bits 9-17 = HC1's ports */
PCI_ERR
=
(
1
<<
18
),
TRAN_LO_DONE
=
(
1
<<
19
),
/* 6xxx: IRQ coalescing */
TRAN_HI_DONE
=
(
1
<<
20
),
/* 6xxx: IRQ coalescing */
PORTS_0_7_COAL_DONE
=
(
1
<<
21
),
/* 6xxx: IRQ coalescing */
GPIO_INT
=
(
1
<<
22
),
SELF_INT
=
(
1
<<
23
),
TWSI_INT
=
(
1
<<
24
),
HC_MAIN_RSVD
=
(
0x7f
<<
25
),
/* bits 31-25 */
HC_MAIN_MASKED_IRQS
=
(
TRAN_LO_DONE
|
TRAN_HI_DONE
|
PORTS_0_7_COAL_DONE
|
GPIO_INT
|
TWSI_INT
|
HC_MAIN_RSVD
),
/* SATAHC registers */
HC_CFG_OFS
=
0
,
HC_IRQ_CAUSE_OFS
=
0x14
,
CRBP_DMA_DONE
=
(
1
<<
0
),
/* shift by port # */
HC_IRQ_COAL
=
(
1
<<
4
),
/* IRQ coalescing */
DEV_IRQ
=
(
1
<<
8
),
/* shift by port # */
/* Shadow block registers */
SHD_PIO_DATA_OFS
=
0x100
,
SHD_FEA_ERR_OFS
=
0x104
,
SHD_SECT_CNT_OFS
=
0x108
,
SHD_LBA_L_OFS
=
0x10C
,
SHD_LBA_M_OFS
=
0x110
,
SHD_LBA_H_OFS
=
0x114
,
SHD_DEV_HD_OFS
=
0x118
,
SHD_CMD_STA_OFS
=
0x11C
,
SHD_CTL_AST_OFS
=
0x120
,
/* SATA registers */
SATA_STATUS_OFS
=
0x300
,
/* ctrl, err regs follow status */
SATA_ACTIVE_OFS
=
0x350
,
/* Port registers */
EDMA_CFG_OFS
=
0
,
EDMA_ERR_IRQ_CAUSE_OFS
=
0x8
,
EDMA_ERR_IRQ_MASK_OFS
=
0xc
,
EDMA_ERR_D_PAR
=
(
1
<<
0
),
EDMA_ERR_PRD_PAR
=
(
1
<<
1
),
EDMA_ERR_DEV
=
(
1
<<
2
),
EDMA_ERR_DEV_DCON
=
(
1
<<
3
),
EDMA_ERR_DEV_CON
=
(
1
<<
4
),
EDMA_ERR_SERR
=
(
1
<<
5
),
EDMA_ERR_SELF_DIS
=
(
1
<<
7
),
EDMA_ERR_BIST_ASYNC
=
(
1
<<
8
),
EDMA_ERR_CRBQ_PAR
=
(
1
<<
9
),
EDMA_ERR_CRPB_PAR
=
(
1
<<
10
),
EDMA_ERR_INTRL_PAR
=
(
1
<<
11
),
EDMA_ERR_IORDY
=
(
1
<<
12
),
EDMA_ERR_LNK_CTRL_RX
=
(
0xf
<<
13
),
EDMA_ERR_LNK_CTRL_RX_2
=
(
1
<<
15
),
EDMA_ERR_LNK_DATA_RX
=
(
0xf
<<
17
),
EDMA_ERR_LNK_CTRL_TX
=
(
0x1f
<<
21
),
EDMA_ERR_LNK_DATA_TX
=
(
0x1f
<<
26
),
EDMA_ERR_TRANS_PROTO
=
(
1
<<
31
),
EDMA_ERR_FATAL
=
(
EDMA_ERR_D_PAR
|
EDMA_ERR_PRD_PAR
|
EDMA_ERR_DEV_DCON
|
EDMA_ERR_CRBQ_PAR
|
EDMA_ERR_CRPB_PAR
|
EDMA_ERR_INTRL_PAR
|
EDMA_ERR_IORDY
|
EDMA_ERR_LNK_CTRL_RX_2
|
EDMA_ERR_LNK_DATA_RX
|
EDMA_ERR_LNK_DATA_TX
|
EDMA_ERR_TRANS_PROTO
),
EDMA_CMD_OFS
=
0x28
,
EDMA_EN
=
(
1
<<
0
),
EDMA_DS
=
(
1
<<
1
),
ATA_RST
=
(
1
<<
2
),
/* BDMA is 6xxx part only */
BDMA_CMD_OFS
=
0x224
,
BDMA_START
=
(
1
<<
0
),
MV_UNDEF
=
0
,
};
struct
mv_port_priv
{
};
struct
mv_host_priv
{
};
static
void
mv_irq_clear
(
struct
ata_port
*
ap
);
static
u32
mv_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg_in
);
static
void
mv_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg_in
,
u32
val
);
static
void
mv_phy_reset
(
struct
ata_port
*
ap
);
static
int
mv_master_reset
(
void
__iomem
*
mmio_base
);
static
irqreturn_t
mv_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
int
mv_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
);
static
Scsi_Host_Template
mv_sht
=
{
.
module
=
THIS_MODULE
,
.
name
=
DRV_NAME
,
.
ioctl
=
ata_scsi_ioctl
,
.
queuecommand
=
ata_scsi_queuecmd
,
.
eh_strategy_handler
=
ata_scsi_error
,
.
can_queue
=
ATA_DEF_QUEUE
,
.
this_id
=
ATA_SHT_THIS_ID
,
.
sg_tablesize
=
MV_UNDEF
,
.
max_sectors
=
ATA_MAX_SECTORS
,
.
cmd_per_lun
=
ATA_SHT_CMD_PER_LUN
,
.
emulated
=
ATA_SHT_EMULATED
,
.
use_clustering
=
MV_UNDEF
,
.
proc_name
=
DRV_NAME
,
.
dma_boundary
=
MV_DMA_BOUNDARY
,
.
slave_configure
=
ata_scsi_slave_config
,
.
bios_param
=
ata_std_bios_param
,
.
ordered_flush
=
1
,
};
static
struct
ata_port_operations
mv_ops
=
{
.
port_disable
=
ata_port_disable
,
.
tf_load
=
ata_tf_load
,
.
tf_read
=
ata_tf_read
,
.
check_status
=
ata_check_status
,
.
exec_command
=
ata_exec_command
,
.
dev_select
=
ata_std_dev_select
,
.
phy_reset
=
mv_phy_reset
,
.
qc_prep
=
ata_qc_prep
,
.
qc_issue
=
ata_qc_issue_prot
,
.
eng_timeout
=
ata_eng_timeout
,
.
irq_handler
=
mv_interrupt
,
.
irq_clear
=
mv_irq_clear
,
.
scr_read
=
mv_scr_read
,
.
scr_write
=
mv_scr_write
,
.
port_start
=
ata_port_start
,
.
port_stop
=
ata_port_stop
,
.
host_stop
=
ata_host_stop
,
};
static
struct
ata_port_info
mv_port_info
[]
=
{
{
/* chip_504x */
.
sht
=
&
mv_sht
,
.
host_flags
=
(
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
),
.
pio_mask
=
0x1f
,
/* pio4-0 */
.
udma_mask
=
0
,
/* 0x7f (udma6-0 disabled for now) */
.
port_ops
=
&
mv_ops
,
},
{
/* chip_508x */
.
sht
=
&
mv_sht
,
.
host_flags
=
(
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
MV_FLAG_DUAL_HC
),
.
pio_mask
=
0x1f
,
/* pio4-0 */
.
udma_mask
=
0
,
/* 0x7f (udma6-0 disabled for now) */
.
port_ops
=
&
mv_ops
,
},
{
/* chip_604x */
.
sht
=
&
mv_sht
,
.
host_flags
=
(
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
MV_FLAG_IRQ_COALESCE
|
MV_FLAG_BDMA
),
.
pio_mask
=
0x1f
,
/* pio4-0 */
.
udma_mask
=
0
,
/* 0x7f (udma6-0 disabled for now) */
.
port_ops
=
&
mv_ops
,
},
{
/* chip_608x */
.
sht
=
&
mv_sht
,
.
host_flags
=
(
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
MV_FLAG_IRQ_COALESCE
|
MV_FLAG_DUAL_HC
|
MV_FLAG_BDMA
),
.
pio_mask
=
0x1f
,
/* pio4-0 */
.
udma_mask
=
0
,
/* 0x7f (udma6-0 disabled for now) */
.
port_ops
=
&
mv_ops
,
},
};
static
struct
pci_device_id
mv_pci_tbl
[]
=
{
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x5040
),
0
,
0
,
chip_504x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x5041
),
0
,
0
,
chip_504x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x5080
),
0
,
0
,
chip_508x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x5081
),
0
,
0
,
chip_508x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x6040
),
0
,
0
,
chip_604x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x6041
),
0
,
0
,
chip_604x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x6080
),
0
,
0
,
chip_608x
},
{
PCI_DEVICE
(
PCI_VENDOR_ID_MARVELL
,
0x6081
),
0
,
0
,
chip_608x
},
{}
/* terminate list */
};
static
struct
pci_driver
mv_pci_driver
=
{
.
name
=
DRV_NAME
,
.
id_table
=
mv_pci_tbl
,
.
probe
=
mv_init_one
,
.
remove
=
ata_pci_remove_one
,
};
/*
* Functions
*/
static
inline
void
writelfl
(
unsigned
long
data
,
void
__iomem
*
addr
)
{
writel
(
data
,
addr
);
(
void
)
readl
(
addr
);
/* flush to avoid PCI posted write */
}
static
inline
void
__iomem
*
mv_port_addr_to_hc_base
(
void
__iomem
*
port_mmio
)
{
return
((
void
__iomem
*
)((
unsigned
long
)
port_mmio
&
(
unsigned
long
)
SATAHC_MASK
));
}
static
inline
void
__iomem
*
mv_hc_base
(
void
__iomem
*
base
,
unsigned
int
hc
)
{
return
(
base
+
MV_SATAHC0_REG_BASE
+
(
hc
*
MV_SATAHC_REG_SZ
));
}
static
inline
void
__iomem
*
mv_port_base
(
void
__iomem
*
base
,
unsigned
int
port
)
{
return
(
mv_hc_base
(
base
,
port
>>
MV_PORT_HC_SHIFT
)
+
MV_SATAHC_ARBTR_REG_SZ
+
((
port
&
MV_PORT_MASK
)
*
MV_PORT_REG_SZ
));
}
static
inline
void
__iomem
*
mv_ap_base
(
struct
ata_port
*
ap
)
{
return
mv_port_base
(
ap
->
host_set
->
mmio_base
,
ap
->
port_no
);
}
static
inline
int
mv_get_hc_count
(
unsigned
long
flags
)
{
return
((
flags
&
MV_FLAG_DUAL_HC
)
?
2
:
1
);
}
static
inline
int
mv_is_edma_active
(
struct
ata_port
*
ap
)
{
void
__iomem
*
port_mmio
=
mv_ap_base
(
ap
);
return
(
EDMA_EN
&
readl
(
port_mmio
+
EDMA_CMD_OFS
));
}
static
inline
int
mv_port_bdma_capable
(
struct
ata_port
*
ap
)
{
return
(
ap
->
flags
&
MV_FLAG_BDMA
);
}
static
void
mv_irq_clear
(
struct
ata_port
*
ap
)
{
}
static
unsigned
int
mv_scr_offset
(
unsigned
int
sc_reg_in
)
{
unsigned
int
ofs
;
switch
(
sc_reg_in
)
{
case
SCR_STATUS
:
case
SCR_CONTROL
:
case
SCR_ERROR
:
ofs
=
SATA_STATUS_OFS
+
(
sc_reg_in
*
sizeof
(
u32
));
break
;
case
SCR_ACTIVE
:
ofs
=
SATA_ACTIVE_OFS
;
/* active is not with the others */
break
;
default:
ofs
=
0xffffffffU
;
break
;
}
return
ofs
;
}
static
u32
mv_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg_in
)
{
unsigned
int
ofs
=
mv_scr_offset
(
sc_reg_in
);
if
(
0xffffffffU
!=
ofs
)
{
return
readl
(
mv_ap_base
(
ap
)
+
ofs
);
}
else
{
return
(
u32
)
ofs
;
}
}
static
void
mv_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg_in
,
u32
val
)
{
unsigned
int
ofs
=
mv_scr_offset
(
sc_reg_in
);
if
(
0xffffffffU
!=
ofs
)
{
writelfl
(
val
,
mv_ap_base
(
ap
)
+
ofs
);
}
}
static
int
mv_master_reset
(
void
__iomem
*
mmio_base
)
{
void
__iomem
*
reg
=
mmio_base
+
PCI_MAIN_CMD_STS_OFS
;
int
i
,
rc
=
0
;
u32
t
;
VPRINTK
(
"ENTER
\n
"
);
/* Following procedure defined in PCI "main command and status
* register" table.
*/
t
=
readl
(
reg
);
writel
(
t
|
STOP_PCI_MASTER
,
reg
);
for
(
i
=
0
;
i
<
100
;
i
++
)
{
msleep
(
10
);
t
=
readl
(
reg
);
if
(
PCI_MASTER_EMPTY
&
t
)
{
break
;
}
}
if
(
!
(
PCI_MASTER_EMPTY
&
t
))
{
printk
(
KERN_ERR
DRV_NAME
"PCI master won't flush
\n
"
);
rc
=
1
;
/* broken HW? */
goto
done
;
}
/* set reset */
i
=
5
;
do
{
writel
(
t
|
GLOB_SFT_RST
,
reg
);
t
=
readl
(
reg
);
udelay
(
1
);
}
while
(
!
(
GLOB_SFT_RST
&
t
)
&&
(
i
--
>
0
));
if
(
!
(
GLOB_SFT_RST
&
t
))
{
printk
(
KERN_ERR
DRV_NAME
"can't set global reset
\n
"
);
rc
=
1
;
/* broken HW? */
goto
done
;
}
/* clear reset */
i
=
5
;
do
{
writel
(
t
&
~
GLOB_SFT_RST
,
reg
);
t
=
readl
(
reg
);
udelay
(
1
);
}
while
((
GLOB_SFT_RST
&
t
)
&&
(
i
--
>
0
));
if
(
GLOB_SFT_RST
&
t
)
{
printk
(
KERN_ERR
DRV_NAME
"can't clear global reset
\n
"
);
rc
=
1
;
/* broken HW? */
}
done:
VPRINTK
(
"EXIT, rc = %i
\n
"
,
rc
);
return
rc
;
}
static
void
mv_err_intr
(
struct
ata_port
*
ap
)
{
void
__iomem
*
port_mmio
;
u32
edma_err_cause
,
serr
=
0
;
/* bug here b/c we got an err int on a port we don't know about,
* so there's no way to clear it
*/
BUG_ON
(
NULL
==
ap
);
port_mmio
=
mv_ap_base
(
ap
);
edma_err_cause
=
readl
(
port_mmio
+
EDMA_ERR_IRQ_CAUSE_OFS
);
if
(
EDMA_ERR_SERR
&
edma_err_cause
)
{
serr
=
scr_read
(
ap
,
SCR_ERROR
);
scr_write_flush
(
ap
,
SCR_ERROR
,
serr
);
}
DPRINTK
(
"port %u error; EDMA err cause: 0x%08x SERR: 0x%08x
\n
"
,
ap
->
port_no
,
edma_err_cause
,
serr
);
/* Clear EDMA now that SERR cleanup done */
writelfl
(
0
,
port_mmio
+
EDMA_ERR_IRQ_CAUSE_OFS
);
/* check for fatal here and recover if needed */
if
(
EDMA_ERR_FATAL
&
edma_err_cause
)
{
mv_phy_reset
(
ap
);
}
}
/* Handle any outstanding interrupts in a single SATAHC
*/
static
void
mv_host_intr
(
struct
ata_host_set
*
host_set
,
u32
relevant
,
unsigned
int
hc
)
{
void
__iomem
*
mmio
=
host_set
->
mmio_base
;
void
__iomem
*
hc_mmio
=
mv_hc_base
(
mmio
,
hc
);
struct
ata_port
*
ap
;
struct
ata_queued_cmd
*
qc
;
u32
hc_irq_cause
;
int
shift
,
port
,
port0
,
hard_port
;
u8
ata_status
;
if
(
hc
==
0
)
{
port0
=
0
;
}
else
{
port0
=
MV_PORTS_PER_HC
;
}
/* we'll need the HC success int register in most cases */
hc_irq_cause
=
readl
(
hc_mmio
+
HC_IRQ_CAUSE_OFS
);
if
(
hc_irq_cause
)
{
writelfl
(
0
,
hc_mmio
+
HC_IRQ_CAUSE_OFS
);
}
VPRINTK
(
"ENTER, hc%u relevant=0x%08x HC IRQ cause=0x%08x
\n
"
,
hc
,
relevant
,
hc_irq_cause
);
for
(
port
=
port0
;
port
<
port0
+
MV_PORTS_PER_HC
;
port
++
)
{
ap
=
host_set
->
ports
[
port
];
hard_port
=
port
&
MV_PORT_MASK
;
/* range 0-3 */
ata_status
=
0xffU
;
if
(((
CRBP_DMA_DONE
|
DEV_IRQ
)
<<
hard_port
)
&
hc_irq_cause
)
{
BUG_ON
(
NULL
==
ap
);
/* rcv'd new resp, basic DMA complete, or ATA IRQ */
/* This is needed to clear the ATA INTRQ.
* FIXME: don't read the status reg in EDMA mode!
*/
ata_status
=
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
status_addr
);
}
shift
=
port
*
2
;
if
(
port
>=
MV_PORTS_PER_HC
)
{
shift
++
;
/* skip bit 8 in the HC Main IRQ reg */
}
if
((
PORT0_ERR
<<
shift
)
&
relevant
)
{
mv_err_intr
(
ap
);
/* FIXME: smart to OR in ATA_ERR? */
ata_status
=
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
status_addr
)
|
ATA_ERR
;
}
if
(
ap
)
{
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
NULL
!=
qc
)
{
VPRINTK
(
"port %u IRQ found for qc, "
"ata_status 0x%x
\n
"
,
port
,
ata_status
);
BUG_ON
(
0xffU
==
ata_status
);
/* mark qc status appropriately */
ata_qc_complete
(
qc
,
ata_status
);
}
}
}
VPRINTK
(
"EXIT
\n
"
);
}
static
irqreturn_t
mv_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ata_host_set
*
host_set
=
dev_instance
;
unsigned
int
hc
,
handled
=
0
,
n_hcs
;
void
__iomem
*
mmio
;
u32
irq_stat
;
mmio
=
host_set
->
mmio_base
;
irq_stat
=
readl
(
mmio
+
HC_MAIN_IRQ_CAUSE_OFS
);
n_hcs
=
mv_get_hc_count
(
host_set
->
ports
[
0
]
->
flags
);
/* check the cases where we either have nothing pending or have read
* a bogus register value which can indicate HW removal or PCI fault
*/
if
(
!
irq_stat
||
(
0xffffffffU
==
irq_stat
))
{
return
IRQ_NONE
;
}
spin_lock
(
&
host_set
->
lock
);
for
(
hc
=
0
;
hc
<
n_hcs
;
hc
++
)
{
u32
relevant
=
irq_stat
&
(
HC0_IRQ_PEND
<<
(
hc
*
HC_SHIFT
));
if
(
relevant
)
{
mv_host_intr
(
host_set
,
relevant
,
hc
);
handled
=
1
;
}
}
if
(
PCI_ERR
&
irq_stat
)
{
/* FIXME: these are all masked by default, but still need
* to recover from them properly.
*/
}
spin_unlock
(
&
host_set
->
lock
);
return
IRQ_RETVAL
(
handled
);
}
static
void
mv_phy_reset
(
struct
ata_port
*
ap
)
{
void
__iomem
*
port_mmio
=
mv_ap_base
(
ap
);
struct
ata_taskfile
tf
;
struct
ata_device
*
dev
=
&
ap
->
device
[
0
];
u32
edma
=
0
,
bdma
;
VPRINTK
(
"ENTER, port %u, mmio 0x%p
\n
"
,
ap
->
port_no
,
port_mmio
);
edma
=
readl
(
port_mmio
+
EDMA_CMD_OFS
);
if
(
EDMA_EN
&
edma
)
{
/* disable EDMA if active */
edma
&=
~
EDMA_EN
;
writelfl
(
edma
|
EDMA_DS
,
port_mmio
+
EDMA_CMD_OFS
);
udelay
(
1
);
}
else
if
(
mv_port_bdma_capable
(
ap
)
&&
(
bdma
=
readl
(
port_mmio
+
BDMA_CMD_OFS
))
&
BDMA_START
)
{
/* disable BDMA if active */
writelfl
(
bdma
&
~
BDMA_START
,
port_mmio
+
BDMA_CMD_OFS
);
}
writelfl
(
edma
|
ATA_RST
,
port_mmio
+
EDMA_CMD_OFS
);
udelay
(
25
);
/* allow reset propagation */
/* Spec never mentions clearing the bit. Marvell's driver does
* clear the bit, however.
*/
writelfl
(
edma
&
~
ATA_RST
,
port_mmio
+
EDMA_CMD_OFS
);
VPRINTK
(
"Done. Now calling __sata_phy_reset()
\n
"
);
/* proceed to init communications via the scr_control reg */
__sata_phy_reset
(
ap
);
if
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
)
{
VPRINTK
(
"Port disabled pre-sig. Exiting.
\n
"
);
return
;
}
tf
.
lbah
=
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
lbah_addr
);
tf
.
lbam
=
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
lbam_addr
);
tf
.
lbal
=
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
lbal_addr
);
tf
.
nsect
=
readb
((
void
__iomem
*
)
ap
->
ioaddr
.
nsect_addr
);
dev
->
class
=
ata_dev_classify
(
&
tf
);
if
(
!
ata_dev_present
(
dev
))
{
VPRINTK
(
"Port disabled post-sig: No device present.
\n
"
);
ata_port_disable
(
ap
);
}
VPRINTK
(
"EXIT
\n
"
);
}
static
void
mv_port_init
(
struct
ata_ioports
*
port
,
unsigned
long
base
)
{
/* PIO related setup */
port
->
data_addr
=
base
+
SHD_PIO_DATA_OFS
;
port
->
error_addr
=
port
->
feature_addr
=
base
+
SHD_FEA_ERR_OFS
;
port
->
nsect_addr
=
base
+
SHD_SECT_CNT_OFS
;
port
->
lbal_addr
=
base
+
SHD_LBA_L_OFS
;
port
->
lbam_addr
=
base
+
SHD_LBA_M_OFS
;
port
->
lbah_addr
=
base
+
SHD_LBA_H_OFS
;
port
->
device_addr
=
base
+
SHD_DEV_HD_OFS
;
port
->
status_addr
=
port
->
command_addr
=
base
+
SHD_CMD_STA_OFS
;
port
->
altstatus_addr
=
port
->
ctl_addr
=
base
+
SHD_CTL_AST_OFS
;
/* unused */
port
->
cmd_addr
=
port
->
bmdma_addr
=
port
->
scr_addr
=
0
;
/* unmask all EDMA error interrupts */
writel
(
~
0
,
(
void
__iomem
*
)
base
+
EDMA_ERR_IRQ_MASK_OFS
);
VPRINTK
(
"EDMA cfg=0x%08x EDMA IRQ err cause/mask=0x%08x/0x%08x
\n
"
,
readl
((
void
__iomem
*
)
base
+
EDMA_CFG_OFS
),
readl
((
void
__iomem
*
)
base
+
EDMA_ERR_IRQ_CAUSE_OFS
),
readl
((
void
__iomem
*
)
base
+
EDMA_ERR_IRQ_MASK_OFS
));
}
static
int
mv_host_init
(
struct
ata_probe_ent
*
probe_ent
)
{
int
rc
=
0
,
n_hc
,
port
,
hc
;
void
__iomem
*
mmio
=
probe_ent
->
mmio_base
;
void
__iomem
*
port_mmio
;
if
(
mv_master_reset
(
probe_ent
->
mmio_base
))
{
rc
=
1
;
goto
done
;
}
n_hc
=
mv_get_hc_count
(
probe_ent
->
host_flags
);
probe_ent
->
n_ports
=
MV_PORTS_PER_HC
*
n_hc
;
for
(
port
=
0
;
port
<
probe_ent
->
n_ports
;
port
++
)
{
port_mmio
=
mv_port_base
(
mmio
,
port
);
mv_port_init
(
&
probe_ent
->
port
[
port
],
(
unsigned
long
)
port_mmio
);
}
for
(
hc
=
0
;
hc
<
n_hc
;
hc
++
)
{
VPRINTK
(
"HC%i: HC config=0x%08x HC IRQ cause=0x%08x
\n
"
,
hc
,
readl
(
mv_hc_base
(
mmio
,
hc
)
+
HC_CFG_OFS
),
readl
(
mv_hc_base
(
mmio
,
hc
)
+
HC_IRQ_CAUSE_OFS
));
}
writel
(
~
HC_MAIN_MASKED_IRQS
,
mmio
+
HC_MAIN_IRQ_MASK_OFS
);
writel
(
PCI_UNMASK_ALL_IRQS
,
mmio
+
PCI_IRQ_MASK_OFS
);
VPRINTK
(
"HC MAIN IRQ cause/mask=0x%08x/0x%08x "
"PCI int cause/mask=0x%08x/0x%08x
\n
"
,
readl
(
mmio
+
HC_MAIN_IRQ_CAUSE_OFS
),
readl
(
mmio
+
HC_MAIN_IRQ_MASK_OFS
),
readl
(
mmio
+
PCI_IRQ_CAUSE_OFS
),
readl
(
mmio
+
PCI_IRQ_MASK_OFS
));
done:
return
rc
;
}
/* move to PCI layer, integrate w/ MSI stuff */
static
void
pci_intx
(
struct
pci_dev
*
pdev
,
int
enable
)
{
u16
pci_command
,
new
;
pci_read_config_word
(
pdev
,
PCI_COMMAND
,
&
pci_command
);
if
(
enable
)
new
=
pci_command
&
~
PCI_COMMAND_INTX_DISABLE
;
else
new
=
pci_command
|
PCI_COMMAND_INTX_DISABLE
;
if
(
new
!=
pci_command
)
pci_write_config_word
(
pdev
,
PCI_COMMAND
,
pci_command
);
}
static
int
mv_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
int
printed_version
=
0
;
struct
ata_probe_ent
*
probe_ent
=
NULL
;
struct
mv_host_priv
*
hpriv
;
unsigned
int
board_idx
=
(
unsigned
int
)
ent
->
driver_data
;
void
__iomem
*
mmio_base
;
int
pci_dev_busy
=
0
;
int
rc
;
if
(
!
printed_version
++
)
{
printk
(
KERN_DEBUG
DRV_NAME
" version "
DRV_VERSION
"
\n
"
);
}
VPRINTK
(
"ENTER for PCI Bus:Slot.Func=%u:%u.%u
\n
"
,
pdev
->
bus
->
number
,
PCI_SLOT
(
pdev
->
devfn
),
PCI_FUNC
(
pdev
->
devfn
));
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
{
return
rc
;
}
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
{
pci_dev_busy
=
1
;
goto
err_out
;
}
pci_intx
(
pdev
,
1
);
probe_ent
=
kmalloc
(
sizeof
(
*
probe_ent
),
GFP_KERNEL
);
if
(
probe_ent
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
err_out_regions
;
}
memset
(
probe_ent
,
0
,
sizeof
(
*
probe_ent
));
probe_ent
->
dev
=
pci_dev_to_dev
(
pdev
);
INIT_LIST_HEAD
(
&
probe_ent
->
node
);
mmio_base
=
ioremap_nocache
(
pci_resource_start
(
pdev
,
MV_PRIMARY_BAR
),
pci_resource_len
(
pdev
,
MV_PRIMARY_BAR
));
if
(
mmio_base
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
err_out_free_ent
;
}
hpriv
=
kmalloc
(
sizeof
(
*
hpriv
),
GFP_KERNEL
);
if
(
!
hpriv
)
{
rc
=
-
ENOMEM
;
goto
err_out_iounmap
;
}
memset
(
hpriv
,
0
,
sizeof
(
*
hpriv
));
probe_ent
->
sht
=
mv_port_info
[
board_idx
].
sht
;
probe_ent
->
host_flags
=
mv_port_info
[
board_idx
].
host_flags
;
probe_ent
->
pio_mask
=
mv_port_info
[
board_idx
].
pio_mask
;
probe_ent
->
udma_mask
=
mv_port_info
[
board_idx
].
udma_mask
;
probe_ent
->
port_ops
=
mv_port_info
[
board_idx
].
port_ops
;
probe_ent
->
irq
=
pdev
->
irq
;
probe_ent
->
irq_flags
=
SA_SHIRQ
;
probe_ent
->
mmio_base
=
mmio_base
;
probe_ent
->
private_data
=
hpriv
;
/* initialize adapter */
rc
=
mv_host_init
(
probe_ent
);
if
(
rc
)
{
goto
err_out_hpriv
;
}
/* mv_print_info(probe_ent); */
{
int
b
,
w
;
u32
dw
[
4
];
/* hold a line of 16b */
VPRINTK
(
"PCI config space:
\n
"
);
for
(
b
=
0
;
b
<
0x40
;
)
{
for
(
w
=
0
;
w
<
4
;
w
++
)
{
(
void
)
pci_read_config_dword
(
pdev
,
b
,
&
dw
[
w
]);
b
+=
sizeof
(
*
dw
);
}
VPRINTK
(
"%08x %08x %08x %08x
\n
"
,
dw
[
0
],
dw
[
1
],
dw
[
2
],
dw
[
3
]);
}
}
/* FIXME: check ata_device_add return value */
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
return
0
;
err_out_hpriv:
kfree
(
hpriv
);
err_out_iounmap:
iounmap
(
mmio_base
);
err_out_free_ent:
kfree
(
probe_ent
);
err_out_regions:
pci_release_regions
(
pdev
);
err_out:
if
(
!
pci_dev_busy
)
{
pci_disable_device
(
pdev
);
}
return
rc
;
}
static
int
__init
mv_init
(
void
)
{
return
pci_module_init
(
&
mv_pci_driver
);
}
static
void
__exit
mv_exit
(
void
)
{
pci_unregister_driver
(
&
mv_pci_driver
);
}
MODULE_AUTHOR
(
"Brett Russ"
);
MODULE_DESCRIPTION
(
"SCSI low-level driver for Marvell SATA controllers"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DEVICE_TABLE
(
pci
,
mv_pci_tbl
);
MODULE_VERSION
(
DRV_VERSION
);
module_init
(
mv_init
);
module_exit
(
mv_exit
);
drivers/scsi/sata_uli.c
View file @
cc896f08
...
...
@@ -125,8 +125,8 @@ static struct ata_port_info uli_port_info = {
.
sht
=
&
uli_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_NO_LEGACY
,
.
pio_mask
=
0x
03
,
//support pio mode 4 (FIXME)
.
udma_mask
=
0x7f
,
/
/support udma mode 6
.
pio_mask
=
0x
1f
,
/* pio0-4 */
.
udma_mask
=
0x7f
,
/
* udma0-6 */
.
port_ops
=
&
uli_ops
,
};
...
...
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