1*65c85c83SThomas Gleixner /* SPDX-License-Identifier: GPL-2.0-only */
22908d778SJames Bottomley /*
32908d778SJames Bottomley * Aic94xx SAS/SATA driver hardware interface header file.
42908d778SJames Bottomley *
52908d778SJames Bottomley * Copyright (C) 2005 Adaptec, Inc. All rights reserved.
62908d778SJames Bottomley * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com>
72908d778SJames Bottomley */
82908d778SJames Bottomley
92908d778SJames Bottomley #ifndef _AIC94XX_HWI_H_
102908d778SJames Bottomley #define _AIC94XX_HWI_H_
112908d778SJames Bottomley
122908d778SJames Bottomley #include <linux/interrupt.h>
132908d778SJames Bottomley #include <linux/pci.h>
142908d778SJames Bottomley #include <linux/dma-mapping.h>
152908d778SJames Bottomley
162908d778SJames Bottomley #include <scsi/libsas.h>
172908d778SJames Bottomley
182908d778SJames Bottomley #include "aic94xx.h"
192908d778SJames Bottomley #include "aic94xx_sas.h"
202908d778SJames Bottomley
212908d778SJames Bottomley /* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */
222908d778SJames Bottomley #define ASD_MAX_PHYS 8
232908d778SJames Bottomley #define ASD_PCBA_SN_SIZE 12
242908d778SJames Bottomley
252908d778SJames Bottomley struct asd_ha_addrspace {
262908d778SJames Bottomley void __iomem *addr;
272908d778SJames Bottomley unsigned long start; /* pci resource start */
282908d778SJames Bottomley unsigned long len; /* pci resource len */
292908d778SJames Bottomley unsigned long flags; /* pci resource flags */
302908d778SJames Bottomley
312908d778SJames Bottomley /* addresses internal to the host adapter */
322908d778SJames Bottomley u32 swa_base; /* mmspace 1 (MBAR1) uses this only */
332908d778SJames Bottomley u32 swb_base;
342908d778SJames Bottomley u32 swc_base;
352908d778SJames Bottomley };
362908d778SJames Bottomley
372908d778SJames Bottomley struct bios_struct {
382908d778SJames Bottomley int present;
392908d778SJames Bottomley u8 maj;
402908d778SJames Bottomley u8 min;
412908d778SJames Bottomley u32 bld;
422908d778SJames Bottomley };
432908d778SJames Bottomley
442908d778SJames Bottomley struct unit_element_struct {
452908d778SJames Bottomley u16 num;
462908d778SJames Bottomley u16 size;
472908d778SJames Bottomley void *area;
482908d778SJames Bottomley };
492908d778SJames Bottomley
502908d778SJames Bottomley struct flash_struct {
512908d778SJames Bottomley u32 bar;
522908d778SJames Bottomley int present;
532908d778SJames Bottomley int wide;
542908d778SJames Bottomley u8 manuf;
552908d778SJames Bottomley u8 dev_id;
562908d778SJames Bottomley u8 sec_prot;
571237c98dSGilbert Wu u8 method;
582908d778SJames Bottomley
592908d778SJames Bottomley u32 dir_offs;
602908d778SJames Bottomley };
612908d778SJames Bottomley
622908d778SJames Bottomley struct asd_phy_desc {
632908d778SJames Bottomley /* From CTRL-A settings, then set to what is appropriate */
642908d778SJames Bottomley u8 sas_addr[SAS_ADDR_SIZE];
652908d778SJames Bottomley u8 max_sas_lrate;
662908d778SJames Bottomley u8 min_sas_lrate;
672908d778SJames Bottomley u8 max_sata_lrate;
682908d778SJames Bottomley u8 min_sata_lrate;
692908d778SJames Bottomley u8 flags;
702908d778SJames Bottomley #define ASD_CRC_DIS 1
712908d778SJames Bottomley #define ASD_SATA_SPINUP_HOLD 2
722908d778SJames Bottomley
732908d778SJames Bottomley u8 phy_control_0; /* mode 5 reg 0x160 */
742908d778SJames Bottomley u8 phy_control_1; /* mode 5 reg 0x161 */
752908d778SJames Bottomley u8 phy_control_2; /* mode 5 reg 0x162 */
762908d778SJames Bottomley u8 phy_control_3; /* mode 5 reg 0x163 */
772908d778SJames Bottomley };
782908d778SJames Bottomley
792908d778SJames Bottomley struct asd_dma_tok {
802908d778SJames Bottomley void *vaddr;
812908d778SJames Bottomley dma_addr_t dma_handle;
822908d778SJames Bottomley size_t size;
832908d778SJames Bottomley };
842908d778SJames Bottomley
852908d778SJames Bottomley struct hw_profile {
862908d778SJames Bottomley struct bios_struct bios;
872908d778SJames Bottomley struct unit_element_struct ue;
882908d778SJames Bottomley struct flash_struct flash;
892908d778SJames Bottomley
902908d778SJames Bottomley u8 sas_addr[SAS_ADDR_SIZE];
912908d778SJames Bottomley char pcba_sn[ASD_PCBA_SN_SIZE+1];
922908d778SJames Bottomley
932908d778SJames Bottomley u8 enabled_phys; /* mask of enabled phys */
942908d778SJames Bottomley struct asd_phy_desc phy_desc[ASD_MAX_PHYS];
952908d778SJames Bottomley u32 max_scbs; /* absolute sequencer scb queue size */
962908d778SJames Bottomley struct asd_dma_tok *scb_ext;
972908d778SJames Bottomley u32 max_ddbs;
982908d778SJames Bottomley struct asd_dma_tok *ddb_ext;
992908d778SJames Bottomley
1002908d778SJames Bottomley spinlock_t ddb_lock;
1012908d778SJames Bottomley void *ddb_bitmap;
1022908d778SJames Bottomley
1032908d778SJames Bottomley int num_phys; /* ENABLEABLE */
1042908d778SJames Bottomley int max_phys; /* REPORTED + ENABLEABLE */
1052908d778SJames Bottomley
1062908d778SJames Bottomley unsigned addr_range; /* max # of addrs; max # of possible ports */
1072908d778SJames Bottomley unsigned port_name_base;
1082908d778SJames Bottomley unsigned dev_name_base;
1092908d778SJames Bottomley unsigned sata_name_base;
1102908d778SJames Bottomley };
1112908d778SJames Bottomley
1122908d778SJames Bottomley struct asd_ascb {
1132908d778SJames Bottomley struct list_head list;
1142908d778SJames Bottomley struct asd_ha_struct *ha;
1152908d778SJames Bottomley
1162908d778SJames Bottomley struct scb *scb; /* equals dma_scb->vaddr */
1172908d778SJames Bottomley struct asd_dma_tok dma_scb;
1182908d778SJames Bottomley struct asd_dma_tok *sg_arr;
1192908d778SJames Bottomley
1202908d778SJames Bottomley void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *);
1212908d778SJames Bottomley u8 uldd_timer:1;
1222908d778SJames Bottomley
1232908d778SJames Bottomley /* internally generated command */
1242908d778SJames Bottomley struct timer_list timer;
125e2396f1eSJames Bottomley struct completion *completion;
1262908d778SJames Bottomley u8 tag_valid:1;
1272908d778SJames Bottomley __be16 tag; /* error recovery only */
1282908d778SJames Bottomley
1292908d778SJames Bottomley /* If this is an Empty SCB, index of first edb in seq->edb_arr. */
1302908d778SJames Bottomley int edb_index;
1312908d778SJames Bottomley
1322908d778SJames Bottomley /* Used by the timer timeout function. */
1332908d778SJames Bottomley int tc_index;
1342908d778SJames Bottomley
1352908d778SJames Bottomley void *uldd_task;
1362908d778SJames Bottomley };
1372908d778SJames Bottomley
1382908d778SJames Bottomley #define ASD_DL_SIZE_BITS 0x8
1392908d778SJames Bottomley #define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS))
1402908d778SJames Bottomley #define ASD_DEF_DL_TOGGLE 0x01
1412908d778SJames Bottomley
1422908d778SJames Bottomley struct asd_seq_data {
1432908d778SJames Bottomley spinlock_t pend_q_lock;
1442908d778SJames Bottomley u16 scbpro;
1452908d778SJames Bottomley int pending;
1462908d778SJames Bottomley struct list_head pend_q;
1472908d778SJames Bottomley int can_queue; /* per adapter */
1482908d778SJames Bottomley struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */
1492908d778SJames Bottomley
1502908d778SJames Bottomley spinlock_t tc_index_lock;
1512908d778SJames Bottomley void **tc_index_array;
1522908d778SJames Bottomley void *tc_index_bitmap;
1532908d778SJames Bottomley int tc_index_bitmap_bits;
1542908d778SJames Bottomley
1552908d778SJames Bottomley struct tasklet_struct dl_tasklet;
1562908d778SJames Bottomley struct done_list_struct *dl; /* array of done list entries, equals */
1572908d778SJames Bottomley struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */
1582908d778SJames Bottomley int dl_toggle;
1592908d778SJames Bottomley int dl_next;
1602908d778SJames Bottomley
1612908d778SJames Bottomley int num_edbs;
1622908d778SJames Bottomley struct asd_dma_tok **edb_arr;
1632908d778SJames Bottomley int num_escbs;
1642908d778SJames Bottomley struct asd_ascb **escb_arr; /* array of pointers to escbs */
1652908d778SJames Bottomley };
1662908d778SJames Bottomley
1673f048109Smalahal@us.ibm.com /* This is an internal port structure. These are used to get accurate
1683f048109Smalahal@us.ibm.com * phy_mask for updating DDB 0.
1693f048109Smalahal@us.ibm.com */
1703f048109Smalahal@us.ibm.com struct asd_port {
1713f048109Smalahal@us.ibm.com u8 sas_addr[SAS_ADDR_SIZE];
1723f048109Smalahal@us.ibm.com u8 attached_sas_addr[SAS_ADDR_SIZE];
1733f048109Smalahal@us.ibm.com u32 phy_mask;
1743f048109Smalahal@us.ibm.com int num_phys;
1753f048109Smalahal@us.ibm.com };
1763f048109Smalahal@us.ibm.com
1772908d778SJames Bottomley /* This is the Host Adapter structure. It describes the hardware
1782908d778SJames Bottomley * SAS adapter.
1792908d778SJames Bottomley */
1802908d778SJames Bottomley struct asd_ha_struct {
1812908d778SJames Bottomley struct pci_dev *pcidev;
1822908d778SJames Bottomley const char *name;
1832908d778SJames Bottomley
1842908d778SJames Bottomley struct sas_ha_struct sas_ha;
1852908d778SJames Bottomley
1862908d778SJames Bottomley u8 revision_id;
1872908d778SJames Bottomley
1882908d778SJames Bottomley int iospace;
1892908d778SJames Bottomley spinlock_t iolock;
1902908d778SJames Bottomley struct asd_ha_addrspace io_handle[2];
1912908d778SJames Bottomley
1922908d778SJames Bottomley struct hw_profile hw_prof;
1932908d778SJames Bottomley
1942908d778SJames Bottomley struct asd_phy phys[ASD_MAX_PHYS];
1953f048109Smalahal@us.ibm.com spinlock_t asd_ports_lock;
1963f048109Smalahal@us.ibm.com struct asd_port asd_ports[ASD_MAX_PHYS];
1972908d778SJames Bottomley struct asd_sas_port ports[ASD_MAX_PHYS];
1982908d778SJames Bottomley
1992908d778SJames Bottomley struct dma_pool *scb_pool;
2002908d778SJames Bottomley
2012908d778SJames Bottomley struct asd_seq_data seq; /* sequencer related */
2021237c98dSGilbert Wu u32 bios_status;
2031237c98dSGilbert Wu const struct firmware *bios_image;
2042908d778SJames Bottomley };
2052908d778SJames Bottomley
2062908d778SJames Bottomley /* ---------- Common macros ---------- */
2072908d778SJames Bottomley
2082908d778SJames Bottomley #define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle))
2092908d778SJames Bottomley #define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \
2102908d778SJames Bottomley ? ((u32)((__dma_handle) >> 32)) \
2112908d778SJames Bottomley : ((u32)0))
2122908d778SJames Bottomley
2132908d778SJames Bottomley #define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev))
2142908d778SJames Bottomley #define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \
2152908d778SJames Bottomley && ((__site_no) & 0xF0FF) > 0x001F)
2162908d778SJames Bottomley /* For each bit set in __lseq_mask, set __lseq to equal the bit
2172908d778SJames Bottomley * position of the set bit and execute the statement following.
2182908d778SJames Bottomley * __mc is the temporary mask, used as a mask "counter".
2192908d778SJames Bottomley */
2202908d778SJames Bottomley #define for_each_sequencer(__lseq_mask, __mc, __lseq) \
2212908d778SJames Bottomley for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
2222908d778SJames Bottomley if (((__mc) & 1))
2232908d778SJames Bottomley #define for_each_phy(__lseq_mask, __mc, __lseq) \
2242908d778SJames Bottomley for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\
2252908d778SJames Bottomley if (((__mc) & 1))
2262908d778SJames Bottomley
2272908d778SJames Bottomley #define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I)))
2282908d778SJames Bottomley
2292908d778SJames Bottomley /* ---------- DMA allocs ---------- */
2302908d778SJames Bottomley
asd_dmatok_alloc(gfp_t flags)2313cc27547SAl Viro static inline struct asd_dma_tok *asd_dmatok_alloc(gfp_t flags)
2322908d778SJames Bottomley {
2332908d778SJames Bottomley return kmem_cache_alloc(asd_dma_token_cache, flags);
2342908d778SJames Bottomley }
2352908d778SJames Bottomley
asd_dmatok_free(struct asd_dma_tok * token)2362908d778SJames Bottomley static inline void asd_dmatok_free(struct asd_dma_tok *token)
2372908d778SJames Bottomley {
2382908d778SJames Bottomley kmem_cache_free(asd_dma_token_cache, token);
2392908d778SJames Bottomley }
2402908d778SJames Bottomley
asd_alloc_coherent(struct asd_ha_struct * asd_ha,size_t size,gfp_t flags)2412908d778SJames Bottomley static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct *
2422908d778SJames Bottomley asd_ha, size_t size,
2433cc27547SAl Viro gfp_t flags)
2442908d778SJames Bottomley {
2452908d778SJames Bottomley struct asd_dma_tok *token = asd_dmatok_alloc(flags);
2462908d778SJames Bottomley if (token) {
2472908d778SJames Bottomley token->size = size;
2482908d778SJames Bottomley token->vaddr = dma_alloc_coherent(&asd_ha->pcidev->dev,
2492908d778SJames Bottomley token->size,
2502908d778SJames Bottomley &token->dma_handle,
2512908d778SJames Bottomley flags);
2522908d778SJames Bottomley if (!token->vaddr) {
2532908d778SJames Bottomley asd_dmatok_free(token);
2542908d778SJames Bottomley token = NULL;
2552908d778SJames Bottomley }
2562908d778SJames Bottomley }
2572908d778SJames Bottomley return token;
2582908d778SJames Bottomley }
2592908d778SJames Bottomley
asd_free_coherent(struct asd_ha_struct * asd_ha,struct asd_dma_tok * token)2602908d778SJames Bottomley static inline void asd_free_coherent(struct asd_ha_struct *asd_ha,
2612908d778SJames Bottomley struct asd_dma_tok *token)
2622908d778SJames Bottomley {
2632908d778SJames Bottomley if (token) {
2642908d778SJames Bottomley dma_free_coherent(&asd_ha->pcidev->dev, token->size,
2652908d778SJames Bottomley token->vaddr, token->dma_handle);
2662908d778SJames Bottomley asd_dmatok_free(token);
2672908d778SJames Bottomley }
2682908d778SJames Bottomley }
2692908d778SJames Bottomley
asd_init_ascb(struct asd_ha_struct * asd_ha,struct asd_ascb * ascb)2702908d778SJames Bottomley static inline void asd_init_ascb(struct asd_ha_struct *asd_ha,
2712908d778SJames Bottomley struct asd_ascb *ascb)
2722908d778SJames Bottomley {
2732908d778SJames Bottomley INIT_LIST_HEAD(&ascb->list);
2742908d778SJames Bottomley ascb->scb = ascb->dma_scb.vaddr;
2752908d778SJames Bottomley ascb->ha = asd_ha;
27630199beeSKees Cook timer_setup(&ascb->timer, NULL, 0);
2772908d778SJames Bottomley ascb->tc_index = -1;
2782908d778SJames Bottomley }
2792908d778SJames Bottomley
2802908d778SJames Bottomley /* Must be called with the tc_index_lock held!
2812908d778SJames Bottomley */
asd_tc_index_release(struct asd_seq_data * seq,int index)2822908d778SJames Bottomley static inline void asd_tc_index_release(struct asd_seq_data *seq, int index)
2832908d778SJames Bottomley {
2842908d778SJames Bottomley seq->tc_index_array[index] = NULL;
2852908d778SJames Bottomley clear_bit(index, seq->tc_index_bitmap);
2862908d778SJames Bottomley }
2872908d778SJames Bottomley
2882908d778SJames Bottomley /* Must be called with the tc_index_lock held!
2892908d778SJames Bottomley */
asd_tc_index_get(struct asd_seq_data * seq,void * ptr)2902908d778SJames Bottomley static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr)
2912908d778SJames Bottomley {
2922908d778SJames Bottomley int index;
2932908d778SJames Bottomley
2942908d778SJames Bottomley index = find_first_zero_bit(seq->tc_index_bitmap,
2952908d778SJames Bottomley seq->tc_index_bitmap_bits);
2962908d778SJames Bottomley if (index == seq->tc_index_bitmap_bits)
2972908d778SJames Bottomley return -1;
2982908d778SJames Bottomley
2992908d778SJames Bottomley seq->tc_index_array[index] = ptr;
3002908d778SJames Bottomley set_bit(index, seq->tc_index_bitmap);
3012908d778SJames Bottomley
3022908d778SJames Bottomley return index;
3032908d778SJames Bottomley }
3042908d778SJames Bottomley
3052908d778SJames Bottomley /* Must be called with the tc_index_lock held!
3062908d778SJames Bottomley */
asd_tc_index_find(struct asd_seq_data * seq,int index)3072908d778SJames Bottomley static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index)
3082908d778SJames Bottomley {
3092908d778SJames Bottomley return seq->tc_index_array[index];
3102908d778SJames Bottomley }
3112908d778SJames Bottomley
3122908d778SJames Bottomley /**
3132908d778SJames Bottomley * asd_ascb_free -- free a single aSCB after is has completed
3142908d778SJames Bottomley * @ascb: pointer to the aSCB of interest
3152908d778SJames Bottomley *
3162908d778SJames Bottomley * This frees an aSCB after it has been executed/completed by
3172908d778SJames Bottomley * the sequencer.
3182908d778SJames Bottomley */
asd_ascb_free(struct asd_ascb * ascb)3192908d778SJames Bottomley static inline void asd_ascb_free(struct asd_ascb *ascb)
3202908d778SJames Bottomley {
3212908d778SJames Bottomley if (ascb) {
3222908d778SJames Bottomley struct asd_ha_struct *asd_ha = ascb->ha;
3232908d778SJames Bottomley unsigned long flags;
3242908d778SJames Bottomley
3252908d778SJames Bottomley BUG_ON(!list_empty(&ascb->list));
3262908d778SJames Bottomley spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags);
3272908d778SJames Bottomley asd_tc_index_release(&ascb->ha->seq, ascb->tc_index);
3282908d778SJames Bottomley spin_unlock_irqrestore(&ascb->ha->seq.tc_index_lock, flags);
3292908d778SJames Bottomley dma_pool_free(asd_ha->scb_pool, ascb->dma_scb.vaddr,
3302908d778SJames Bottomley ascb->dma_scb.dma_handle);
3312908d778SJames Bottomley kmem_cache_free(asd_ascb_cache, ascb);
3322908d778SJames Bottomley }
3332908d778SJames Bottomley }
3342908d778SJames Bottomley
3352908d778SJames Bottomley /**
3362908d778SJames Bottomley * asd_ascb_list_free -- free a list of ascbs
3372908d778SJames Bottomley * @ascb_list: a list of ascbs
3382908d778SJames Bottomley *
3392908d778SJames Bottomley * This function will free a list of ascbs allocated by asd_ascb_alloc_list.
3402908d778SJames Bottomley * It is used when say the scb queueing function returned QUEUE_FULL,
3412908d778SJames Bottomley * and we do not need the ascbs any more.
3422908d778SJames Bottomley */
asd_ascb_free_list(struct asd_ascb * ascb_list)3432908d778SJames Bottomley static inline void asd_ascb_free_list(struct asd_ascb *ascb_list)
3442908d778SJames Bottomley {
3452908d778SJames Bottomley LIST_HEAD(list);
3462908d778SJames Bottomley struct list_head *n, *pos;
3472908d778SJames Bottomley
3482908d778SJames Bottomley __list_add(&list, ascb_list->list.prev, &ascb_list->list);
3492908d778SJames Bottomley list_for_each_safe(pos, n, &list) {
3502908d778SJames Bottomley list_del_init(pos);
3512908d778SJames Bottomley asd_ascb_free(list_entry(pos, struct asd_ascb, list));
3522908d778SJames Bottomley }
3532908d778SJames Bottomley }
3542908d778SJames Bottomley
3552908d778SJames Bottomley /* ---------- Function declarations ---------- */
3562908d778SJames Bottomley
3572908d778SJames Bottomley int asd_init_hw(struct asd_ha_struct *asd_ha);
3587d12e780SDavid Howells irqreturn_t asd_hw_isr(int irq, void *dev_id);
3592908d778SJames Bottomley
3602908d778SJames Bottomley
3612908d778SJames Bottomley struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct
3622908d778SJames Bottomley *asd_ha, int *num,
3633cc27547SAl Viro gfp_t gfp_mask);
3642908d778SJames Bottomley
3652908d778SJames Bottomley int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
3662908d778SJames Bottomley int num);
3672908d778SJames Bottomley int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
3682908d778SJames Bottomley int num);
3692908d778SJames Bottomley
3702908d778SJames Bottomley int asd_init_post_escbs(struct asd_ha_struct *asd_ha);
3712908d778SJames Bottomley void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc);
3722908d778SJames Bottomley void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
3732908d778SJames Bottomley void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op);
3742908d778SJames Bottomley int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask);
3752908d778SJames Bottomley
37630199beeSKees Cook void asd_ascb_timedout(struct timer_list *t);
3772908d778SJames Bottomley int asd_chip_hardrst(struct asd_ha_struct *asd_ha);
3782908d778SJames Bottomley
3792908d778SJames Bottomley #endif
380