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
17049ac0
Commit
17049ac0
authored
Mar 09, 2004
by
Jeremy Higdon
Committed by
James Bottomley
Mar 09, 2004
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[libata] Add new driver for Vitesse VSC-7174.
parent
b2bda14c
Changes
3
Hide whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
421 additions
and
0 deletions
+421
-0
drivers/scsi/Kconfig
drivers/scsi/Kconfig
+8
-0
drivers/scsi/Makefile
drivers/scsi/Makefile
+1
-0
drivers/scsi/sata_vsc.c
drivers/scsi/sata_vsc.c
+412
-0
No files found.
drivers/scsi/Kconfig
View file @
17049ac0
...
...
@@ -438,6 +438,14 @@ config SCSI_SATA_VIA
If unsure, say N.
config SCSI_SATA_VITESSE
tristate "VITESSE VSC-7174 SATA support"
depends on SCSI_SATA && PCI && EXPERIMENTAL
help
This option enables support for Vitesse VSC7174 Serial ATA.
If unsure, say N.
config SCSI_BUSLOGIC
tristate "BusLogic SCSI support"
depends on (PCI || ISA || MCA) && SCSI
...
...
drivers/scsi/Makefile
View file @
17049ac0
...
...
@@ -114,6 +114,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_SIL)
+=
libata.o sata_sil.o
obj-$(CONFIG_SCSI_SATA_VIA)
+=
libata.o sata_via.o
obj-$(CONFIG_SCSI_SATA_VITESSE)
+=
libata.o sata_vsc.o
obj-$(CONFIG_ARM)
+=
arm/
...
...
drivers/scsi/sata_vsc.c
0 → 100644
View file @
17049ac0
/*
* sata_vsc.c - Vitesse VSC7174 4 port DPA SATA
*
* Copyright 2004 SGI
*
* Bits from Jeff Garzik, Copyright RedHat, 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.
*
*/
#include <linux/config.h>
#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 "scsi.h"
#include "hosts.h"
#include <linux/libata.h>
#define DRV_NAME "sata_vsc"
#define DRV_VERSION "0.01"
/* Interrupt register offsets (from chip base address) */
#define VSC_SATA_INT_STAT_OFFSET 0x00
#define VSC_SATA_INT_MASK_OFFSET 0x04
/* Taskfile registers offsets */
#define VSC_SATA_TF_CMD_OFFSET 0x00
#define VSC_SATA_TF_DATA_OFFSET 0x00
#define VSC_SATA_TF_ERROR_OFFSET 0x04
#define VSC_SATA_TF_FEATURE_OFFSET 0x06
#define VSC_SATA_TF_NSECT_OFFSET 0x08
#define VSC_SATA_TF_LBAL_OFFSET 0x0c
#define VSC_SATA_TF_LBAM_OFFSET 0x10
#define VSC_SATA_TF_LBAH_OFFSET 0x14
#define VSC_SATA_TF_DEVICE_OFFSET 0x18
#define VSC_SATA_TF_STATUS_OFFSET 0x1c
#define VSC_SATA_TF_COMMAND_OFFSET 0x1d
#define VSC_SATA_TF_ALTSTATUS_OFFSET 0x28
#define VSC_SATA_TF_CTL_OFFSET 0x29
/* DMA base */
#define VSC_SATA_DMA_CMD_OFFSET 0x70
/* SCRs base */
#define VSC_SATA_SCR_STATUS_OFFSET 0x100
#define VSC_SATA_SCR_ERROR_OFFSET 0x104
#define VSC_SATA_SCR_CONTROL_OFFSET 0x108
/* Port stride */
#define VSC_SATA_PORT_OFFSET 0x200
static
u32
vsc_sata_scr_read
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
)
{
if
(
sc_reg
>
SCR_CONTROL
)
return
0xffffffffU
;
return
readl
((
void
*
)
ap
->
ioaddr
.
scr_addr
+
(
sc_reg
*
4
));
}
static
void
vsc_sata_scr_write
(
struct
ata_port
*
ap
,
unsigned
int
sc_reg
,
u32
val
)
{
if
(
sc_reg
>
SCR_CONTROL
)
return
;
writel
(
val
,
(
void
*
)
ap
->
ioaddr
.
scr_addr
+
(
sc_reg
*
4
));
}
static
void
vsc_intr_mask_update
(
struct
ata_port
*
ap
,
u8
ctl
)
{
unsigned
long
mask_addr
;
u8
mask
;
mask_addr
=
(
unsigned
long
)
ap
->
host_set
->
mmio_base
+
VSC_SATA_INT_MASK_OFFSET
+
ap
->
port_no
;
mask
=
readb
(
mask_addr
);
if
(
ctl
&
ATA_NIEN
)
mask
|=
0x80
;
else
mask
&=
0x7F
;
writeb
(
mask
,
mask_addr
);
}
static
void
vsc_sata_tf_load
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
unsigned
int
is_addr
=
tf
->
flags
&
ATA_TFLAG_ISADDR
;
/*
* The only thing the ctl register is used for is SRST.
* That is not enabled or disabled via tf_load.
* However, if ATA_NIEN is changed, then we need to change the interrupt register.
*/
if
((
tf
->
ctl
&
ATA_NIEN
)
!=
(
ap
->
last_ctl
&
ATA_NIEN
))
{
ap
->
last_ctl
=
tf
->
ctl
;
vsc_intr_mask_update
(
ap
,
tf
->
ctl
&
ATA_NIEN
);
}
if
(
is_addr
&&
(
tf
->
flags
&
ATA_TFLAG_LBA48
))
{
writew
(
tf
->
feature
|
(((
u16
)
tf
->
hob_feature
)
<<
8
),
ioaddr
->
feature_addr
);
writew
(
tf
->
nsect
|
(((
u16
)
tf
->
hob_nsect
)
<<
8
),
ioaddr
->
nsect_addr
);
writew
(
tf
->
lbal
|
(((
u16
)
tf
->
hob_lbal
)
<<
8
),
ioaddr
->
lbal_addr
);
writew
(
tf
->
lbam
|
(((
u16
)
tf
->
hob_lbam
)
<<
8
),
ioaddr
->
lbam_addr
);
writew
(
tf
->
lbah
|
(((
u16
)
tf
->
hob_lbah
)
<<
8
),
ioaddr
->
lbah_addr
);
}
else
if
(
is_addr
)
{
writew
(
tf
->
feature
,
ioaddr
->
feature_addr
);
writew
(
tf
->
nsect
,
ioaddr
->
nsect_addr
);
writew
(
tf
->
lbal
,
ioaddr
->
lbal_addr
);
writew
(
tf
->
lbam
,
ioaddr
->
lbam_addr
);
writew
(
tf
->
lbah
,
ioaddr
->
lbah_addr
);
}
if
(
tf
->
flags
&
ATA_TFLAG_DEVICE
)
writeb
(
tf
->
device
,
ioaddr
->
device_addr
);
ata_wait_idle
(
ap
);
}
static
void
vsc_sata_tf_read
(
struct
ata_port
*
ap
,
struct
ata_taskfile
*
tf
)
{
struct
ata_ioports
*
ioaddr
=
&
ap
->
ioaddr
;
u16
nsect
,
lbal
,
lbam
,
lbah
;
nsect
=
tf
->
nsect
=
readw
(
ioaddr
->
nsect_addr
);
lbal
=
tf
->
lbal
=
readw
(
ioaddr
->
lbal_addr
);
lbam
=
tf
->
lbam
=
readw
(
ioaddr
->
lbam_addr
);
lbah
=
tf
->
lbah
=
readw
(
ioaddr
->
lbah_addr
);
tf
->
device
=
readw
(
ioaddr
->
device_addr
);
if
(
tf
->
flags
&
ATA_TFLAG_LBA48
)
{
tf
->
hob_feature
=
readb
(
ioaddr
->
error_addr
);
tf
->
hob_nsect
=
nsect
>>
8
;
tf
->
hob_lbal
=
lbal
>>
8
;
tf
->
hob_lbam
=
lbam
>>
8
;
tf
->
hob_lbah
=
lbah
>>
8
;
}
}
static
void
vsc_sata_set_piomode
(
struct
ata_port
*
ap
,
struct
ata_device
*
adev
,
unsigned
int
pio
)
{
/* We need empty implementation, the core doesn't test for NULL
* function pointer
*/
}
static
void
vsc_sata_set_udmamode
(
struct
ata_port
*
ap
,
struct
ata_device
*
adev
,
unsigned
int
udma
)
{
/* We need empty implementation, the core doesn't test for NULL
* function pointer
*/
}
/*
* vsc_sata_interrupt
*
* Read the interrupt register and process for the devices that have them pending.
*/
irqreturn_t
vsc_sata_interrupt
(
int
irq
,
void
*
dev_instance
,
struct
pt_regs
*
regs
)
{
struct
ata_host_set
*
host_set
=
dev_instance
;
unsigned
int
i
;
unsigned
int
handled
=
0
;
u32
int_status
;
spin_lock
(
&
host_set
->
lock
);
int_status
=
readl
(
host_set
->
mmio_base
+
VSC_SATA_INT_STAT_OFFSET
);
for
(
i
=
0
;
i
<
host_set
->
n_ports
;
i
++
)
{
if
(
int_status
&
((
u32
)
0xFF
<<
(
8
*
i
)))
{
struct
ata_port
*
ap
;
ap
=
host_set
->
ports
[
i
];
if
(
ap
&&
(
!
(
ap
->
flags
&
ATA_FLAG_PORT_DISABLED
)))
{
struct
ata_queued_cmd
*
qc
;
qc
=
ata_qc_from_tag
(
ap
,
ap
->
active_tag
);
if
(
qc
&&
((
qc
->
flags
&
ATA_QCFLAG_POLL
)
==
0
))
handled
+=
ata_host_intr
(
ap
,
qc
);
}
}
}
spin_unlock
(
&
host_set
->
lock
);
return
IRQ_RETVAL
(
handled
);
}
static
Scsi_Host_Template
vsc_sata_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
=
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
,
};
static
struct
ata_port_operations
vsc_sata_ops
=
{
.
port_disable
=
ata_port_disable
,
.
set_piomode
=
vsc_sata_set_piomode
,
.
set_udmamode
=
vsc_sata_set_udmamode
,
.
tf_load
=
vsc_sata_tf_load
,
.
tf_read
=
vsc_sata_tf_read
,
.
exec_command
=
ata_exec_command_mmio
,
.
check_status
=
ata_check_status_mmio
,
.
phy_reset
=
sata_phy_reset
,
.
phy_config
=
pata_phy_config
,
/* not a typo */
.
bmdma_start
=
ata_bmdma_start_mmio
,
.
fill_sg
=
ata_fill_sg
,
.
eng_timeout
=
ata_eng_timeout
,
.
irq_handler
=
vsc_sata_interrupt
,
.
scr_read
=
vsc_sata_scr_read
,
.
scr_write
=
vsc_sata_scr_write
,
.
port_start
=
ata_port_start
,
.
port_stop
=
ata_port_stop
,
};
static
void
vsc_sata_setup_port
(
struct
ata_ioports
*
port
,
unsigned
long
base
)
{
port
->
cmd_addr
=
base
+
VSC_SATA_TF_CMD_OFFSET
;
port
->
data_addr
=
base
+
VSC_SATA_TF_DATA_OFFSET
;
port
->
error_addr
=
base
+
VSC_SATA_TF_ERROR_OFFSET
;
port
->
feature_addr
=
base
+
VSC_SATA_TF_FEATURE_OFFSET
;
port
->
nsect_addr
=
base
+
VSC_SATA_TF_NSECT_OFFSET
;
port
->
lbal_addr
=
base
+
VSC_SATA_TF_LBAL_OFFSET
;
port
->
lbam_addr
=
base
+
VSC_SATA_TF_LBAM_OFFSET
;
port
->
lbah_addr
=
base
+
VSC_SATA_TF_LBAH_OFFSET
;
port
->
device_addr
=
base
+
VSC_SATA_TF_DEVICE_OFFSET
;
port
->
status_addr
=
base
+
VSC_SATA_TF_STATUS_OFFSET
;
port
->
command_addr
=
base
+
VSC_SATA_TF_COMMAND_OFFSET
;
port
->
altstatus_addr
=
base
+
VSC_SATA_TF_ALTSTATUS_OFFSET
;
port
->
ctl_addr
=
base
+
VSC_SATA_TF_CTL_OFFSET
;
port
->
bmdma_addr
=
base
+
VSC_SATA_DMA_CMD_OFFSET
;
port
->
scr_addr
=
base
+
VSC_SATA_SCR_STATUS_OFFSET
;
}
static
int
vsc_sata_init_one
(
struct
pci_dev
*
pdev
,
const
struct
pci_device_id
*
ent
)
{
static
int
printed_version
;
struct
ata_probe_ent
*
probe_ent
=
NULL
;
unsigned
long
base
;
void
*
mmio_base
;
int
rc
;
if
(
!
printed_version
++
)
printk
(
KERN_DEBUG
DRV_NAME
" version "
DRV_VERSION
"
\n
"
);
rc
=
pci_enable_device
(
pdev
);
if
(
rc
)
return
rc
;
/*
* Check if we have needed resource mapped.
*/
if
(
pci_resource_len
(
pdev
,
0
)
==
0
)
{
rc
=
-
ENODEV
;
goto
err_out
;
}
rc
=
pci_request_regions
(
pdev
,
DRV_NAME
);
if
(
rc
)
goto
err_out
;
/*
* Use 32 bit DMA mask, because 64 bit address support is poor.
*/
rc
=
pci_set_dma_mask
(
pdev
,
0xFFFFFFFF
);
if
(
rc
)
goto
err_out_regions
;
rc
=
pci_set_consistent_dma_mask
(
pdev
,
0xFFFFFFFF
);
if
(
rc
)
goto
err_out_regions
;
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
,
0
),
pci_resource_len
(
pdev
,
0
));
if
(
mmio_base
==
NULL
)
{
rc
=
-
ENOMEM
;
goto
err_out_free_ent
;
}
base
=
(
unsigned
long
)
mmio_base
;
/*
* Due to a bug in the chip, the default cache line size can't be used
*/
pci_write_config_byte
(
pdev
,
PCI_CACHE_LINE_SIZE
,
0x80
);
probe_ent
->
sht
=
&
vsc_sata_sht
;
probe_ent
->
host_flags
=
ATA_FLAG_SATA
|
ATA_FLAG_NO_LEGACY
|
ATA_FLAG_MMIO
|
ATA_FLAG_SATA_RESET
;
probe_ent
->
port_ops
=
&
vsc_sata_ops
;
probe_ent
->
n_ports
=
4
;
probe_ent
->
irq
=
pdev
->
irq
;
probe_ent
->
irq_flags
=
SA_SHIRQ
;
probe_ent
->
mmio_base
=
mmio_base
;
/* We don't care much about the PIO/UDMA masks, but the core won't like us
* if we don't fill these
*/
probe_ent
->
pio_mask
=
0x1f
;
probe_ent
->
udma_mask
=
0x3f
;
/* We have 4 ports per PCI function */
vsc_sata_setup_port
(
&
probe_ent
->
port
[
0
],
base
+
1
*
VSC_SATA_PORT_OFFSET
);
vsc_sata_setup_port
(
&
probe_ent
->
port
[
1
],
base
+
2
*
VSC_SATA_PORT_OFFSET
);
vsc_sata_setup_port
(
&
probe_ent
->
port
[
2
],
base
+
3
*
VSC_SATA_PORT_OFFSET
);
vsc_sata_setup_port
(
&
probe_ent
->
port
[
3
],
base
+
4
*
VSC_SATA_PORT_OFFSET
);
pci_set_master
(
pdev
);
/* FIXME: check ata_device_add return value */
ata_device_add
(
probe_ent
);
kfree
(
probe_ent
);
return
0
;
err_out_free_ent:
kfree
(
probe_ent
);
err_out_regions:
pci_release_regions
(
pdev
);
err_out:
pci_disable_device
(
pdev
);
return
rc
;
}
static
struct
pci_device_id
vsc_sata_pci_tbl
[]
=
{
{
0x1725
,
0x7174
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0x10600
,
0xFFFFFF
,
0
},
{
0x8086
,
0x3200
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0x10600
,
0xFFFFFF
,
0
},
{
}
};
static
struct
pci_driver
vsc_sata_pci_driver
=
{
.
name
=
DRV_NAME
,
.
id_table
=
vsc_sata_pci_tbl
,
.
probe
=
vsc_sata_init_one
,
.
remove
=
ata_pci_remove_one
,
};
static
int
__init
vsc_sata_init
(
void
)
{
int
rc
;
rc
=
pci_module_init
(
&
vsc_sata_pci_driver
);
if
(
rc
)
return
rc
;
return
0
;
}
static
void
__exit
vsc_sata_exit
(
void
)
{
pci_unregister_driver
(
&
vsc_sata_pci_driver
);
}
MODULE_AUTHOR
(
"Jeremy Higdon"
);
MODULE_DESCRIPTION
(
"low-level driver for Vitesse VSC7174 SATA controller"
);
MODULE_LICENSE
(
"GPL"
);
MODULE_DEVICE_TABLE
(
pci
,
vsc_sata_pci_tbl
);
module_init
(
vsc_sata_init
);
module_exit
(
vsc_sata_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