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
3d3467f0
Commit
3d3467f0
authored
Oct 09, 2005
by
Jeff Garzik
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'sil24'
parents
e710245b
042c21fd
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
884 additions
and
0 deletions
+884
-0
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+8
-0
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-0
drivers/scsi/sata_sil24.c
drivers/scsi/sata_sil24.c
+875
-0
No files found.
drivers/scsi/Kconfig
View file @
3d3467f0
...
...
@@ -521,6 +521,14 @@ config SCSI_SATA_SIL
If
unsure
,
say
N
.
config
SCSI_SATA_SIL24
tristate
"Silicon Image 3124/3132 SATA support"
depends
on
SCSI_SATA
&&
PCI
&&
EXPERIMENTAL
help
This
option
enables
support
for
Silicon
Image
3124
/
3132
Serial
ATA
.
If
unsure
,
say
N
.
config
SCSI_SATA_SIS
tristate
"SiS 964/180 SATA support"
depends
on
SCSI_SATA
&&
PCI
&&
EXPERIMENTAL
...
...
drivers/scsi/Makefile
View file @
3d3467f0
...
...
@@ -130,6 +130,7 @@ obj-$(CONFIG_SCSI_ATA_PIIX) += libata.o ata_piix.o
obj-$(CONFIG_SCSI_SATA_PROMISE)
+=
libata.o sata_promise.o
obj-$(CONFIG_SCSI_SATA_QSTOR)
+=
libata.o sata_qstor.o
obj-$(CONFIG_SCSI_SATA_SIL)
+=
libata.o sata_sil.o
obj-$(CONFIG_SCSI_SATA_SIL24)
+=
libata.o sata_sil24.o
obj-$(CONFIG_SCSI_SATA_VIA)
+=
libata.o sata_via.o
obj-$(CONFIG_SCSI_SATA_VITESSE)
+=
libata.o sata_vsc.o
obj-$(CONFIG_SCSI_SATA_SIS)
+=
libata.o sata_sis.o
...
...
drivers/scsi/sata_sil24.c
0 → 100644
View file @
3d3467f0
/*
* sata_sil24.c - Driver for Silicon Image 3124/3132 SATA-2 controllers
*
* Copyright 2005 Tejun Heo
*
* Based on preview driver from Silicon Image.
*
* NOTE: No NCQ/ATAPI support yet. The preview driver didn't support
* NCQ nor ATAPI, and, unfortunately, I couldn't find out how to make
* those work. Enabling those shouldn't be difficult. Basic
* structure is all there (in libata-dev tree). If you have any
* information about this hardware, please contact me or linux-ide.
* Info is needed on...
*
* - How to issue tagged commands and turn on sactive on issue accordingly.
* - Where to put an ATAPI command and how to tell the device to send it.
* - How to enable/use 64bit.
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <scsi/scsi_host.h>
#include "scsi.h"
#include <linux/libata.h>
#include <asm/io.h>
#define DRV_NAME "sata_sil24"
#define DRV_VERSION "0.22"
/* Silicon Image's preview driver was 0.10 */
/*
* Port request block (PRB) 32 bytes
*/
struct
sil24_prb
{
u16
ctrl
;
u16
prot
;
u32
rx_cnt
;
u8
fis
[
6
*
4
];
};
/*
* Scatter gather entry (SGE) 16 bytes
*/
struct
sil24_sge
{
u64
addr
;
u32
cnt
;
u32
flags
;
};
/*
* Port multiplier
*/
struct
sil24_port_multiplier
{
u32
diag
;
u32
sactive
;
};
enum
{
/*
* Global controller registers (128 bytes @ BAR0)
*/
/* 32 bit regs */
HOST_SLOT_STAT
=
0x00
,
/* 32 bit slot stat * 4 */
HOST_CTRL
=
0x40
,
HOST_IRQ_STAT
=
0x44
,
HOST_PHY_CFG
=
0x48
,
HOST_BIST_CTRL
=
0x50
,
HOST_BIST_PTRN
=
0x54
,
HOST_BIST_STAT
=
0x58
,
HOST_MEM_BIST_STAT
=
0x5c
,
HOST_FLASH_CMD
=
0x70
,
/* 8 bit regs */
HOST_FLASH_DATA
=
0x74
,
HOST_TRANSITION_DETECT
=
0x75
,
HOST_GPIO_CTRL
=
0x76
,
HOST_I2C_ADDR
=
0x78
,
/* 32 bit */
HOST_I2C_DATA
=
0x7c
,
HOST_I2C_XFER_CNT
=
0x7e
,
HOST_I2C_CTRL
=
0x7f
,
/* HOST_SLOT_STAT bits */
HOST_SSTAT_ATTN
=
(
1
<<
31
),
/*
* Port registers
* (8192 bytes @ +0x0000, +0x2000, +0x4000 and +0x6000 @ BAR2)
*/
PORT_REGS_SIZE
=
0x2000
,
PORT_PRB
=
0x0000
,
/* (32 bytes PRB + 16 bytes SGEs * 6) * 31 (3968 bytes) */
PORT_PM
=
0x0f80
,
/* 8 bytes PM * 16 (128 bytes) */
/* 32 bit regs */
PORT_CTRL_STAT
=
0x1000
,
/* write: ctrl-set, read: stat */
PORT_CTRL_CLR
=
0x1004
,
/* write: ctrl-clear */
PORT_IRQ_STAT
=
0x1008
,
/* high: status, low: interrupt */
PORT_IRQ_ENABLE_SET
=
0x1010
,
/* write: enable-set */
PORT_IRQ_ENABLE_CLR
=
0x1014
,
/* write: enable-clear */
PORT_ACTIVATE_UPPER_ADDR
=
0x101c
,
PORT_EXEC_FIFO
=
0x1020
,
/* command execution fifo */
PORT_CMD_ERR
=
0x1024
,
/* command error number */
PORT_FIS_CFG
=
0x1028
,
PORT_FIFO_THRES
=
0x102c
,
/* 16 bit regs */
PORT_DECODE_ERR_CNT
=
0x1040
,
PORT_DECODE_ERR_THRESH
=
0x1042
,
PORT_CRC_ERR_CNT
=
0x1044
,
PORT_CRC_ERR_THRESH
=
0x1046
,
PORT_HSHK_ERR_CNT
=
0x1048
,
PORT_HSHK_ERR_THRESH
=
0x104a
,
/* 32 bit regs */
PORT_PHY_CFG
=
0x1050
,
PORT_SLOT_STAT
=
0x1800
,
PORT_CMD_ACTIVATE
=
0x1c00
,
/* 64 bit cmd activate * 31 (248 bytes) */
PORT_EXEC_DIAG
=
0x1e00
,
/* 32bit exec diag * 16 (64 bytes, 0-10 used on 3124) */
PORT_PSD_DIAG
=
0x1e40
,
/* 32bit psd diag * 16 (64 bytes, 0-8 used on 3124) */
PORT_SCONTROL
=
0x1f00
,
PORT_SSTATUS
=
0x1f04
,
PORT_SERROR
=
0x1f08
,
PORT_SACTIVE
=
0x1f0c
,
/* PORT_CTRL_STAT bits */
PORT_CS_PORT_RST
=
(
1
<<
0
),
/* port reset */
PORT_CS_DEV_RST
=
(
1
<<
1
),
/* device reset */
PORT_CS_INIT
=
(
1
<<
2
),
/* port initialize */
PORT_CS_IRQ_WOC
=
(
1
<<
3
),
/* interrupt write one to clear */
PORT_CS_RESUME
=
(
1
<<
6
),
/* port resume */
PORT_CS_32BIT_ACTV
=
(
1
<<
10
),
/* 32-bit activation */
PORT_CS_PM_EN
=
(
1
<<
13
),
/* port multiplier enable */
PORT_CS_RDY
=
(
1
<<
31
),
/* port ready to accept commands */
/* PORT_IRQ_STAT/ENABLE_SET/CLR */
/* bits[11:0] are masked */
PORT_IRQ_COMPLETE
=
(
1
<<
0
),
/* command(s) completed */
PORT_IRQ_ERROR
=
(
1
<<
1
),
/* command execution error */
PORT_IRQ_PORTRDY_CHG
=
(
1
<<
2
),
/* port ready change */
PORT_IRQ_PWR_CHG
=
(
1
<<
3
),
/* power management change */
PORT_IRQ_PHYRDY_CHG
=
(
1
<<
4
),
/* PHY ready change */
PORT_IRQ_COMWAKE
=
(
1
<<
5
),
/* COMWAKE received */
PORT_IRQ_UNK_FIS
=
(
1
<<
6
),
/* Unknown FIS received */
PORT_IRQ_SDB_FIS
=
(
1
<<
11
),
/* SDB FIS received */
/* bits[27:16] are unmasked (raw) */
PORT_IRQ_RAW_SHIFT
=
16
,
PORT_IRQ_MASKED_MASK
=
0x7ff
,
PORT_IRQ_RAW_MASK
=
(
0x7ff
<<
PORT_IRQ_RAW_SHIFT
),
/* ENABLE_SET/CLR specific, intr steering - 2 bit field */
PORT_IRQ_STEER_SHIFT
=
30
,
PORT_IRQ_STEER_MASK
=
(
3
<<
PORT_IRQ_STEER_SHIFT
),
/* PORT_CMD_ERR constants */
PORT_CERR_DEV
=
1
,
/* Error bit in D2H Register FIS */
PORT_CERR_SDB
=
2
,
/* Error bit in SDB FIS */
PORT_CERR_DATA
=
3
,
/* Error in data FIS not detected by dev */
PORT_CERR_SEND
=
4
,
/* Initial cmd FIS transmission failure */
PORT_CERR_INCONSISTENT
=
5
,
/* Protocol mismatch */
PORT_CERR_DIRECTION
=
6
,
/* Data direction mismatch */
PORT_CERR_UNDERRUN
=
7
,
/* Ran out of SGEs while writing */
PORT_CERR_OVERRUN
=
8
,
/* Ran out of SGEs while reading */
PORT_CERR_PKT_PROT
=
11
,
/* DIR invalid in 1st PIO setup of ATAPI */
PORT_CERR_SGT_BOUNDARY
=
16
,
/* PLD ecode 00 - SGT not on qword boundary */
PORT_CERR_SGT_TGTABRT
=
17
,
/* PLD ecode 01 - target abort */
PORT_CERR_SGT_MSTABRT
=
18
,
/* PLD ecode 10 - master abort */
PORT_CERR_SGT_PCIPERR
=
19
,
/* PLD ecode 11 - PCI parity err while fetching SGT */
PORT_CERR_CMD_BOUNDARY
=
24
,
/* ctrl[15:13] 001 - PRB not on qword boundary */
PORT_CERR_CMD_TGTABRT
=
25
,
/* ctrl[15:13] 010 - target abort */
PORT_CERR_CMD_MSTABRT
=
26
,
/* ctrl[15:13] 100 - master abort */
PORT_CERR_CMD_PCIPERR
=
27
,
/* ctrl[15:13] 110 - PCI parity err while fetching PRB */
PORT_CERR_XFR_UNDEF
=
32
,
/* PSD ecode 00 - undefined */
PORT_CERR_XFR_TGTABRT
=
33
,
/* PSD ecode 01 - target abort */
PORT_CERR_XFR_MSGABRT
=
34
,
/* PSD ecode 10 - master abort */
PORT_CERR_XFR_PCIPERR
=
35
,
/* PSD ecode 11 - PCI prity err during transfer */
PORT_CERR_SENDSERVICE
=
36
,
/* FIS received while sending service */
/*
* Other constants
*/
SGE_TRM
=
(
1
<<
31
),
/* Last SGE in chain */
PRB_SOFT_RST
=
(
1
<<
7
),
/* Soft reset request (ign BSY?) */
/* board id */
BID_SIL3124
=
0
,
BID_SIL3132
=
1
,
BID_SIL3131
=
2
,
IRQ_STAT_4PORTS
=
0xf
,
};
struct
sil24_cmd_block
{
struct
sil24_prb
prb
;
struct
sil24_sge
sge
[
LIBATA_MAX_PRD
];
};
/*
* ap->private_data
*
* The preview driver always returned 0 for status. We emulate it
* here from the previous interrupt.
*/
struct
sil24_port_priv
{
struct
sil24_cmd_block
*
cmd_block
;
/* 32 cmd blocks */
dma_addr_t
cmd_block_dma
;
/* DMA base addr for them */
struct
ata_taskfile
tf
;
/* Cached taskfile registers */
};
/* ap->host_set->private_data */
struct
sil24_host_priv
{
void
*
host_base
;
/* global controller control (128 bytes @BAR0) */
void
*
port_base
;
/* port registers (4 * 8192 bytes @BAR2) */
};
static
u8
sil24_check_status
(
struct
ata_port
*
ap
);
static
u8
sil24_check_err
(
struct
ata_port
*
ap
);
static
u32
sil24_scr_read
(
struct
ata_port
*
ap
,
unsigned
sc_reg
);
static
void
sil24_scr_write
(
struct
ata_port
*
ap
,
unsigned
sc_reg
,
u32
val
);
static
void
sil24_tf_read
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
);
static
void
sil24_phy_reset
(
struct
ata_port
*
ap
);
static
void
sil24_qc_prep
(
struct
ata_queued_cmd
*
qc
);
static
int
sil24_qc_issue
(
struct
ata_queued_cmd
*
qc
);
static
void
sil24_irq_clear
(
struct
ata_port
*
ap
);
static
void
sil24_eng_timeout
(
struct
ata_port
*
ap
);
static
irqreturn_t
sil24_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
int
sil24_port_start
(
struct
ata_port
*
ap
);
static
void
sil24_port_stop
(
struct
ata_port
*
ap
);
static
void
sil24_host_stop
(
struct
ata_host_set
*
host_set
);
static
int
sil24_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
);
static
struct
pci_device_id
sil24_pci_tbl
[]
=
{
{
0x1095
,
0x3124
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
BID_SIL3124
},
{
0x1095
,
0x3132
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
BID_SIL3132
},
{
0x1095
,
0x3131
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
BID_SIL3131
},
{
0x1095
,
0x3531
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
BID_SIL3131
},
{
}
/* terminate list */
};
static
struct
pci_driver
sil24_pci_driver
=
{
.
name
=
DRV_NAME
,
.
id_table
=
sil24_pci_tbl
,
.
probe
=
sil24_init_one
,
.
remove
=
ata_pci_remove_one
,
/* safe? */
};
static
Scsi_Host_Template
sil24_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
=
LIBATA_MAX_PRD
,
.
max_sectors
=
ATA_MAX_SECTORS
,
.
cmd_per_lun
=
ATA_SHT_CMD_PER_LUN
,
.
emulated
=
ATA_SHT_EMULATED
,
.
use_clustering
=
ATA_SHT_USE_CLUSTERING
,
.
proc_name
=
DRV_NAME
,
.
dma_boundary
=
ATA_DMA_BOUNDARY
,
.
slave_configure
=
ata_scsi_slave_config
,
.
bios_param
=
ata_std_bios_param
,
.
ordered_flush
=
1
,
/* NCQ not supported yet */
};
static
struct
ata_port_operations
sil24_ops
=
{
.
port_disable
=
ata_port_disable
,
.
check_status
=
sil24_check_status
,
.
check_altstatus
=
sil24_check_status
,
.
check_err
=
sil24_check_err
,
.
dev_select
=
ata_noop_dev_select
,
.
tf_read
=
sil24_tf_read
,
.
phy_reset
=
sil24_phy_reset
,
.
qc_prep
=
sil24_qc_prep
,
.
qc_issue
=
sil24_qc_issue
,
.
eng_timeout
=
sil24_eng_timeout
,
.
irq_handler
=
sil24_interrupt
,
.
irq_clear
=
sil24_irq_clear
,
.
scr_read
=
sil24_scr_read
,
.
scr_write
=
sil24_scr_write
,
.
port_start
=
sil24_port_start
,
.
port_stop
=
sil24_port_stop
,
.
host_stop
=
sil24_host_stop
,
};
/*
* Use bits 30-31 of host_flags to encode available port numbers.
* Current maxium is 4.
*/
#define SIL24_NPORTS2FLAG(nports) ((((unsigned)(nports) - 1) & 0x3) << 30)
#define SIL24_FLAG2NPORTS(flag) ((((flag) >> 30) & 0x3) + 1)
static
struct
ata_port_info
sil24_port_info
[]
=
{
/* sil_3124 */
{
.
sht
=
&
sil24_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
ATA_FLAG_PIO_DMA
|
SIL24_NPORTS2FLAG
(
4
),
.
pio_mask
=
0x1f
,
/* pio0-4 */
.
mwdma_mask
=
0x07
,
/* mwdma0-2 */
.
udma_mask
=
0x3f
,
/* udma0-5 */
.
port_ops
=
&
sil24_ops
,
},
/* sil_3132 */
{
.
sht
=
&
sil24_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
ATA_FLAG_PIO_DMA
|
SIL24_NPORTS2FLAG
(
2
),
.
pio_mask
=
0x1f
,
/* pio0-4 */
.
mwdma_mask
=
0x07
,
/* mwdma0-2 */
.
udma_mask
=
0x3f
,
/* udma0-5 */
.
port_ops
=
&
sil24_ops
,
},
/* sil_3131/sil_3531 */
{
.
sht
=
&
sil24_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
|
ATA_FLAG_PIO_DMA
|
SIL24_NPORTS2FLAG
(
1
),
.
pio_mask
=
0x1f
,
/* pio0-4 */
.
mwdma_mask
=
0x07
,
/* mwdma0-2 */
.
udma_mask
=
0x3f
,
/* udma0-5 */
.
port_ops
=
&
sil24_ops
,
},
};
static
inline
void
sil24_update_tf
(
struct
ata_port
*
ap
)
{
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
void
*
port
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
;
struct
sil24_prb
*
prb
=
port
;
ata_tf_from_fis
(
prb
->
fis
,
&
pp
->
tf
);
}
static
u8
sil24_check_status
(
struct
ata_port
*
ap
)
{
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
return
pp
->
tf
.
command
;
}
static
u8
sil24_check_err
(
struct
ata_port
*
ap
)
{
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
return
pp
->
tf
.
feature
;
}
static
int
sil24_scr_map
[]
=
{
[
SCR_CONTROL
]
=
0
,
[
SCR_STATUS
]
=
1
,
[
SCR_ERROR
]
=
2
,
[
SCR_ACTIVE
]
=
3
,
};
static
u32
sil24_scr_read
(
struct
ata_port
*
ap
,
unsigned
sc_reg
)
{
void
*
scr_addr
=
(
void
*
)
ap
->
ioaddr
.
scr_addr
;
if
(
sc_reg
<
ARRAY_SIZE
(
sil24_scr_map
))
{
void
*
addr
;
addr
=
scr_addr
+
sil24_scr_map
[
sc_reg
]
*
4
;
return
readl
(
scr_addr
+
sil24_scr_map
[
sc_reg
]
*
4
);
}
return
0xffffffffU
;
}
static
void
sil24_scr_write
(
struct
ata_port
*
ap
,
unsigned
sc_reg
,
u32
val
)
{
void
*
scr_addr
=
(
void
*
)
ap
->
ioaddr
.
scr_addr
;
if
(
sc_reg
<
ARRAY_SIZE
(
sil24_scr_map
))
{
void
*
addr
;
addr
=
scr_addr
+
sil24_scr_map
[
sc_reg
]
*
4
;
writel
(
val
,
scr_addr
+
sil24_scr_map
[
sc_reg
]
*
4
);
}
}
static
void
sil24_tf_read
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
*
tf
=
pp
->
tf
;
}
static
void
sil24_phy_reset
(
struct
ata_port
*
ap
)
{
__sata_phy_reset
(
ap
);
/*
* No ATAPI yet. Just unconditionally indicate ATA device.
* If ATAPI device is attached, it will fail ATA_CMD_ID_ATA
* and libata core will ignore the device.
*/
if
(
!
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
))
ap
->
device
[
0
].
class
=
ATA_DEV_ATA
;
}
static
inline
void
sil24_fill_sg
(
struct
ata_queued_cmd
*
qc
,
struct
sil24_cmd_block
*
cb
)
{
struct
scatterlist
*
sg
=
qc
->
sg
;
struct
sil24_sge
*
sge
=
cb
->
sge
;
unsigned
i
;
for
(
i
=
0
;
i
<
qc
->
n_elem
;
i
++
,
sg
++
,
sge
++
)
{
sge
->
addr
=
cpu_to_le64
(
sg_dma_address
(
sg
));
sge
->
cnt
=
cpu_to_le32
(
sg_dma_len
(
sg
));
sge
->
flags
=
0
;
sge
->
flags
=
i
<
qc
->
n_elem
-
1
?
0
:
cpu_to_le32
(
SGE_TRM
);
}
}
static
void
sil24_qc_prep
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
struct
sil24_cmd_block
*
cb
=
pp
->
cmd_block
+
qc
->
tag
;
struct
sil24_prb
*
prb
=
&
cb
->
prb
;
switch
(
qc
->
tf
.
protocol
)
{
case
ATA_PROT_PIO
:
case
ATA_PROT_DMA
:
case
ATA_PROT_NODATA
:
break
;
default:
/* ATAPI isn't supported yet */
BUG
();
}
ata_tf_to_fis
(
&
qc
->
tf
,
prb
->
fis
,
0
);
if
(
qc
->
flags
&
ATA_QCFLAG_DMAMAP
)
sil24_fill_sg
(
qc
,
cb
);
}
static
int
sil24_qc_issue
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
void
*
port
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
;
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
dma_addr_t
paddr
=
pp
->
cmd_block_dma
+
qc
->
tag
*
sizeof
(
*
pp
->
cmd_block
);
writel
((
u32
)
paddr
,
port
+
PORT_CMD_ACTIVATE
);
return
0
;
}
static
void
sil24_irq_clear
(
struct
ata_port
*
ap
)
{
/* unused */
}
static
int
__sil24_reset_controller
(
void
*
port
)
{
int
cnt
;
u32
tmp
;
/* Reset controller state. Is this correct? */
writel
(
PORT_CS_DEV_RST
,
port
+
PORT_CTRL_STAT
);
readl
(
port
+
PORT_CTRL_STAT
);
/* sync */
/* Max ~100ms */
for
(
cnt
=
0
;
cnt
<
1000
;
cnt
++
)
{
udelay
(
100
);
tmp
=
readl
(
port
+
PORT_CTRL_STAT
);
if
(
!
(
tmp
&
PORT_CS_DEV_RST
))
break
;
}
if
(
tmp
&
PORT_CS_DEV_RST
)
return
-
1
;
return
0
;
}
static
void
sil24_reset_controller
(
struct
ata_port
*
ap
)
{
printk
(
KERN_NOTICE
DRV_NAME
" ata%u: resetting controller...
\n
"
,
ap
->
id
);
if
(
__sil24_reset_controller
((
void
*
)
ap
->
ioaddr
.
cmd_addr
))
printk
(
KERN_ERR
DRV_NAME
" ata%u: failed to reset controller
\n
"
,
ap
->
id
);
}
static
void
sil24_eng_timeout
(
struct
ata_port
*
ap
)
{
struct
ata_queued_cmd
*
qc
;
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
!
qc
)
{
printk
(
KERN_ERR
"ata%u: BUG: tiemout without command
\n
"
,
ap
->
id
);
return
;
}
/*
* hack alert! We cannot use the supplied completion
* function from inside the ->eh_strategy_handler() thread.
* libata is the only user of ->eh_strategy_handler() in
* any kernel, so the default scsi_done() assumes it is
* not being called from the SCSI EH.
*/
printk
(
KERN_ERR
"ata%u: command timeout
\n
"
,
ap
->
id
);
qc
->
scsidone
=
scsi_finish_command
;
ata_qc_complete
(
qc
,
ATA_ERR
);
sil24_reset_controller
(
ap
);
}
static
void
sil24_error_intr
(
struct
ata_port
*
ap
,
u32
slot_stat
)
{
struct
ata_queued_cmd
*
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
void
*
port
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
;
u32
irq_stat
,
cmd_err
,
sstatus
,
serror
;
irq_stat
=
readl
(
port
+
PORT_IRQ_STAT
);
writel
(
irq_stat
,
port
+
PORT_IRQ_STAT
);
/* clear irq */
if
(
!
(
irq_stat
&
PORT_IRQ_ERROR
))
{
/* ignore non-completion, non-error irqs for now */
printk
(
KERN_WARNING
DRV_NAME
"ata%u: non-error exception irq (irq_stat %x)
\n
"
,
ap
->
id
,
irq_stat
);
return
;
}
cmd_err
=
readl
(
port
+
PORT_CMD_ERR
);
sstatus
=
readl
(
port
+
PORT_SSTATUS
);
serror
=
readl
(
port
+
PORT_SERROR
);
if
(
serror
)
writel
(
serror
,
port
+
PORT_SERROR
);
printk
(
KERN_ERR
DRV_NAME
" ata%u: error interrupt on port%d
\n
"
" stat=0x%x irq=0x%x cmd_err=%d sstatus=0x%x serror=0x%x
\n
"
,
ap
->
id
,
ap
->
port_no
,
slot_stat
,
irq_stat
,
cmd_err
,
sstatus
,
serror
);
if
(
cmd_err
==
PORT_CERR_DEV
||
cmd_err
==
PORT_CERR_SDB
)
{
/*
* Device is reporting error, tf registers are valid.
*/
sil24_update_tf
(
ap
);
}
else
{
/*
* Other errors. libata currently doesn't have any
* mechanism to report these errors. Just turn on
* ATA_ERR.
*/
pp
->
tf
.
command
=
ATA_ERR
;
}
if
(
qc
)
ata_qc_complete
(
qc
,
pp
->
tf
.
command
);
sil24_reset_controller
(
ap
);
}
static
inline
void
sil24_host_intr
(
struct
ata_port
*
ap
)
{
struct
ata_queued_cmd
*
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
void
*
port
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
;
u32
slot_stat
;
slot_stat
=
readl
(
port
+
PORT_SLOT_STAT
);
if
(
!
(
slot_stat
&
HOST_SSTAT_ATTN
))
{
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
/*
* !HOST_SSAT_ATTN guarantees successful completion,
* so reading back tf registers is unnecessary for
* most commands. TODO: read tf registers for
* commands which require these values on successful
* completion (EXECUTE DEVICE DIAGNOSTIC, CHECK POWER,
* DEVICE RESET and READ PORT MULTIPLIER (any more?).
*/
sil24_update_tf
(
ap
);
if
(
qc
)
ata_qc_complete
(
qc
,
pp
->
tf
.
command
);
}
else
sil24_error_intr
(
ap
,
slot_stat
);
}
static
irqreturn_t
sil24_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ata_host_set
*
host_set
=
dev_instance
;
struct
sil24_host_priv
*
hpriv
=
host_set
->
private_data
;
unsigned
handled
=
0
;
u32
status
;
int
i
;
status
=
readl
(
hpriv
->
host_base
+
HOST_IRQ_STAT
);
if
(
status
==
0xffffffff
)
{
printk
(
KERN_ERR
DRV_NAME
": IRQ status == 0xffffffff, "
"PCI fault or device removal?
\n
"
);
goto
out
;
}
if
(
!
(
status
&
IRQ_STAT_4PORTS
))
goto
out
;
spin_lock
(
&
host_set
->
lock
);
for
(
i
=
0
;
i
<
host_set
->
n_ports
;
i
++
)
if
(
status
&
(
1
<<
i
))
{
struct
ata_port
*
ap
=
host_set
->
ports
[
i
];
if
(
ap
&&
!
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
))
{
sil24_host_intr
(
host_set
->
ports
[
i
]);
handled
++
;
}
else
printk
(
KERN_ERR
DRV_NAME
": interrupt from disabled port %d
\n
"
,
i
);
}
spin_unlock
(
&
host_set
->
lock
);
out:
return
IRQ_RETVAL
(
handled
);
}
static
int
sil24_port_start
(
struct
ata_port
*
ap
)
{
struct
device
*
dev
=
ap
->
host_set
->
dev
;
struct
sil24_port_priv
*
pp
;
struct
sil24_cmd_block
*
cb
;
size_t
cb_size
=
sizeof
(
*
cb
);
dma_addr_t
cb_dma
;
pp
=
kmalloc
(
sizeof
(
*
pp
),
GFP_KERNEL
);
if
(
!
pp
)
return
-
ENOMEM
;
memset
(
pp
,
0
,
sizeof
(
*
pp
));
pp
->
tf
.
command
=
ATA_DRDY
;
cb
=
dma_alloc_coherent
(
dev
,
cb_size
,
&
cb_dma
,
GFP_KERNEL
);
if
(
!
cb
)
{
kfree
(
pp
);
return
-
ENOMEM
;
}
memset
(
cb
,
0
,
cb_size
);
pp
->
cmd_block
=
cb
;
pp
->
cmd_block_dma
=
cb_dma
;
ap
->
private_data
=
pp
;
return
0
;
}
static
void
sil24_port_stop
(
struct
ata_port
*
ap
)
{
struct
device
*
dev
=
ap
->
host_set
->
dev
;
struct
sil24_port_priv
*
pp
=
ap
->
private_data
;
size_t
cb_size
=
sizeof
(
*
pp
->
cmd_block
);
dma_free_coherent
(
dev
,
cb_size
,
pp
->
cmd_block
,
pp
->
cmd_block_dma
);
kfree
(
pp
);
}
static
void
sil24_host_stop
(
struct
ata_host_set
*
host_set
)
{
struct
sil24_host_priv
*
hpriv
=
host_set
->
private_data
;
iounmap
(
hpriv
->
host_base
);
iounmap
(
hpriv
->
port_base
);
kfree
(
hpriv
);
}
static
int
sil24_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
int
printed_version
=
0
;
unsigned
int
board_id
=
(
unsigned
int
)
ent
->
driver_data
;
struct
ata_port_info
*
pinfo
=
&
sil24_port_info
[
board_id
];
struct
ata_probe_ent
*
probe_ent
=
NULL
;
struct
sil24_host_priv
*
hpriv
=
NULL
;
void
*
host_base
=
NULL
,
*
port_base
=
NULL
;
int
i
,
rc
;
if
(
!
printed_version
++
)
printk
(
KERN_DEBUG
DRV_NAME
" version "
DRV_VERSION
"
\n
"
);
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
return
rc
;
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
goto
out_disable
;
rc
=
-
ENOMEM
;
/* ioremap mmio registers */
host_base
=
ioremap
(
pci_resource_start
(
pdev
,
0
),
pci_resource_len
(
pdev
,
0
));
if
(
!
host_base
)
goto
out_free
;
port_base
=
ioremap
(
pci_resource_start
(
pdev
,
2
),
pci_resource_len
(
pdev
,
2
));
if
(
!
port_base
)
goto
out_free
;
/* allocate & init probe_ent and hpriv */
probe_ent
=
kmalloc
(
sizeof
(
*
probe_ent
),
GFP_KERNEL
);
if
(
!
probe_ent
)
goto
out_free
;
hpriv
=
kmalloc
(
sizeof
(
*
hpriv
),
GFP_KERNEL
);
if
(
!
hpriv
)
goto
out_free
;
memset
(
probe_ent
,
0
,
sizeof
(
*
probe_ent
));
probe_ent
->
dev
=
pci_dev_to_dev
(
pdev
);
INIT_LIST_HEAD
(
&
probe_ent
->
node
);
probe_ent
->
sht
=
pinfo
->
sht
;
probe_ent
->
host_flags
=
pinfo
->
host_flags
;
probe_ent
->
pio_mask
=
pinfo
->
pio_mask
;
probe_ent
->
udma_mask
=
pinfo
->
udma_mask
;
probe_ent
->
port_ops
=
pinfo
->
port_ops
;
probe_ent
->
n_ports
=
SIL24_FLAG2NPORTS
(
pinfo
->
host_flags
);
probe_ent
->
irq
=
pdev
->
irq
;
probe_ent
->
irq_flags
=
SA_SHIRQ
;
probe_ent
->
mmio_base
=
port_base
;
probe_ent
->
private_data
=
hpriv
;
memset
(
hpriv
,
0
,
sizeof
(
*
hpriv
));
hpriv
->
host_base
=
host_base
;
hpriv
->
port_base
=
port_base
;
/*
* Configure the device
*/
/*
* FIXME: This device is certainly 64-bit capable. We just
* don't know how to use it. After fixing 32bit activation in
* this function, enable 64bit masks here.
*/
rc
=
pci_set_dma_mask
(
pdev
,
DMA_32BIT_MASK
);
if
(
rc
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): 32-bit DMA enable failed
\n
"
,
pci_name
(
pdev
));
goto
out_free
;
}
rc
=
pci_set_consistent_dma_mask
(
pdev
,
DMA_32BIT_MASK
);
if
(
rc
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): 32-bit consistent DMA enable failed
\n
"
,
pci_name
(
pdev
));
goto
out_free
;
}
/* GPIO off */
writel
(
0
,
host_base
+
HOST_FLASH_CMD
);
/* Mask interrupts during initialization */
writel
(
0
,
host_base
+
HOST_CTRL
);
for
(
i
=
0
;
i
<
probe_ent
->
n_ports
;
i
++
)
{
void
*
port
=
port_base
+
i
*
PORT_REGS_SIZE
;
unsigned
long
portu
=
(
unsigned
long
)
port
;
u32
tmp
;
int
cnt
;
probe_ent
->
port
[
i
].
cmd_addr
=
portu
+
PORT_PRB
;
probe_ent
->
port
[
i
].
scr_addr
=
portu
+
PORT_SCONTROL
;
ata_std_ports
(
&
probe_ent
->
port
[
i
]);
/* Initial PHY setting */
writel
(
0x20c
,
port
+
PORT_PHY_CFG
);
/* Clear port RST */
tmp
=
readl
(
port
+
PORT_CTRL_STAT
);
if
(
tmp
&
PORT_CS_PORT_RST
)
{
writel
(
PORT_CS_PORT_RST
,
port
+
PORT_CTRL_CLR
);
readl
(
port
+
PORT_CTRL_STAT
);
/* sync */
for
(
cnt
=
0
;
cnt
<
10
;
cnt
++
)
{
msleep
(
10
);
tmp
=
readl
(
port
+
PORT_CTRL_STAT
);
if
(
!
(
tmp
&
PORT_CS_PORT_RST
))
break
;
}
if
(
tmp
&
PORT_CS_PORT_RST
)
printk
(
KERN_ERR
DRV_NAME
"(%s): failed to clear port RST
\n
"
,
pci_name
(
pdev
));
}
/* Zero error counters. */
writel
(
0x8000
,
port
+
PORT_DECODE_ERR_THRESH
);
writel
(
0x8000
,
port
+
PORT_CRC_ERR_THRESH
);
writel
(
0x8000
,
port
+
PORT_HSHK_ERR_THRESH
);
writel
(
0x0000
,
port
+
PORT_DECODE_ERR_CNT
);
writel
(
0x0000
,
port
+
PORT_CRC_ERR_CNT
);
writel
(
0x0000
,
port
+
PORT_HSHK_ERR_CNT
);
/* FIXME: 32bit activation? */
writel
(
0
,
port
+
PORT_ACTIVATE_UPPER_ADDR
);
writel
(
PORT_CS_32BIT_ACTV
,
port
+
PORT_CTRL_STAT
);
/* Configure interrupts */
writel
(
0xffff
,
port
+
PORT_IRQ_ENABLE_CLR
);
writel
(
PORT_IRQ_COMPLETE
|
PORT_IRQ_ERROR
|
PORT_IRQ_SDB_FIS
,
port
+
PORT_IRQ_ENABLE_SET
);
/* Clear interrupts */
writel
(
0x0fff0fff
,
port
+
PORT_IRQ_STAT
);
writel
(
PORT_CS_IRQ_WOC
,
port
+
PORT_CTRL_CLR
);
/* Clear port multiplier enable and resume bits */
writel
(
PORT_CS_PM_EN
|
PORT_CS_RESUME
,
port
+
PORT_CTRL_CLR
);
/* Reset itself */
if
(
__sil24_reset_controller
(
port
))
printk
(
KERN_ERR
DRV_NAME
"(%s): failed to reset controller
\n
"
,
pci_name
(
pdev
));
}
/* Turn on interrupts */
writel
(
IRQ_STAT_4PORTS
,
host_base
+
HOST_CTRL
);
pci_set_master
(
pdev
);
/* FIXME: check ata_device_add return value */
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
return
0
;
out_free:
if
(
host_base
)
iounmap
(
host_base
);
if
(
port_base
)
iounmap
(
port_base
);
kfree
(
probe_ent
);
kfree
(
hpriv
);
pci_release_regions
(
pdev
);
out_disable:
pci_disable_device
(
pdev
);
return
rc
;
}
static
int
__init
sil24_init
(
void
)
{
return
pci_module_init
(
&
sil24_pci_driver
);
}
static
void
__exit
sil24_exit
(
void
)
{
pci_unregister_driver
(
&
sil24_pci_driver
);
}
MODULE_AUTHOR
(
"Tejun Heo"
);
MODULE_DESCRIPTION
(
"Silicon Image 3124/3132 SATA low-level driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DEVICE_TABLE
(
pci
,
sil24_pci_tbl
);
module_init
(
sil24_init
);
module_exit
(
sil24_exit
);
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