2015-11-17 19:50:30 +03:00
/*
* Copyright ( c ) 2015 Linaro Ltd .
* Copyright ( c ) 2015 Hisilicon Limited .
*
* 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 of the License , or
* ( at your option ) any later version .
*
*/
# ifndef _HISI_SAS_H_
# define _HISI_SAS_H_
2016-02-03 21:26:08 +03:00
# include <linux/acpi.h>
2016-10-04 14:11:11 +03:00
# include <linux/clk.h>
2015-11-17 19:50:30 +03:00
# include <linux/dmapool.h>
2017-08-10 19:09:40 +03:00
# include <linux/iopoll.h>
2015-11-17 19:50:30 +03:00
# include <linux/mfd/syscon.h>
# include <linux/module.h>
# include <linux/of_address.h>
2017-06-14 18:33:17 +03:00
# include <linux/pci.h>
2015-11-17 19:50:30 +03:00
# include <linux/platform_device.h>
2016-02-03 21:26:08 +03:00
# include <linux/property.h>
2015-11-17 19:50:30 +03:00
# include <linux/regmap.h>
2016-01-25 21:47:20 +03:00
# include <scsi/sas_ata.h>
2015-11-17 19:50:30 +03:00
# include <scsi/libsas.h>
2015-11-17 19:50:31 +03:00
# define HISI_SAS_MAX_PHYS 9
2015-11-17 19:50:34 +03:00
# define HISI_SAS_MAX_QUEUES 32
# define HISI_SAS_QUEUE_SLOTS 512
2017-10-24 18:51:35 +03:00
# define HISI_SAS_MAX_ITCT_ENTRIES 1024
2015-11-17 19:50:31 +03:00
# define HISI_SAS_MAX_DEVICES HISI_SAS_MAX_ITCT_ENTRIES
2017-03-22 20:25:18 +03:00
# define HISI_SAS_RESET_BIT 0
2017-08-10 19:09:26 +03:00
# define HISI_SAS_REJECT_CMD_BIT 1
2015-11-17 19:50:31 +03:00
2017-06-29 16:02:14 +03:00
# define HISI_SAS_STATUS_BUF_SZ (sizeof(struct hisi_sas_status_buffer))
# define HISI_SAS_COMMAND_TABLE_SZ (sizeof(union hisi_sas_command_table))
# define hisi_sas_status_buf_addr(buf) \
( buf + offsetof ( struct hisi_sas_slot_buf_table , status_buffer ) )
# define hisi_sas_status_buf_addr_mem(slot) hisi_sas_status_buf_addr(slot->buf)
# define hisi_sas_status_buf_addr_dma(slot) \
hisi_sas_status_buf_addr ( slot - > buf_dma )
# define hisi_sas_cmd_hdr_addr(buf) \
( buf + offsetof ( struct hisi_sas_slot_buf_table , command_header ) )
# define hisi_sas_cmd_hdr_addr_mem(slot) hisi_sas_cmd_hdr_addr(slot->buf)
# define hisi_sas_cmd_hdr_addr_dma(slot) hisi_sas_cmd_hdr_addr(slot->buf_dma)
# define hisi_sas_sge_addr(buf) \
( buf + offsetof ( struct hisi_sas_slot_buf_table , sge_page ) )
# define hisi_sas_sge_addr_mem(slot) hisi_sas_sge_addr(slot->buf)
# define hisi_sas_sge_addr_dma(slot) hisi_sas_sge_addr(slot->buf_dma)
2015-11-17 19:50:34 +03:00
2015-11-17 19:50:49 +03:00
# define HISI_SAS_MAX_SSP_RESP_SZ (sizeof(struct ssp_frame_hdr) + 1024)
2015-11-17 19:50:54 +03:00
# define HISI_SAS_MAX_SMP_RESP_SZ 1028
2016-01-25 21:47:20 +03:00
# define HISI_SAS_MAX_STP_RESP_SZ 28
2015-11-17 19:50:49 +03:00
2016-01-25 21:47:02 +03:00
# define DEV_IS_EXPANDER(type) \
( ( type = = SAS_EDGE_EXPANDER_DEVICE ) | | \
( type = = SAS_FANOUT_EXPANDER_DEVICE ) )
2017-06-14 18:33:14 +03:00
# define HISI_SAS_SATA_PROTOCOL_NONDATA 0x1
# define HISI_SAS_SATA_PROTOCOL_PIO 0x2
# define HISI_SAS_SATA_PROTOCOL_DMA 0x4
# define HISI_SAS_SATA_PROTOCOL_FPDMA 0x8
# define HISI_SAS_SATA_PROTOCOL_ATAPI 0x10
2015-11-17 19:50:51 +03:00
struct hisi_hba ;
2015-11-17 19:50:41 +03:00
2015-11-17 19:50:47 +03:00
enum {
PORT_TYPE_SAS = ( 1U < < 1 ) ,
PORT_TYPE_SATA = ( 1U < < 0 ) ,
} ;
2015-11-17 19:50:41 +03:00
enum dev_status {
HISI_SAS_DEV_NORMAL ,
HISI_SAS_DEV_EH ,
} ;
2015-11-17 19:50:51 +03:00
2016-08-24 14:05:47 +03:00
enum {
HISI_SAS_INT_ABT_CMD = 0 ,
HISI_SAS_INT_ABT_DEV = 1 ,
} ;
2015-11-17 19:50:51 +03:00
enum hisi_sas_dev_type {
HISI_SAS_DEV_TYPE_STP = 0 ,
HISI_SAS_DEV_TYPE_SSP ,
HISI_SAS_DEV_TYPE_SATA ,
} ;
2017-08-10 19:09:30 +03:00
struct hisi_sas_hw_error {
u32 irq_msk ;
u32 msk ;
int shift ;
const char * msg ;
int reg ;
2017-10-24 18:51:39 +03:00
const struct hisi_sas_hw_error * sub ;
2017-08-10 19:09:30 +03:00
} ;
2015-11-17 19:50:31 +03:00
struct hisi_sas_phy {
2015-11-17 19:50:42 +03:00
struct hisi_hba * hisi_hba ;
struct hisi_sas_port * port ;
2015-11-17 19:50:31 +03:00
struct asd_sas_phy sas_phy ;
2015-11-17 19:50:42 +03:00
struct sas_identify identify ;
2015-11-17 19:50:48 +03:00
struct work_struct phyup_ws ;
2015-11-17 19:50:42 +03:00
u64 port_id ; /* from hw */
2015-11-17 19:50:38 +03:00
u64 dev_sas_addr ;
2015-11-17 19:50:42 +03:00
u64 frame_rcvd_size ;
u8 frame_rcvd [ 32 ] ;
u8 phy_attached ;
u8 reserved [ 3 ] ;
2017-06-26 13:27:28 +03:00
u32 phy_type ;
2015-11-17 19:50:42 +03:00
enum sas_linkrate minimum_linkrate ;
enum sas_linkrate maximum_linkrate ;
2015-11-17 19:50:31 +03:00
} ;
struct hisi_sas_port {
struct asd_sas_port sas_port ;
2015-11-17 19:50:42 +03:00
u8 port_attached ;
u8 id ; /* from hw */
2015-11-17 19:50:31 +03:00
} ;
2015-11-17 19:50:37 +03:00
struct hisi_sas_cq {
struct hisi_hba * hisi_hba ;
2017-01-03 15:24:48 +03:00
struct tasklet_struct tasklet ;
2016-09-06 18:36:11 +03:00
int rd_point ;
2015-11-17 19:50:37 +03:00
int id ;
} ;
2016-09-06 18:36:12 +03:00
struct hisi_sas_dq {
struct hisi_hba * hisi_hba ;
2017-06-14 18:33:13 +03:00
struct hisi_sas_slot * slot_prep ;
spinlock_t lock ;
2016-09-06 18:36:12 +03:00
int wr_point ;
int id ;
} ;
2015-11-17 19:50:41 +03:00
struct hisi_sas_device {
2015-11-17 19:50:51 +03:00
struct hisi_hba * hisi_hba ;
struct domain_device * sas_device ;
2017-08-10 19:09:33 +03:00
struct completion * completion ;
2017-06-14 18:33:13 +03:00
struct hisi_sas_dq * dq ;
2017-06-14 18:33:12 +03:00
struct list_head list ;
2015-11-17 19:50:51 +03:00
u64 attached_phy ;
2016-11-07 15:48:39 +03:00
atomic64_t running_req ;
2017-06-14 18:33:12 +03:00
enum sas_device_type dev_type ;
int device_id ;
2017-04-10 16:21:57 +03:00
int sata_idx ;
2017-06-14 18:33:12 +03:00
u8 dev_status ;
2015-11-17 19:50:41 +03:00
} ;
2015-11-17 19:50:34 +03:00
struct hisi_sas_slot {
2015-11-17 19:50:49 +03:00
struct list_head entry ;
struct sas_task * task ;
struct hisi_sas_port * port ;
u64 n_elem ;
int dlvry_queue ;
int dlvry_queue_slot ;
2015-11-17 19:50:50 +03:00
int cmplt_queue ;
int cmplt_queue_slot ;
2015-11-17 19:50:49 +03:00
int idx ;
2016-02-25 12:42:11 +03:00
int abort ;
2017-06-29 16:02:14 +03:00
void * buf ;
dma_addr_t buf_dma ;
2015-11-17 19:50:49 +03:00
void * cmd_hdr ;
dma_addr_t cmd_hdr_dma ;
2016-02-25 12:42:11 +03:00
struct work_struct abort_slot ;
2017-04-10 16:21:59 +03:00
struct timer_list internal_abort_timer ;
2015-11-17 19:50:49 +03:00
} ;
struct hisi_sas_tmf_task {
u8 tmf ;
u16 tag_of_task_to_be_managed ;
2015-11-17 19:50:34 +03:00
} ;
2015-11-17 19:50:31 +03:00
struct hisi_sas_hw {
2015-11-17 19:50:46 +03:00
int ( * hw_init ) ( struct hisi_hba * hisi_hba ) ;
2015-11-17 19:50:51 +03:00
void ( * setup_itct ) ( struct hisi_hba * hisi_hba ,
struct hisi_sas_device * device ) ;
2016-04-15 16:36:36 +03:00
int ( * slot_index_alloc ) ( struct hisi_hba * hisi_hba , int * slot_idx ,
struct domain_device * device ) ;
struct hisi_sas_device * ( * alloc_dev ) ( struct domain_device * device ) ;
2015-11-17 19:50:48 +03:00
void ( * sl_notify ) ( struct hisi_hba * hisi_hba , int phy_no ) ;
2017-06-14 18:33:13 +03:00
int ( * get_free_slot ) ( struct hisi_hba * hisi_hba , struct hisi_sas_dq * dq ) ;
void ( * start_delivery ) ( struct hisi_sas_dq * dq ) ;
2015-11-17 19:50:49 +03:00
int ( * prep_ssp ) ( struct hisi_hba * hisi_hba ,
struct hisi_sas_slot * slot , int is_tmf ,
struct hisi_sas_tmf_task * tmf ) ;
2015-11-17 19:50:54 +03:00
int ( * prep_smp ) ( struct hisi_hba * hisi_hba ,
struct hisi_sas_slot * slot ) ;
2016-01-25 21:47:20 +03:00
int ( * prep_stp ) ( struct hisi_hba * hisi_hba ,
struct hisi_sas_slot * slot ) ;
2016-08-24 14:05:47 +03:00
int ( * prep_abort ) ( struct hisi_hba * hisi_hba ,
struct hisi_sas_slot * slot ,
int device_id , int abort_flag , int tag_to_abort ) ;
2015-11-17 19:50:50 +03:00
int ( * slot_complete ) ( struct hisi_hba * hisi_hba ,
2017-03-22 20:25:21 +03:00
struct hisi_sas_slot * slot ) ;
2017-03-22 20:25:19 +03:00
void ( * phys_init ) ( struct hisi_hba * hisi_hba ) ;
2017-10-24 18:51:36 +03:00
void ( * phy_start ) ( struct hisi_hba * hisi_hba , int phy_no ) ;
2015-11-17 19:50:57 +03:00
void ( * phy_disable ) ( struct hisi_hba * hisi_hba , int phy_no ) ;
void ( * phy_hard_reset ) ( struct hisi_hba * hisi_hba , int phy_no ) ;
2017-08-10 19:09:29 +03:00
void ( * get_events ) ( struct hisi_hba * hisi_hba , int phy_no ) ;
2016-11-07 15:48:40 +03:00
void ( * phy_set_linkrate ) ( struct hisi_hba * hisi_hba , int phy_no ,
struct sas_phy_linkrates * linkrates ) ;
enum sas_linkrate ( * phy_get_max_linkrate ) ( void ) ;
2015-11-17 19:50:50 +03:00
void ( * free_device ) ( struct hisi_hba * hisi_hba ,
struct hisi_sas_device * dev ) ;
2015-11-17 19:50:52 +03:00
int ( * get_wideport_bitmap ) ( struct hisi_hba * hisi_hba , int port_id ) ;
2017-06-14 18:33:32 +03:00
void ( * dereg_device ) ( struct hisi_hba * hisi_hba ,
struct domain_device * device ) ;
2017-03-22 20:25:18 +03:00
int ( * soft_reset ) ( struct hisi_hba * hisi_hba ) ;
2017-08-10 19:09:26 +03:00
u32 ( * get_phys_state ) ( struct hisi_hba * hisi_hba ) ;
2016-01-25 21:47:03 +03:00
int max_command_entries ;
2015-11-17 19:50:34 +03:00
int complete_hdr_size ;
2015-11-17 19:50:31 +03:00
} ;
struct hisi_hba {
/* This must be the first element, used by SHOST_TO_SAS_HA */
struct sas_ha_struct * p ;
2017-06-14 18:33:17 +03:00
struct platform_device * platform_dev ;
struct pci_dev * pci_dev ;
struct device * dev ;
2015-11-17 19:50:32 +03:00
void __iomem * regs ;
struct regmap * ctrl ;
u32 ctrl_reset_reg ;
u32 ctrl_reset_sts_reg ;
u32 ctrl_clock_ena_reg ;
2016-10-04 14:11:11 +03:00
u32 refclk_frequency_mhz ;
2015-11-17 19:50:31 +03:00
u8 sas_addr [ SAS_ADDR_SIZE ] ;
int n_phy ;
2015-11-17 19:50:43 +03:00
spinlock_t lock ;
2015-11-17 19:50:31 +03:00
2015-11-17 19:50:43 +03:00
struct timer_list timer ;
2015-11-17 19:50:40 +03:00
struct workqueue_struct * wq ;
2015-11-17 19:50:36 +03:00
int slot_index_count ;
unsigned long * slot_index_tags ;
2017-04-10 16:21:56 +03:00
unsigned long reject_stp_links_msk ;
2015-11-17 19:50:36 +03:00
2015-11-17 19:50:31 +03:00
/* SCSI/SAS glue */
struct sas_ha_struct sha ;
struct Scsi_Host * shost ;
2015-11-17 19:50:37 +03:00
struct hisi_sas_cq cq [ HISI_SAS_MAX_QUEUES ] ;
2016-09-06 18:36:12 +03:00
struct hisi_sas_dq dq [ HISI_SAS_MAX_QUEUES ] ;
2015-11-17 19:50:31 +03:00
struct hisi_sas_phy phy [ HISI_SAS_MAX_PHYS ] ;
struct hisi_sas_port port [ HISI_SAS_MAX_PHYS ] ;
2015-11-17 19:50:32 +03:00
int queue_count ;
2015-11-17 19:50:34 +03:00
2017-06-29 16:02:14 +03:00
struct dma_pool * buffer_pool ;
2015-11-17 19:50:41 +03:00
struct hisi_sas_device devices [ HISI_SAS_MAX_DEVICES ] ;
2015-11-17 19:50:34 +03:00
struct hisi_sas_cmd_hdr * cmd_hdr [ HISI_SAS_MAX_QUEUES ] ;
dma_addr_t cmd_hdr_dma [ HISI_SAS_MAX_QUEUES ] ;
void * complete_hdr [ HISI_SAS_MAX_QUEUES ] ;
dma_addr_t complete_hdr_dma [ HISI_SAS_MAX_QUEUES ] ;
struct hisi_sas_initial_fis * initial_fis ;
dma_addr_t initial_fis_dma ;
struct hisi_sas_itct * itct ;
dma_addr_t itct_dma ;
struct hisi_sas_iost * iost ;
dma_addr_t iost_dma ;
struct hisi_sas_breakpoint * breakpoint ;
dma_addr_t breakpoint_dma ;
struct hisi_sas_breakpoint * sata_breakpoint ;
dma_addr_t sata_breakpoint_dma ;
struct hisi_sas_slot * slot_info ;
2017-03-22 20:25:18 +03:00
unsigned long flags ;
2015-11-17 19:50:31 +03:00
const struct hisi_sas_hw * hw ; /* Low level hw interface */
2017-04-10 16:21:57 +03:00
unsigned long sata_dev_bitmap [ BITS_TO_LONGS ( HISI_SAS_MAX_DEVICES ) ] ;
2017-03-22 20:25:18 +03:00
struct work_struct rst_work ;
2015-11-17 19:50:31 +03:00
} ;
2015-11-17 19:50:33 +03:00
/* Generic HW DMA host memory structures */
/* Delivery queue header */
struct hisi_sas_cmd_hdr {
/* dw0 */
__le32 dw0 ;
/* dw1 */
__le32 dw1 ;
/* dw2 */
__le32 dw2 ;
/* dw3 */
__le32 transfer_tags ;
/* dw4 */
__le32 data_transfer_len ;
/* dw5 */
__le32 first_burst_num ;
/* dw6 */
__le32 sg_len ;
/* dw7 */
__le32 dw7 ;
/* dw8-9 */
__le64 cmd_table_addr ;
/* dw10-11 */
__le64 sts_buffer_addr ;
/* dw12-13 */
__le64 prd_table_addr ;
/* dw14-15 */
__le64 dif_prd_table_addr ;
} ;
struct hisi_sas_itct {
__le64 qw0 ;
__le64 sas_addr ;
__le64 qw2 ;
__le64 qw3 ;
2016-01-25 21:47:06 +03:00
__le64 qw4_15 [ 12 ] ;
2015-11-17 19:50:33 +03:00
} ;
struct hisi_sas_iost {
__le64 qw0 ;
__le64 qw1 ;
__le64 qw2 ;
__le64 qw3 ;
} ;
struct hisi_sas_err_record {
2016-01-25 21:47:05 +03:00
u32 data [ 4 ] ;
2015-11-17 19:50:33 +03:00
} ;
struct hisi_sas_initial_fis {
struct hisi_sas_err_record err_record ;
struct dev_to_host_fis fis ;
u32 rsvd [ 3 ] ;
} ;
struct hisi_sas_breakpoint {
2017-10-24 18:51:35 +03:00
u8 data [ 128 ] ;
} ;
struct hisi_sas_sata_breakpoint {
struct hisi_sas_breakpoint tag [ 32 ] ;
2015-11-17 19:50:33 +03:00
} ;
struct hisi_sas_sge {
__le64 addr ;
__le32 page_ctrl_0 ;
__le32 page_ctrl_1 ;
__le32 data_len ;
__le32 data_off ;
} ;
struct hisi_sas_command_table_smp {
u8 bytes [ 44 ] ;
} ;
struct hisi_sas_command_table_stp {
struct host_to_dev_fis command_fis ;
u8 dummy [ 12 ] ;
u8 atapi_cdb [ ATAPI_CDB_LEN ] ;
} ;
2016-04-05 00:48:10 +03:00
# define HISI_SAS_SGE_PAGE_CNT SG_CHUNK_SIZE
2015-11-17 19:50:33 +03:00
struct hisi_sas_sge_page {
struct hisi_sas_sge sge [ HISI_SAS_SGE_PAGE_CNT ] ;
2017-06-29 16:02:14 +03:00
} __aligned ( 16 ) ;
2015-11-17 19:50:33 +03:00
struct hisi_sas_command_table_ssp {
struct ssp_frame_hdr hdr ;
union {
struct {
struct ssp_command_iu task ;
u32 prot [ 6 ] ;
} ;
struct ssp_tmf_iu ssp_task ;
struct xfer_rdy_iu xfer_rdy ;
struct ssp_response_iu ssp_res ;
} u ;
} ;
union hisi_sas_command_table {
struct hisi_sas_command_table_ssp ssp ;
struct hisi_sas_command_table_smp smp ;
struct hisi_sas_command_table_stp stp ;
2017-06-29 16:02:14 +03:00
} __aligned ( 16 ) ;
struct hisi_sas_status_buffer {
struct hisi_sas_err_record err ;
u8 iu [ 1024 ] ;
} __aligned ( 16 ) ;
struct hisi_sas_slot_buf_table {
struct hisi_sas_status_buffer status_buffer ;
union hisi_sas_command_table command_header ;
struct hisi_sas_sge_page sge_page ;
2015-11-17 19:50:33 +03:00
} ;
2017-03-22 20:25:17 +03:00
2017-06-14 18:33:20 +03:00
extern struct scsi_transport_template * hisi_sas_stt ;
extern struct scsi_host_template * hisi_sas_sht ;
2017-08-10 19:09:40 +03:00
extern void hisi_sas_stop_phys ( struct hisi_hba * hisi_hba ) ;
2017-06-14 18:33:20 +03:00
extern void hisi_sas_init_add ( struct hisi_hba * hisi_hba ) ;
extern int hisi_sas_alloc ( struct hisi_hba * hisi_hba , struct Scsi_Host * shost ) ;
extern void hisi_sas_free ( struct hisi_hba * hisi_hba ) ;
2017-06-14 18:33:14 +03:00
extern u8 hisi_sas_get_ata_protocol ( u8 cmd , int direction ) ;
2017-03-22 20:25:17 +03:00
extern struct hisi_sas_port * to_hisi_sas_port ( struct asd_sas_port * sas_port ) ;
2017-06-14 18:33:15 +03:00
extern void hisi_sas_sata_done ( struct sas_task * task ,
struct hisi_sas_slot * slot ) ;
2017-06-14 18:33:16 +03:00
extern int hisi_sas_get_ncq_tag ( struct sas_task * task , u32 * tag ) ;
2017-06-14 18:33:18 +03:00
extern int hisi_sas_get_fw_info ( struct hisi_hba * hisi_hba ) ;
2015-11-17 19:50:44 +03:00
extern int hisi_sas_probe ( struct platform_device * pdev ,
const struct hisi_sas_hw * ops ) ;
extern int hisi_sas_remove ( struct platform_device * pdev ) ;
2015-11-17 19:50:33 +03:00
2015-11-17 19:50:52 +03:00
extern void hisi_sas_phy_down ( struct hisi_hba * hisi_hba , int phy_no , int rdy ) ;
2015-11-17 19:50:50 +03:00
extern void hisi_sas_slot_task_free ( struct hisi_hba * hisi_hba ,
struct sas_task * task ,
struct hisi_sas_slot * slot ) ;
2017-03-22 20:25:18 +03:00
extern void hisi_sas_init_mem ( struct hisi_hba * hisi_hba ) ;
2017-10-24 18:51:45 +03:00
extern void hisi_sas_rst_work_handler ( struct work_struct * work ) ;
2017-10-24 18:51:47 +03:00
extern void hisi_sas_kill_tasklets ( struct hisi_hba * hisi_hba ) ;
2015-11-17 19:50:30 +03:00
# endif