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
82718086
Commit
82718086
authored
Oct 18, 2004
by
Linus Torvalds
Browse files
Options
Browse Files
Download
Plain Diff
Merge
bk://gkernel.bkbits.net/libata-2.6
into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents
dd582fa6
a034f8d6
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
1217 additions
and
43 deletions
+1217
-43
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+8
-0
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-0
drivers/scsi/ahci.c
drivers/scsi/ahci.c
+1023
-0
drivers/scsi/libata-core.c
drivers/scsi/libata-core.c
+163
-41
drivers/scsi/libata-scsi.c
drivers/scsi/libata-scsi.c
+10
-2
drivers/scsi/sata_vsc.c
drivers/scsi/sata_vsc.c
+8
-0
include/linux/libata.h
include/linux/libata.h
+4
-0
No files found.
drivers/scsi/Kconfig
View file @
82718086
...
@@ -406,6 +406,14 @@ config SCSI_SATA
...
@@ -406,6 +406,14 @@ config SCSI_SATA
If unsure, say N.
If unsure, say N.
config SCSI_SATA_AHCI
tristate "AHCI SATA support"
depends on SCSI_SATA && PCI && EXPERIMENTAL
help
This option enables support for AHCI Serial ATA.
If unsure, say N.
config SCSI_SATA_SVW
config SCSI_SATA_SVW
tristate "ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)"
tristate "ServerWorks Frodo / Apple K2 SATA support (EXPERIMENTAL)"
depends on SCSI_SATA && PCI && EXPERIMENTAL
depends on SCSI_SATA && PCI && EXPERIMENTAL
...
...
drivers/scsi/Makefile
View file @
82718086
...
@@ -121,6 +121,7 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
...
@@ -121,6 +121,7 @@ obj-$(CONFIG_SCSI_LASI700) += 53c700.o lasi700.o
obj-$(CONFIG_SCSI_NSP32)
+=
nsp32.o
obj-$(CONFIG_SCSI_NSP32)
+=
nsp32.o
obj-$(CONFIG_SCSI_IPR)
+=
ipr.o
obj-$(CONFIG_SCSI_IPR)
+=
ipr.o
obj-$(CONFIG_SCSI_IBMVSCSI)
+=
ibmvscsi/
obj-$(CONFIG_SCSI_IBMVSCSI)
+=
ibmvscsi/
obj-$(CONFIG_SCSI_SATA_AHCI)
+=
libata.o ahci.o
obj-$(CONFIG_SCSI_SATA_SVW)
+=
libata.o sata_svw.o
obj-$(CONFIG_SCSI_SATA_SVW)
+=
libata.o sata_svw.o
obj-$(CONFIG_SCSI_ATA_PIIX)
+=
libata.o ata_piix.o
obj-$(CONFIG_SCSI_ATA_PIIX)
+=
libata.o ata_piix.o
obj-$(CONFIG_SCSI_SATA_PROMISE)
+=
libata.o sata_promise.o
obj-$(CONFIG_SCSI_SATA_PROMISE)
+=
libata.o sata_promise.o
...
...
drivers/scsi/ahci.c
0 → 100644
View file @
82718086
/*
* ahci.c - AHCI SATA support
*
* Copyright 2004 Red Hat, Inc.
*
* The contents of this file are subject to the Open
* Software License version 1.1 that can be found at
* http://www.opensource.org/licenses/osl-1.1.txt and is included herein
* by reference.
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License version 2 (the "GPL") as distributed
* in the kernel source COPYING file, in which case the provisions of
* the GPL are applicable instead of the above. If you wish to allow
* the use of your version of this file only under the terms of the
* GPL and not to allow others to use your version of this file under
* the OSL, indicate your decision by deleting the provisions above and
* replace them with the notice and other provisions required by the GPL.
* If you do not delete the provisions above, a recipient may use your
* version of this file under either the OSL or the GPL.
*
* Version 1.0 of the AHCI specification:
* http://www.intel.com/technology/serialata/pdf/rev1_0.pdf
*
*/
#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 "scsi.h"
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <asm/io.h>
#define DRV_NAME "ahci"
#define DRV_VERSION "0.11"
enum
{
AHCI_PCI_BAR
=
5
,
AHCI_MAX_SG
=
168
,
/* hardware max is 64K */
AHCI_DMA_BOUNDARY
=
0xffffffff
,
AHCI_USE_CLUSTERING
=
0
,
AHCI_CMD_SLOT_SZ
=
32
*
32
,
AHCI_RX_FIS_SZ
=
256
,
AHCI_CMD_TBL_HDR
=
0x80
,
AHCI_CMD_TBL_SZ
=
AHCI_CMD_TBL_HDR
+
(
AHCI_MAX_SG
*
16
),
AHCI_PORT_PRIV_DMA_SZ
=
AHCI_CMD_SLOT_SZ
+
AHCI_CMD_TBL_SZ
+
AHCI_RX_FIS_SZ
,
AHCI_IRQ_ON_SG
=
(
1
<<
31
),
AHCI_CMD_ATAPI
=
(
1
<<
5
),
AHCI_CMD_WRITE
=
(
1
<<
6
),
RX_FIS_D2H_REG
=
0x40
,
/* offset of D2H Register FIS data */
board_ahci
=
0
,
/* global controller registers */
HOST_CAP
=
0x00
,
/* host capabilities */
HOST_CTL
=
0x04
,
/* global host control */
HOST_IRQ_STAT
=
0x08
,
/* interrupt status */
HOST_PORTS_IMPL
=
0x0c
,
/* bitmap of implemented ports */
HOST_VERSION
=
0x10
,
/* AHCI spec. version compliancy */
/* HOST_CTL bits */
HOST_RESET
=
(
1
<<
0
),
/* reset controller; self-clear */
HOST_IRQ_EN
=
(
1
<<
1
),
/* global IRQ enable */
HOST_AHCI_EN
=
(
1
<<
31
),
/* AHCI enabled */
/* HOST_CAP bits */
HOST_CAP_64
=
(
1
<<
31
),
/* PCI DAC (64-bit DMA) support */
/* registers for each SATA port */
PORT_LST_ADDR
=
0x00
,
/* command list DMA addr */
PORT_LST_ADDR_HI
=
0x04
,
/* command list DMA addr hi */
PORT_FIS_ADDR
=
0x08
,
/* FIS rx buf addr */
PORT_FIS_ADDR_HI
=
0x0c
,
/* FIS rx buf addr hi */
PORT_IRQ_STAT
=
0x10
,
/* interrupt status */
PORT_IRQ_MASK
=
0x14
,
/* interrupt enable/disable mask */
PORT_CMD
=
0x18
,
/* port command */
PORT_TFDATA
=
0x20
,
/* taskfile data */
PORT_SIG
=
0x24
,
/* device TF signature */
PORT_CMD_ISSUE
=
0x38
,
/* command issue */
PORT_SCR
=
0x28
,
/* SATA phy register block */
PORT_SCR_STAT
=
0x28
,
/* SATA phy register: SStatus */
PORT_SCR_CTL
=
0x2c
,
/* SATA phy register: SControl */
PORT_SCR_ERR
=
0x30
,
/* SATA phy register: SError */
/* PORT_IRQ_{STAT,MASK} bits */
PORT_IRQ_COLD_PRES
=
(
1
<<
31
),
/* cold presence detect */
PORT_IRQ_TF_ERR
=
(
1
<<
30
),
/* task file error */
PORT_IRQ_HBUS_ERR
=
(
1
<<
29
),
/* host bus fatal error */
PORT_IRQ_HBUS_DATA_ERR
=
(
1
<<
28
),
/* host bus data error */
PORT_IRQ_IF_ERR
=
(
1
<<
27
),
/* interface fatal error */
PORT_IRQ_IF_NONFATAL
=
(
1
<<
26
),
/* interface non-fatal error */
PORT_IRQ_OVERFLOW
=
(
1
<<
24
),
/* xfer exhausted available S/G */
PORT_IRQ_BAD_PMP
=
(
1
<<
23
),
/* incorrect port multiplier */
PORT_IRQ_PHYRDY
=
(
1
<<
22
),
/* PhyRdy changed */
PORT_IRQ_DEV_ILCK
=
(
1
<<
7
),
/* device interlock */
PORT_IRQ_CONNECT
=
(
1
<<
6
),
/* port connect change status */
PORT_IRQ_SG_DONE
=
(
1
<<
5
),
/* descriptor processed */
PORT_IRQ_UNK_FIS
=
(
1
<<
4
),
/* unknown FIS rx'd */
PORT_IRQ_SDB_FIS
=
(
1
<<
3
),
/* Set Device Bits FIS rx'd */
PORT_IRQ_DMAS_FIS
=
(
1
<<
2
),
/* DMA Setup FIS rx'd */
PORT_IRQ_PIOS_FIS
=
(
1
<<
1
),
/* PIO Setup FIS rx'd */
PORT_IRQ_D2H_REG_FIS
=
(
1
<<
0
),
/* D2H Register FIS rx'd */
PORT_IRQ_FATAL
=
PORT_IRQ_TF_ERR
|
PORT_IRQ_HBUS_ERR
|
PORT_IRQ_HBUS_DATA_ERR
|
PORT_IRQ_IF_ERR
,
DEF_PORT_IRQ
=
PORT_IRQ_FATAL
|
PORT_IRQ_PHYRDY
|
PORT_IRQ_D2H_REG_FIS
,
/* PORT_CMD bits */
PORT_CMD_LIST_ON
=
(
1
<<
15
),
/* cmd list DMA engine running */
PORT_CMD_FIS_ON
=
(
1
<<
14
),
/* FIS DMA engine running */
PORT_CMD_FIS_RX
=
(
1
<<
4
),
/* Enable FIS receive DMA engine */
PORT_CMD_POWER_ON
=
(
1
<<
2
),
/* Power up device */
PORT_CMD_SPIN_UP
=
(
1
<<
1
),
/* Spin up device */
PORT_CMD_START
=
(
1
<<
0
),
/* Enable port DMA engine */
PORT_CMD_ICC_ACTIVE
=
(
0x1
<<
28
),
/* Put i/f in active state */
PORT_CMD_ICC_PARTIAL
=
(
0x2
<<
28
),
/* Put i/f in partial state */
PORT_CMD_ICC_SLUMBER
=
(
0x6
<<
28
),
/* Put i/f in slumber state */
};
struct
ahci_cmd_hdr
{
u32
opts
;
u32
status
;
u32
tbl_addr
;
u32
tbl_addr_hi
;
u32
reserved
[
4
];
};
struct
ahci_sg
{
u32
addr
;
u32
addr_hi
;
u32
reserved
;
u32
flags_size
;
};
struct
ahci_host_priv
{
unsigned
long
flags
;
u32
cap
;
/* cache of HOST_CAP register */
u32
port_map
;
/* cache of HOST_PORTS_IMPL reg */
};
struct
ahci_port_priv
{
struct
ahci_cmd_hdr
*
cmd_slot
;
dma_addr_t
cmd_slot_dma
;
void
*
cmd_tbl
;
dma_addr_t
cmd_tbl_dma
;
struct
ahci_sg
*
cmd_tbl_sg
;
void
*
rx_fis
;
dma_addr_t
rx_fis_dma
;
};
static
u32
ahci_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
);
static
void
ahci_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
,
u32
val
);
static
int
ahci_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
);
static
int
ahci_qc_issue
(
struct
ata_queued_cmd
*
qc
);
static
irqreturn_t
ahci_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
);
static
void
ahci_phy_reset
(
struct
ata_port
*
ap
);
static
void
ahci_irq_clear
(
struct
ata_port
*
ap
);
static
void
ahci_eng_timeout
(
struct
ata_port
*
ap
);
static
int
ahci_port_start
(
struct
ata_port
*
ap
);
static
void
ahci_port_stop
(
struct
ata_port
*
ap
);
static
void
ahci_host_stop
(
struct
ata_host_set
*
host_set
);
static
void
ahci_qc_prep
(
struct
ata_queued_cmd
*
qc
);
static
u8
ahci_check_status
(
struct
ata_port
*
ap
);
static
inline
int
ahci_host_intr
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
);
static
Scsi_Host_Template
ahci_sht
=
{
.
module
=
THIS_MODULE
,
.
name
=
DRV_NAME
,
.
queuecommand
=
ata_scsi_queuecmd
,
.
eh_strategy_handler
=
ata_scsi_error
,
.
can_queue
=
ATA_DEF_QUEUE
,
.
this_id
=
ATA_SHT_THIS_ID
,
.
sg_tablesize
=
AHCI_MAX_SG
,
.
max_sectors
=
ATA_MAX_SECTORS
,
.
cmd_per_lun
=
ATA_SHT_CMD_PER_LUN
,
.
emulated
=
ATA_SHT_EMULATED
,
.
use_clustering
=
AHCI_USE_CLUSTERING
,
.
proc_name
=
DRV_NAME
,
.
dma_boundary
=
AHCI_DMA_BOUNDARY
,
.
slave_configure
=
ata_scsi_slave_config
,
.
bios_param
=
ata_std_bios_param
,
};
static
struct
ata_port_operations
ahci_ops
=
{
.
port_disable
=
ata_port_disable
,
.
check_status
=
ahci_check_status
,
.
dev_select
=
ata_noop_dev_select
,
.
phy_reset
=
ahci_phy_reset
,
.
qc_prep
=
ahci_qc_prep
,
.
qc_issue
=
ahci_qc_issue
,
.
eng_timeout
=
ahci_eng_timeout
,
.
irq_handler
=
ahci_interrupt
,
.
irq_clear
=
ahci_irq_clear
,
.
scr_read
=
ahci_scr_read
,
.
scr_write
=
ahci_scr_write
,
.
port_start
=
ahci_port_start
,
.
port_stop
=
ahci_port_stop
,
.
host_stop
=
ahci_host_stop
,
};
static
struct
ata_port_info
ahci_port_info
[]
=
{
/* board_ahci */
{
.
sht
=
&
ahci_sht
,
.
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_SATA_RESET
|
ATA_FLAG_MMIO
,
.
pio_mask
=
0x03
,
/* pio3-4 */
.
udma_mask
=
0x7f
,
/* udma0-6 ; FIXME */
.
port_ops
=
&
ahci_ops
,
},
};
static
struct
pci_device_id
ahci_pci_tbl
[]
=
{
{
PCI_VENDOR_ID_INTEL
,
0x2652
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_ahci
},
{
PCI_VENDOR_ID_INTEL
,
0x2653
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
board_ahci
},
{
}
/* terminate list */
};
static
struct
pci_driver
ahci_pci_driver
=
{
.
name
=
DRV_NAME
,
.
id_table
=
ahci_pci_tbl
,
.
probe
=
ahci_init_one
,
.
remove
=
ata_pci_remove_one
,
};
static
inline
unsigned
long
ahci_port_base_ul
(
unsigned
long
base
,
unsigned
int
port
)
{
return
base
+
0x100
+
(
port
*
0x80
);
}
static
inline
void
*
ahci_port_base
(
void
*
base
,
unsigned
int
port
)
{
return
(
void
*
)
ahci_port_base_ul
((
unsigned
long
)
base
,
port
);
}
static
void
ahci_host_stop
(
struct
ata_host_set
*
host_set
)
{
struct
ahci_host_priv
*
hpriv
=
host_set
->
private_data
;
kfree
(
hpriv
);
}
static
int
ahci_port_start
(
struct
ata_port
*
ap
)
{
struct
pci_dev
*
pdev
=
ap
->
host_set
->
pdev
;
struct
ahci_host_priv
*
hpriv
=
ap
->
host_set
->
private_data
;
struct
ahci_port_priv
*
pp
;
int
rc
;
void
*
mem
,
*
mmio
=
ap
->
host_set
->
mmio_base
;
void
*
port_mmio
=
ahci_port_base
(
mmio
,
ap
->
port_no
);
dma_addr_t
mem_dma
;
rc
=
ata_port_start
(
ap
);
if
(
rc
)
return
rc
;
pp
=
kmalloc
(
sizeof
(
*
pp
),
GFP_KERNEL
);
if
(
!
pp
)
{
rc
=
-
ENOMEM
;
goto
err_out
;
}
memset
(
pp
,
0
,
sizeof
(
*
pp
));
mem
=
pci_alloc_consistent
(
pdev
,
AHCI_PORT_PRIV_DMA_SZ
,
&
mem_dma
);
if
(
!
mem
)
{
rc
=
-
ENOMEM
;
goto
err_out_kfree
;
}
memset
(
mem
,
0
,
AHCI_PORT_PRIV_DMA_SZ
);
/*
* First item in chunk of DMA memory: 32-slot command table,
* 32 bytes each in size
*/
pp
->
cmd_slot
=
mem
;
pp
->
cmd_slot_dma
=
mem_dma
;
mem
+=
AHCI_CMD_SLOT_SZ
;
mem_dma
+=
AHCI_CMD_SLOT_SZ
;
/*
* Second item: Received-FIS area
*/
pp
->
rx_fis
=
mem
;
pp
->
rx_fis_dma
=
mem_dma
;
mem
+=
AHCI_RX_FIS_SZ
;
mem_dma
+=
AHCI_RX_FIS_SZ
;
/*
* Third item: data area for storing a single command
* and its scatter-gather table
*/
pp
->
cmd_tbl
=
mem
;
pp
->
cmd_tbl_dma
=
mem_dma
;
pp
->
cmd_tbl_sg
=
mem
+
AHCI_CMD_TBL_HDR
;
ap
->
private_data
=
pp
;
if
(
hpriv
->
cap
&
HOST_CAP_64
)
writel
((
pp
->
cmd_slot_dma
>>
16
)
>>
16
,
port_mmio
+
PORT_LST_ADDR_HI
);
writel
(
pp
->
cmd_slot_dma
&
0xffffffff
,
port_mmio
+
PORT_LST_ADDR
);
readl
(
port_mmio
+
PORT_LST_ADDR
);
/* flush */
if
(
hpriv
->
cap
&
HOST_CAP_64
)
writel
((
pp
->
rx_fis_dma
>>
16
)
>>
16
,
port_mmio
+
PORT_FIS_ADDR_HI
);
writel
(
pp
->
rx_fis_dma
&
0xffffffff
,
port_mmio
+
PORT_LST_ADDR
);
readl
(
port_mmio
+
PORT_LST_ADDR
);
/* flush */
writel
(
PORT_CMD_ICC_ACTIVE
|
PORT_CMD_FIS_RX
|
PORT_CMD_POWER_ON
|
PORT_CMD_SPIN_UP
|
PORT_CMD_START
,
port_mmio
+
PORT_CMD
);
readl
(
port_mmio
+
PORT_CMD
);
/* flush */
return
0
;
err_out_kfree:
kfree
(
pp
);
err_out:
ata_port_stop
(
ap
);
return
rc
;
}
static
void
ahci_port_stop
(
struct
ata_port
*
ap
)
{
struct
pci_dev
*
pdev
=
ap
->
host_set
->
pdev
;
struct
ahci_port_priv
*
pp
=
ap
->
private_data
;
void
*
mmio
=
ap
->
host_set
->
mmio_base
;
void
*
port_mmio
=
ahci_port_base
(
mmio
,
ap
->
port_no
);
u32
tmp
;
tmp
=
readl
(
port_mmio
+
PORT_CMD
);
tmp
&=
~
(
PORT_CMD_START
|
PORT_CMD_FIS_RX
);
writel
(
tmp
,
port_mmio
+
PORT_CMD
);
readl
(
port_mmio
+
PORT_CMD
);
/* flush */
/* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so
* this is slightly incorrect.
*/
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
((
HZ
/
2
)
+
1
);
ap
->
private_data
=
NULL
;
pci_free_consistent
(
pdev
,
AHCI_PORT_PRIV_DMA_SZ
,
pp
->
cmd_slot
,
pp
->
cmd_slot_dma
);
kfree
(
pp
);
ata_port_stop
(
ap
);
}
static
u32
ahci_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg_in
)
{
unsigned
int
sc_reg
;
switch
(
sc_reg_in
)
{
case
SCR_STATUS
:
sc_reg
=
0
;
break
;
case
SCR_CONTROL
:
sc_reg
=
1
;
break
;
case
SCR_ERROR
:
sc_reg
=
2
;
break
;
case
SCR_ACTIVE
:
sc_reg
=
3
;
break
;
default:
return
0xffffffffU
;
}
return
readl
((
void
*
)
ap
->
ioaddr
.
scr_addr
+
(
sc_reg
*
4
));
}
static
void
ahci_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg_in
,
u32
val
)
{
unsigned
int
sc_reg
;
switch
(
sc_reg_in
)
{
case
SCR_STATUS
:
sc_reg
=
0
;
break
;
case
SCR_CONTROL
:
sc_reg
=
1
;
break
;
case
SCR_ERROR
:
sc_reg
=
2
;
break
;
case
SCR_ACTIVE
:
sc_reg
=
3
;
break
;
default:
return
;
}
writel
(
val
,
(
void
*
)
ap
->
ioaddr
.
scr_addr
+
(
sc_reg
*
4
));
}
static
void
ahci_phy_reset
(
struct
ata_port
*
ap
)
{
void
__iomem
*
port_mmio
=
(
void
__iomem
*
)
ap
->
ioaddr
.
cmd_addr
;
struct
ata_taskfile
tf
;
struct
ata_device
*
dev
=
&
ap
->
device
[
0
];
u32
tmp
;
__sata_phy_reset
(
ap
);
if
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
)
return
;
tmp
=
readl
(
port_mmio
+
PORT_SIG
);
tf
.
lbah
=
(
tmp
>>
24
)
&
0xff
;
tf
.
lbam
=
(
tmp
>>
16
)
&
0xff
;
tf
.
lbal
=
(
tmp
>>
8
)
&
0xff
;
tf
.
nsect
=
(
tmp
)
&
0xff
;
dev
->
class
=
ata_dev_classify
(
&
tf
);
if
(
!
ata_dev_present
(
dev
))
ata_port_disable
(
ap
);
}
static
u8
ahci_check_status
(
struct
ata_port
*
ap
)
{
void
*
mmio
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
;
return
readl
(
mmio
+
PORT_TFDATA
)
&
0xFF
;
}
static
void
ahci_fill_sg
(
struct
ata_queued_cmd
*
qc
)
{
struct
ahci_port_priv
*
pp
=
qc
->
ap
->
private_data
;
unsigned
int
i
;
VPRINTK
(
"ENTER
\n
"
);
/*
* Next, the S/G list.
*/
for
(
i
=
0
;
i
<
qc
->
n_elem
;
i
++
)
{
u32
sg_len
;
dma_addr_t
addr
;
addr
=
sg_dma_address
(
&
qc
->
sg
[
i
]);
sg_len
=
sg_dma_len
(
&
qc
->
sg
[
i
]);
pp
->
cmd_tbl_sg
[
i
].
addr
=
cpu_to_le32
(
addr
&
0xffffffff
);
pp
->
cmd_tbl_sg
[
i
].
addr_hi
=
cpu_to_le32
((
addr
>>
16
)
>>
16
);
pp
->
cmd_tbl_sg
[
i
].
flags_size
=
cpu_to_le32
(
sg_len
-
1
);
}
}
static
void
ahci_qc_prep
(
struct
ata_queued_cmd
*
qc
)
{
struct
ahci_port_priv
*
pp
=
qc
->
ap
->
private_data
;
u32
opts
;
const
u32
cmd_fis_len
=
5
;
/* five dwords */
/*
* Fill in command slot information (currently only one slot,
* slot 0, is currently since we don't do queueing)
*/
opts
=
(
qc
->
n_elem
<<
16
)
|
cmd_fis_len
;
if
(
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
)
opts
|=
AHCI_CMD_WRITE
;
switch
(
qc
->
tf
.
protocol
)
{
case
ATA_PROT_ATAPI
:
case
ATA_PROT_ATAPI_NODATA
:
case
ATA_PROT_ATAPI_DMA
:
opts
|=
AHCI_CMD_ATAPI
;
break
;
default:
/* do nothing */
break
;
}
pp
->
cmd_slot
[
0
].
opts
=
cpu_to_le32
(
opts
);
pp
->
cmd_slot
[
0
].
status
=
0
;
pp
->
cmd_slot
[
0
].
tbl_addr
=
cpu_to_le32
(
pp
->
cmd_tbl_dma
&
0xffffffff
);
pp
->
cmd_slot
[
0
].
tbl_addr_hi
=
cpu_to_le32
((
pp
->
cmd_tbl_dma
>>
16
)
>>
16
);
/*
* Fill in command table information. First, the header,
* a SATA Register - Host to Device command FIS.
*/
ata_tf_to_fis
(
&
qc
->
tf
,
pp
->
cmd_tbl
,
0
);
if
(
!
(
qc
->
flags
&
ATA_QCFLAG_DMAMAP
))
return
;
ahci_fill_sg
(
qc
);
}
static
inline
void
ahci_dma_complete
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
,
int
have_err
)
{
/* get drive status; clear intr; complete txn */
ata_qc_complete
(
ata_qc_from_tag
(
ap
,
ap
->
active_tag
),
have_err
?
ATA_ERR
:
0
);
}
static
void
ahci_intr_error
(
struct
ata_port
*
ap
,
u32
irq_stat
)
{
void
*
mmio
=
ap
->
host_set
->
mmio_base
;
void
*
port_mmio
=
ahci_port_base
(
mmio
,
ap
->
port_no
);
u32
tmp
;
int
work
;
/* stop DMA */
tmp
=
readl
(
port_mmio
+
PORT_CMD
);
tmp
&=
PORT_CMD_START
|
PORT_CMD_FIS_RX
;
writel
(
tmp
,
port_mmio
+
PORT_CMD
);
/* wait for engine to stop. TODO: this could be
* as long as 500 msec
*/
work
=
1000
;
while
(
work
--
>
0
)
{
tmp
=
readl
(
port_mmio
+
PORT_CMD
);
if
((
tmp
&
PORT_CMD_LIST_ON
)
==
0
)
break
;
udelay
(
10
);
}
/* clear SATA phy error, if any */
tmp
=
readl
(
port_mmio
+
PORT_SCR_ERR
);
writel
(
tmp
,
port_mmio
+
PORT_SCR_ERR
);
/* if DRQ/BSY is set, device needs to be reset.
* if so, issue COMRESET
*/
tmp
=
readl
(
port_mmio
+
PORT_TFDATA
);
if
(
tmp
&
(
ATA_BUSY
|
ATA_DRQ
))
{
writel
(
0x301
,
port_mmio
+
PORT_SCR_CTL
);
readl
(
port_mmio
+
PORT_SCR_CTL
);
/* flush */
udelay
(
10
);
writel
(
0x300
,
port_mmio
+
PORT_SCR_CTL
);
readl
(
port_mmio
+
PORT_SCR_CTL
);
/* flush */
}
/* re-start DMA */
tmp
=
readl
(
port_mmio
+
PORT_CMD
);
tmp
|=
PORT_CMD_START
|
PORT_CMD_FIS_RX
;
writel
(
tmp
,
port_mmio
+
PORT_CMD
);
readl
(
port_mmio
+
PORT_CMD
);
/* flush */
printk
(
KERN_WARNING
"ata%u: error occurred, port reset
\n
"
,
ap
->
port_no
);
}
static
void
ahci_eng_timeout
(
struct
ata_port
*
ap
)
{
void
*
mmio
=
ap
->
host_set
->
mmio_base
;
void
*
port_mmio
=
ahci_port_base
(
mmio
,
ap
->
port_no
);
struct
ata_queued_cmd
*
qc
;
DPRINTK
(
"ENTER
\n
"
);
ahci_intr_error
(
ap
,
readl
(
port_mmio
+
PORT_IRQ_STAT
));
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
!
qc
)
{
printk
(
KERN_ERR
"ata%u: BUG: timeout without command
\n
"
,
ap
->
id
);
}
else
{
/* 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.
*/
qc
->
scsidone
=
scsi_finish_command
;
ata_qc_complete
(
qc
,
ATA_ERR
);
}
}
static
inline
int
ahci_host_intr
(
struct
ata_port
*
ap
,
struct
ata_queued_cmd
*
qc
)
{
void
*
mmio
=
ap
->
host_set
->
mmio_base
;
void
*
port_mmio
=
ahci_port_base
(
mmio
,
ap
->
port_no
);
u32
status
,
serr
,
ci
;
serr
=
readl
(
port_mmio
+
PORT_SCR_ERR
);
writel
(
serr
,
port_mmio
+
PORT_SCR_ERR
);
status
=
readl
(
port_mmio
+
PORT_IRQ_STAT
);
writel
(
status
,
port_mmio
+
PORT_IRQ_STAT
);
ci
=
readl
(
port_mmio
+
PORT_CMD_ISSUE
);
if
(
likely
((
ci
&
0x1
)
==
0
))
{
if
(
qc
)
{
ata_qc_complete
(
qc
,
0
);
qc
=
NULL
;
}
}
if
(
status
&
PORT_IRQ_FATAL
)
{
ahci_intr_error
(
ap
,
status
);
if
(
qc
)
ata_qc_complete
(
qc
,
ATA_ERR
);
}
return
1
;
}
static
void
ahci_irq_clear
(
struct
ata_port
*
ap
)
{
/* TODO */
}
static
irqreturn_t
ahci_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ata_host_set
*
host_set
=
dev_instance
;
struct
ahci_host_priv
*
hpriv
;
unsigned
int
i
,
handled
=
0
;
void
*
mmio
;
u32
irq_stat
,
irq_ack
=
0
;
VPRINTK
(
"ENTER
\n
"
);
hpriv
=
host_set
->
private_data
;
mmio
=
host_set
->
mmio_base
;
/* sigh. 0xffffffff is a valid return from h/w */
irq_stat
=
readl
(
mmio
+
HOST_IRQ_STAT
);
irq_stat
&=
hpriv
->
port_map
;
if
(
!
irq_stat
)
return
IRQ_NONE
;
spin_lock
(
&
host_set
->
lock
);
for
(
i
=
0
;
i
<
host_set
->
n_ports
;
i
++
)
{
struct
ata_port
*
ap
;
u32
tmp
;
VPRINTK
(
"port %u
\n
"
,
i
);
ap
=
host_set
->
ports
[
i
];
tmp
=
irq_stat
&
(
1
<<
i
);
if
(
tmp
&&
ap
)
{
struct
ata_queued_cmd
*
qc
;
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
ahci_host_intr
(
ap
,
qc
))
irq_ack
|=
(
1
<<
i
);
}
}
if
(
irq_ack
)
{
writel
(
irq_ack
,
mmio
+
HOST_IRQ_STAT
);
handled
=
1
;
}
spin_unlock
(
&
host_set
->
lock
);
VPRINTK
(
"EXIT
\n
"
);
return
IRQ_RETVAL
(
handled
);
}
static
int
ahci_qc_issue
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
void
*
mmio
=
(
void
*
)
ap
->
ioaddr
.
cmd_addr
;
writel
(
1
,
mmio
+
PORT_CMD_ISSUE
);
readl
(
mmio
+
PORT_CMD_ISSUE
);
/* flush */
return
0
;
}
static
void
ahci_setup_port
(
struct
ata_ioports
*
port
,
unsigned
long
base
,
unsigned
int
port_idx
)
{
VPRINTK
(
"ENTER, base==0x%lx, port_idx %u
\n
"
,
base
,
port_idx
);
base
=
ahci_port_base_ul
(
base
,
port_idx
);
VPRINTK
(
"base now==0x%lx
\n
"
,
base
);
port
->
cmd_addr
=
base
;
port
->
scr_addr
=
base
+
PORT_SCR
;
VPRINTK
(
"EXIT
\n
"
);
}
static
int
ahci_host_init
(
struct
ata_probe_ent
*
probe_ent
)
{
struct
ahci_host_priv
*
hpriv
=
probe_ent
->
private_data
;
struct
pci_dev
*
pdev
=
probe_ent
->
pdev
;
void
__iomem
*
mmio
=
probe_ent
->
mmio_base
;
u32
tmp
,
cap_save
;
u16
tmp16
;
unsigned
int
i
,
j
,
using_dac
;
int
rc
;
void
__iomem
*
port_mmio
;
cap_save
=
readl
(
mmio
+
HOST_CAP
);
cap_save
&=
(
(
1
<<
28
)
|
(
1
<<
17
)
);
cap_save
|=
(
1
<<
27
);
/* global controller reset */
tmp
=
readl
(
mmio
+
HOST_CTL
);
if
((
tmp
&
HOST_RESET
)
==
0
)
{
writel
(
tmp
|
HOST_RESET
,
mmio
+
HOST_CTL
);
readl
(
mmio
+
HOST_CTL
);
/* flush */
}
/* reset must complete within 1 second, or
* the hardware should be considered fried.
*/
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
(
HZ
+
1
);
tmp
=
readl
(
mmio
+
HOST_CTL
);
if
(
tmp
&
HOST_RESET
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): controller reset failed (0x%x)
\n
"
,
pci_name
(
pdev
),
tmp
);
return
-
EIO
;
}
writel
(
HOST_AHCI_EN
,
mmio
+
HOST_CTL
);
(
void
)
readl
(
mmio
+
HOST_CTL
);
/* flush */
writel
(
cap_save
,
mmio
+
HOST_CAP
);
writel
(
0xf
,
mmio
+
HOST_PORTS_IMPL
);
(
void
)
readl
(
mmio
+
HOST_PORTS_IMPL
);
/* flush */
pci_read_config_word
(
pdev
,
0x92
,
&
tmp16
);
tmp16
|=
0xf
;
pci_write_config_word
(
pdev
,
0x92
,
tmp16
);
hpriv
->
cap
=
readl
(
mmio
+
HOST_CAP
);
hpriv
->
port_map
=
readl
(
mmio
+
HOST_PORTS_IMPL
);
probe_ent
->
n_ports
=
(
hpriv
->
cap
&
0x1f
)
+
1
;
VPRINTK
(
"cap 0x%x port_map 0x%x n_ports %d
\n
"
,
hpriv
->
cap
,
hpriv
->
port_map
,
probe_ent
->
n_ports
);
using_dac
=
hpriv
->
cap
&
HOST_CAP_64
;
if
(
using_dac
&&
!
pci_set_dma_mask
(
pdev
,
0xffffffffffffffffULL
))
{
rc
=
pci_set_consistent_dma_mask
(
pdev
,
0xffffffffffffffffULL
);
if
(
rc
)
{
rc
=
pci_set_consistent_dma_mask
(
pdev
,
0xffffffffULL
);
if
(
rc
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): 64-bit DMA enable failed
\n
"
,
pci_name
(
pdev
));
return
rc
;
}
}
hpriv
->
flags
|=
HOST_CAP_64
;
}
else
{
rc
=
pci_set_dma_mask
(
pdev
,
0xffffffffULL
);
if
(
rc
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): 32-bit DMA enable failed
\n
"
,
pci_name
(
pdev
));
return
rc
;
}
rc
=
pci_set_consistent_dma_mask
(
pdev
,
0xffffffffULL
);
if
(
rc
)
{
printk
(
KERN_ERR
DRV_NAME
"(%s): 32-bit consistent DMA enable failed
\n
"
,
pci_name
(
pdev
));
return
rc
;
}
}
for
(
i
=
0
;
i
<
probe_ent
->
n_ports
;
i
++
)
{
if
(
!
(
hpriv
->
port_map
&
(
1
<<
i
)))
continue
;
port_mmio
=
ahci_port_base
(
mmio
,
i
);
VPRINTK
(
"mmio %p port_mmio %p
\n
"
,
mmio
,
port_mmio
);
ahci_setup_port
(
&
probe_ent
->
port
[
i
],
(
unsigned
long
)
mmio
,
i
);
/* make sure port is not active */
tmp
=
readl
(
port_mmio
+
PORT_CMD
);
VPRINTK
(
"PORT_CMD 0x%x
\n
"
,
tmp
);
if
(
tmp
&
(
PORT_CMD_LIST_ON
|
PORT_CMD_FIS_ON
|
PORT_CMD_FIS_RX
|
PORT_CMD_START
))
{
tmp
&=
~
(
PORT_CMD_LIST_ON
|
PORT_CMD_FIS_ON
|
PORT_CMD_FIS_RX
|
PORT_CMD_START
);
writel
(
tmp
,
port_mmio
+
PORT_CMD
);
readl
(
port_mmio
+
PORT_CMD
);
/* flush */
/* spec says 500 msecs for each bit, so
* this is slightly incorrect.
*/
set_current_state
(
TASK_UNINTERRUPTIBLE
);
schedule_timeout
((
HZ
/
2
)
+
1
);
}
writel
(
PORT_CMD_SPIN_UP
,
port_mmio
+
PORT_CMD
);
j
=
0
;
while
(
j
<
100
)
{
msleep
(
10
);
tmp
=
readl
(
port_mmio
+
PORT_SCR_STAT
);
if
((
tmp
&
0xf
)
==
0x3
)
break
;
j
++
;
}
tmp
=
readl
(
port_mmio
+
PORT_SCR_ERR
);
VPRINTK
(
"PORT_SCR_ERR 0x%x
\n
"
,
tmp
);
writel
(
tmp
,
port_mmio
+
PORT_SCR_ERR
);
/* ack any pending irq events for this port */
tmp
=
readl
(
port_mmio
+
PORT_IRQ_STAT
);
VPRINTK
(
"PORT_IRQ_STAT 0x%x
\n
"
,
tmp
);
if
(
tmp
)
writel
(
tmp
,
port_mmio
+
PORT_IRQ_STAT
);
writel
(
1
<<
i
,
mmio
+
HOST_IRQ_STAT
);
/* set irq mask (enables interrupts) */
writel
(
DEF_PORT_IRQ
,
port_mmio
+
PORT_IRQ_MASK
);
}
tmp
=
readl
(
mmio
+
HOST_CTL
);
VPRINTK
(
"HOST_CTL 0x%x
\n
"
,
tmp
);
writel
(
tmp
|
HOST_IRQ_EN
,
mmio
+
HOST_CTL
);
tmp
=
readl
(
mmio
+
HOST_CTL
);
VPRINTK
(
"HOST_CTL 0x%x
\n
"
,
tmp
);
pci_set_master
(
pdev
);
return
0
;
}
/* move to PCI layer, integrate w/ MSI stuff */
static
void
pci_enable_intx
(
struct
pci_dev
*
pdev
)
{
u16
pci_command
;
pci_read_config_word
(
pdev
,
PCI_COMMAND
,
&
pci_command
);
if
(
pci_command
&
PCI_COMMAND_INTX_DISABLE
)
{
pci_command
&=
~
PCI_COMMAND_INTX_DISABLE
;
pci_write_config_word
(
pdev
,
PCI_COMMAND
,
pci_command
);
}
}
static
void
ahci_print_info
(
struct
ata_probe_ent
*
probe_ent
)
{
struct
ahci_host_priv
*
hpriv
=
probe_ent
->
private_data
;
struct
pci_dev
*
pdev
=
probe_ent
->
pdev
;
void
*
mmio
=
probe_ent
->
mmio_base
;
u32
vers
,
cap
,
impl
,
speed
;
const
char
*
speed_s
;
vers
=
readl
(
mmio
+
HOST_VERSION
);
cap
=
hpriv
->
cap
;
impl
=
hpriv
->
port_map
;
speed
=
(
cap
>>
20
)
&
0xf
;
if
(
speed
==
1
)
speed_s
=
"1.5"
;
else
if
(
speed
==
2
)
speed_s
=
"3"
;
else
speed_s
=
"?"
;
printk
(
KERN_INFO
DRV_NAME
"(%s) AHCI %02x%02x.%02x%02x "
"%u slots %u ports %s Gbps 0x%x impl
\n
"
,
pci_name
(
pdev
),
(
vers
>>
24
)
&
0xff
,
(
vers
>>
16
)
&
0xff
,
(
vers
>>
8
)
&
0xff
,
vers
&
0xff
,
((
cap
>>
8
)
&
0x1f
)
+
1
,
(
cap
&
0x1f
)
+
1
,
speed_s
,
impl
);
printk
(
KERN_INFO
DRV_NAME
"(%s) flags: "
"%s%s%s%s%s%s"
"%s%s%s%s%s%s%s
\n
"
,
pci_name
(
pdev
),
cap
&
(
1
<<
31
)
?
"64bit "
:
""
,
cap
&
(
1
<<
30
)
?
"ncq "
:
""
,
cap
&
(
1
<<
28
)
?
"ilck "
:
""
,
cap
&
(
1
<<
27
)
?
"stag "
:
""
,
cap
&
(
1
<<
26
)
?
"pm "
:
""
,
cap
&
(
1
<<
25
)
?
"led "
:
""
,
cap
&
(
1
<<
24
)
?
"clo "
:
""
,
cap
&
(
1
<<
19
)
?
"nz "
:
""
,
cap
&
(
1
<<
18
)
?
"only "
:
""
,
cap
&
(
1
<<
17
)
?
"pmp "
:
""
,
cap
&
(
1
<<
15
)
?
"pio "
:
""
,
cap
&
(
1
<<
14
)
?
"slum "
:
""
,
cap
&
(
1
<<
13
)
?
"part "
:
""
);
}
static
int
ahci_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
int
printed_version
;
struct
ata_probe_ent
*
probe_ent
=
NULL
;
struct
ahci_host_priv
*
hpriv
;
unsigned
long
base
;
void
*
mmio_base
;
unsigned
int
board_idx
=
(
unsigned
int
)
ent
->
driver_data
;
int
rc
;
VPRINTK
(
"ENTER
\n
"
);
if
(
!
printed_version
++
)
printk
(
KERN_DEBUG
DRV_NAME
" version "
DRV_VERSION
"
\n
"
);
/*
* If this driver happens to only be useful on Apple's K2, then
* we should check that here as it has a normal Serverworks ID
*/
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
return
rc
;
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
goto
err_out
;
pci_enable_intx
(
pdev
);
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
->
pdev
=
pdev
;
INIT_LIST_HEAD
(
&
probe_ent
->
node
);
mmio_base
=
ioremap
(
pci_resource_start
(
pdev
,
AHCI_PCI_BAR
),
pci_resource_len
(
pdev
,
AHCI_PCI_BAR
));
if
(
mmio_base
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
err_out_free_ent
;
}
base
=
(
unsigned
long
)
mmio_base
;
hpriv
=
kmalloc
(
sizeof
(
*
hpriv
),
GFP_KERNEL
);
if
(
!
hpriv
)
{
rc
=
-
ENOMEM
;
goto
err_out_iounmap
;
}
memset
(
hpriv
,
0
,
sizeof
(
*
hpriv
));
probe_ent
->
sht
=
ahci_port_info
[
board_idx
].
sht
;
probe_ent
->
host_flags
=
ahci_port_info
[
board_idx
].
host_flags
;
probe_ent
->
pio_mask
=
ahci_port_info
[
board_idx
].
pio_mask
;
probe_ent
->
udma_mask
=
ahci_port_info
[
board_idx
].
udma_mask
;
probe_ent
->
port_ops
=
ahci_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
=
ahci_host_init
(
probe_ent
);
if
(
rc
)
goto
err_out_hpriv
;
ahci_print_info
(
probe_ent
);
/* 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:
pci_disable_device
(
pdev
);
return
rc
;
}
static
int
__init
ahci_init
(
void
)
{
return
pci_module_init
(
&
ahci_pci_driver
);
}
static
void
__exit
ahci_exit
(
void
)
{
pci_unregister_driver
(
&
ahci_pci_driver
);
}
MODULE_AUTHOR
(
"Jeff Garzik"
);
MODULE_DESCRIPTION
(
"AHCI SATA low-level driver"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DEVICE_TABLE
(
pci
,
ahci_pci_tbl
);
module_init
(
ahci_init
);
module_exit
(
ahci_exit
);
drivers/scsi/libata-core.c
View file @
82718086
...
@@ -39,6 +39,7 @@
...
@@ -39,6 +39,7 @@
#include <linux/workqueue.h>
#include <linux/workqueue.h>
#include <scsi/scsi.h>
#include <scsi/scsi.h>
#include "scsi.h"
#include "scsi.h"
#include "scsi_priv.h"
#include <scsi/scsi_host.h>
#include <scsi/scsi_host.h>
#include <linux/libata.h>
#include <linux/libata.h>
#include <asm/io.h>
#include <asm/io.h>
...
@@ -58,6 +59,7 @@ static int ata_choose_xfer_mode(struct ata_port *ap,
...
@@ -58,6 +59,7 @@ static int ata_choose_xfer_mode(struct ata_port *ap,
u8
*
xfer_mode_out
,
u8
*
xfer_mode_out
,
unsigned
int
*
xfer_shift_out
);
unsigned
int
*
xfer_shift_out
);
static
int
ata_qc_complete_noop
(
struct
ata_queued_cmd
*
qc
,
u8
drv_stat
);
static
int
ata_qc_complete_noop
(
struct
ata_queued_cmd
*
qc
,
u8
drv_stat
);
static
void
__ata_qc_complete
(
struct
ata_queued_cmd
*
qc
);
static
unsigned
int
ata_unique_id
=
1
;
static
unsigned
int
ata_unique_id
=
1
;
static
struct
workqueue_struct
*
ata_wq
;
static
struct
workqueue_struct
*
ata_wq
;
...
@@ -2193,11 +2195,50 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
...
@@ -2193,11 +2195,50 @@ static void ata_pio_sector(struct ata_queued_cmd *qc)
kunmap
(
page
);
kunmap
(
page
);
}
}
static
void
atapi_pio_sector
(
struct
ata_queued_cmd
*
qc
)
static
void
__atapi_pio_bytes
(
struct
ata_queued_cmd
*
qc
,
unsigned
int
bytes
)
{
int
do_write
=
(
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
);
struct
scatterlist
*
sg
=
qc
->
sg
;
struct
ata_port
*
ap
=
qc
->
ap
;
struct
page
*
page
;
unsigned
char
*
buf
;
unsigned
int
count
;
if
(
qc
->
curbytes
==
qc
->
nbytes
-
bytes
)
ap
->
pio_task_state
=
PIO_ST_LAST
;
next_sg:
sg
=
&
qc
->
sg
[
qc
->
cursg
];
page
=
sg
->
page
;
count
=
min
(
sg_dma_len
(
sg
)
-
qc
->
cursg_ofs
,
bytes
);
buf
=
kmap
(
page
)
+
sg
->
offset
+
qc
->
cursg_ofs
;
bytes
-=
count
;
qc
->
curbytes
+=
count
;
qc
->
cursg_ofs
+=
count
;
if
(
qc
->
cursg_ofs
==
sg_dma_len
(
sg
))
{
qc
->
cursg
++
;
qc
->
cursg_ofs
=
0
;
}
DPRINTK
(
"data %s
\n
"
,
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
?
"write"
:
"read"
);
/* do the actual data transfer */
ata_data_xfer
(
ap
,
buf
,
count
,
do_write
);
kunmap
(
page
);
if
(
bytes
)
goto
next_sg
;
}
static
void
atapi_pio_bytes
(
struct
ata_queued_cmd
*
qc
)
{
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
ata_port
*
ap
=
qc
->
ap
;
struct
ata_device
*
dev
=
qc
->
dev
;
struct
ata_device
*
dev
=
qc
->
dev
;
unsigned
int
i
,
i
reason
,
bc_lo
,
bc_hi
,
bytes
;
unsigned
int
ireason
,
bc_lo
,
bc_hi
,
bytes
;
int
i_write
,
do_write
=
(
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
)
?
1
:
0
;
int
i_write
,
do_write
=
(
qc
->
tf
.
flags
&
ATA_TFLAG_WRITE
)
?
1
:
0
;
ap
->
ops
->
tf_read
(
ap
,
&
qc
->
tf
);
ap
->
ops
->
tf_read
(
ap
,
&
qc
->
tf
);
...
@@ -2215,16 +2256,7 @@ static void atapi_pio_sector(struct ata_queued_cmd *qc)
...
@@ -2215,16 +2256,7 @@ static void atapi_pio_sector(struct ata_queued_cmd *qc)
if
(
do_write
!=
i_write
)
if
(
do_write
!=
i_write
)
goto
err_out
;
goto
err_out
;
/* make sure byte count is multiple of sector size; not
__atapi_pio_bytes
(
qc
,
bytes
);
* required by standard (warning! warning!), but IDE driver
* does this to simplify things a bit. We are lazy, and
* follow suit.
*/
if
(
bytes
&
(
ATA_SECT_SIZE
-
1
))
goto
err_out
;
for
(
i
=
0
;
i
<
(
bytes
>>
9
);
i
++
)
ata_pio_sector
(
qc
);
return
;
return
;
...
@@ -2265,19 +2297,30 @@ static void ata_pio_block(struct ata_port *ap)
...
@@ -2265,19 +2297,30 @@ static void ata_pio_block(struct ata_port *ap)
}
}
}
}
/* handle BSY=0, DRQ=0 as error */
if
((
status
&
ATA_DRQ
)
==
0
)
{
ap
->
pio_task_state
=
PIO_ST_ERR
;
return
;
}
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
assert
(
qc
!=
NULL
);
assert
(
qc
!=
NULL
);
if
(
is_atapi_taskfile
(
&
qc
->
tf
))
if
(
is_atapi_taskfile
(
&
qc
->
tf
))
{
atapi_pio_sector
(
qc
);
/* no more data to transfer or unsupported ATAPI command */
else
if
((
status
&
ATA_DRQ
)
==
0
)
{
ap
->
pio_task_state
=
PIO_ST_IDLE
;
ata_irq_on
(
ap
);
ata_qc_complete
(
qc
,
status
);
return
;
}
atapi_pio_bytes
(
qc
);
}
else
{
/* handle BSY=0, DRQ=0 as error */
if
((
status
&
ATA_DRQ
)
==
0
)
{
ap
->
pio_task_state
=
PIO_ST_ERR
;
return
;
}
ata_pio_sector
(
qc
);
ata_pio_sector
(
qc
);
}
}
}
static
void
ata_pio_error
(
struct
ata_port
*
ap
)
static
void
ata_pio_error
(
struct
ata_port
*
ap
)
...
@@ -2335,6 +2378,59 @@ static void ata_pio_task(void *_data)
...
@@ -2335,6 +2378,59 @@ static void ata_pio_task(void *_data)
}
}
}
}
static
void
atapi_request_sense
(
struct
ata_port
*
ap
,
struct
ata_device
*
dev
,
struct
scsi_cmnd
*
cmd
)
{
DECLARE_COMPLETION
(
wait
);
struct
ata_queued_cmd
*
qc
;
unsigned
long
flags
;
int
using_pio
=
dev
->
flags
&
ATA_DFLAG_PIO
;
int
rc
;
DPRINTK
(
"ATAPI request sense
\n
"
);
qc
=
ata_qc_new_init
(
ap
,
dev
);
BUG_ON
(
qc
==
NULL
);
/* FIXME: is this needed? */
memset
(
cmd
->
sense_buffer
,
0
,
sizeof
(
cmd
->
sense_buffer
));
ata_sg_init_one
(
qc
,
cmd
->
sense_buffer
,
sizeof
(
cmd
->
sense_buffer
));
qc
->
pci_dma_dir
=
PCI_DMA_FROMDEVICE
;
memset
(
&
qc
->
cdb
,
0
,
sizeof
(
ap
->
cdb_len
));
qc
->
cdb
[
0
]
=
REQUEST_SENSE
;
qc
->
cdb
[
4
]
=
SCSI_SENSE_BUFFERSIZE
;
qc
->
tf
.
flags
|=
ATA_TFLAG_ISADDR
|
ATA_TFLAG_DEVICE
;
qc
->
tf
.
command
=
ATA_CMD_PACKET
;
if
(
using_pio
)
{
qc
->
tf
.
protocol
=
ATA_PROT_ATAPI
;
qc
->
tf
.
lbam
=
(
8
*
1024
)
&
0xff
;
qc
->
tf
.
lbah
=
(
8
*
1024
)
>>
8
;
qc
->
nbytes
=
SCSI_SENSE_BUFFERSIZE
;
}
else
{
qc
->
tf
.
protocol
=
ATA_PROT_ATAPI_DMA
;
qc
->
tf
.
feature
|=
ATAPI_PKT_DMA
;
}
qc
->
waiting
=
&
wait
;
qc
->
complete_fn
=
ata_qc_complete_noop
;
spin_lock_irqsave
(
&
ap
->
host_set
->
lock
,
flags
);
rc
=
ata_qc_issue
(
qc
);
spin_unlock_irqrestore
(
&
ap
->
host_set
->
lock
,
flags
);
if
(
rc
)
ata_port_disable
(
ap
);
else
wait_for_completion
(
&
wait
);
DPRINTK
(
"EXIT
\n
"
);
}
/**
/**
* ata_qc_timeout - Handle timeout of queued command
* ata_qc_timeout - Handle timeout of queued command
* @qc: Command that timed out
* @qc: Command that timed out
...
@@ -2356,10 +2452,29 @@ static void ata_pio_task(void *_data)
...
@@ -2356,10 +2452,29 @@ static void ata_pio_task(void *_data)
static
void
ata_qc_timeout
(
struct
ata_queued_cmd
*
qc
)
static
void
ata_qc_timeout
(
struct
ata_queued_cmd
*
qc
)
{
{
struct
ata_port
*
ap
=
qc
->
ap
;
struct
ata_port
*
ap
=
qc
->
ap
;
struct
ata_device
*
dev
=
qc
->
dev
;
u8
host_stat
=
0
,
drv_stat
;
u8
host_stat
=
0
,
drv_stat
;
DPRINTK
(
"ENTER
\n
"
);
DPRINTK
(
"ENTER
\n
"
);
/* FIXME: doesn't this conflict with timeout handling? */
if
(
qc
->
dev
->
class
==
ATA_DEV_ATAPI
&&
qc
->
scsicmd
)
{
struct
scsi_cmnd
*
cmd
=
qc
->
scsicmd
;
if
(
!
scsi_eh_eflags_chk
(
cmd
,
SCSI_EH_CANCEL_CMD
))
{
/* finish completing original command */
__ata_qc_complete
(
qc
);
atapi_request_sense
(
ap
,
dev
,
cmd
);
cmd
->
result
=
(
CHECK_CONDITION
<<
1
)
|
(
DID_OK
<<
16
);
scsi_finish_command
(
cmd
);
goto
out
;
}
}
/* hack alert! We cannot use the supplied completion
/* hack alert! We cannot use the supplied completion
* function from inside the ->eh_strategy_handler() thread.
* function from inside the ->eh_strategy_handler() thread.
* libata is the only user of ->eh_strategy_handler() in
* libata is the only user of ->eh_strategy_handler() in
...
@@ -2393,7 +2508,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
...
@@ -2393,7 +2508,7 @@ static void ata_qc_timeout(struct ata_queued_cmd *qc)
ata_qc_complete
(
qc
,
drv_stat
);
ata_qc_complete
(
qc
,
drv_stat
);
break
;
break
;
}
}
out:
DPRINTK
(
"EXIT
\n
"
);
DPRINTK
(
"EXIT
\n
"
);
}
}
...
@@ -2482,6 +2597,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
...
@@ -2482,6 +2597,7 @@ struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap,
qc
->
dev
=
dev
;
qc
->
dev
=
dev
;
qc
->
cursect
=
qc
->
cursg
=
qc
->
cursg_ofs
=
0
;
qc
->
cursect
=
qc
->
cursg
=
qc
->
cursg_ofs
=
0
;
qc
->
nsect
=
0
;
qc
->
nsect
=
0
;
qc
->
nbytes
=
qc
->
curbytes
=
0
;
ata_tf_init
(
ap
,
&
qc
->
tf
,
dev
->
devno
);
ata_tf_init
(
ap
,
&
qc
->
tf
,
dev
->
devno
);
...
@@ -2497,6 +2613,30 @@ static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
...
@@ -2497,6 +2613,30 @@ static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
return
0
;
return
0
;
}
}
static
void
__ata_qc_complete
(
struct
ata_queued_cmd
*
qc
)
{
struct
ata_port
*
ap
=
qc
->
ap
;
unsigned
int
tag
,
do_clear
=
0
;
qc
->
flags
=
0
;
tag
=
qc
->
tag
;
if
(
likely
(
ata_tag_valid
(
tag
)))
{
if
(
tag
==
ap
->
active_tag
)
ap
->
active_tag
=
ATA_TAG_POISON
;
qc
->
tag
=
ATA_TAG_POISON
;
do_clear
=
1
;
}
if
(
qc
->
waiting
)
{
struct
completion
*
waiting
=
qc
->
waiting
;
qc
->
waiting
=
NULL
;
complete
(
waiting
);
}
if
(
likely
(
do_clear
))
clear_bit
(
tag
,
&
ap
->
qactive
);
}
/**
/**
* ata_qc_complete - Complete an active ATA command
* ata_qc_complete - Complete an active ATA command
* @qc: Command to complete
* @qc: Command to complete
...
@@ -2508,8 +2648,6 @@ static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
...
@@ -2508,8 +2648,6 @@ static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat)
void
ata_qc_complete
(
struct
ata_queued_cmd
*
qc
,
u8
drv_stat
)
void
ata_qc_complete
(
struct
ata_queued_cmd
*
qc
,
u8
drv_stat
)
{
{
struct
ata_port
*
ap
=
qc
->
ap
;
unsigned
int
tag
,
do_clear
=
0
;
int
rc
;
int
rc
;
assert
(
qc
!=
NULL
);
/* ata_qc_from_tag _might_ return NULL */
assert
(
qc
!=
NULL
);
/* ata_qc_from_tag _might_ return NULL */
...
@@ -2527,23 +2665,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
...
@@ -2527,23 +2665,7 @@ void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
if
(
rc
!=
0
)
if
(
rc
!=
0
)
return
;
return
;
qc
->
flags
=
0
;
__ata_qc_complete
(
qc
);
tag
=
qc
->
tag
;
if
(
likely
(
ata_tag_valid
(
tag
)))
{
if
(
tag
==
ap
->
active_tag
)
ap
->
active_tag
=
ATA_TAG_POISON
;
qc
->
tag
=
ATA_TAG_POISON
;
do_clear
=
1
;
}
if
(
qc
->
waiting
)
{
struct
completion
*
waiting
=
qc
->
waiting
;
qc
->
waiting
=
NULL
;
complete
(
waiting
);
}
if
(
likely
(
do_clear
))
clear_bit
(
tag
,
&
ap
->
qactive
);
VPRINTK
(
"EXIT
\n
"
);
VPRINTK
(
"EXIT
\n
"
);
}
}
...
...
drivers/scsi/libata-scsi.c
View file @
82718086
...
@@ -1248,9 +1248,15 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
...
@@ -1248,9 +1248,15 @@ static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat)
{
{
struct
scsi_cmnd
*
cmd
=
qc
->
scsicmd
;
struct
scsi_cmnd
*
cmd
=
qc
->
scsicmd
;
if
(
unlikely
(
drv_stat
&
(
ATA_ERR
|
ATA_BUSY
|
ATA_DRQ
)))
if
(
unlikely
(
drv_stat
&
(
ATA_ERR
|
ATA_BUSY
|
ATA_DRQ
)))
{
DPRINTK
(
"request check condition
\n
"
);
cmd
->
result
=
SAM_STAT_CHECK_CONDITION
;
cmd
->
result
=
SAM_STAT_CHECK_CONDITION
;
else
{
qc
->
scsidone
(
cmd
);
return
1
;
}
else
{
u8
*
scsicmd
=
cmd
->
cmnd
;
u8
*
scsicmd
=
cmd
->
cmnd
;
if
(
scsicmd
[
0
]
==
INQUIRY
)
{
if
(
scsicmd
[
0
]
==
INQUIRY
)
{
...
@@ -1322,6 +1328,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
...
@@ -1322,6 +1328,8 @@ static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd)
#endif
#endif
}
}
qc
->
nbytes
=
cmd
->
bufflen
;
return
0
;
return
0
;
}
}
...
...
drivers/scsi/sata_vsc.c
View file @
82718086
...
@@ -333,6 +333,14 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
...
@@ -333,6 +333,14 @@ static int __devinit vsc_sata_init_one (struct pci_dev *pdev, const struct pci_d
pci_set_master
(
pdev
);
pci_set_master
(
pdev
);
/*
* Config offset 0x98 is "Extended Control and Status Register 0"
* Default value is (1 << 28). All bits except bit 28 are reserved in
* DPA mode. If bit 28 is set, LED 0 reflects all ports' activity.
* If bit 28 is clear, each port has its own LED.
*/
pci_write_config_dword
(
pdev
,
0x98
,
0
);
/* FIXME: check ata_device_add return value */
/* FIXME: check ata_device_add return value */
ata_device_add
(
probe_ent
);
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
kfree
(
probe_ent
);
...
...
include/linux/libata.h
View file @
82718086
...
@@ -230,6 +230,10 @@ struct ata_queued_cmd {
...
@@ -230,6 +230,10 @@ struct ata_queued_cmd {
unsigned
int
nsect
;
unsigned
int
nsect
;
unsigned
int
cursect
;
unsigned
int
cursect
;
unsigned
int
nbytes
;
unsigned
int
curbytes
;
unsigned
int
cursg
;
unsigned
int
cursg
;
unsigned
int
cursg_ofs
;
unsigned
int
cursg_ofs
;
...
...
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