| 1 | /* SPDX-License-Identifier: GPL-2.0-only */ |
| 2 | /* |
| 3 | * Aic94xx SAS/SATA driver hardware interface header file. |
| 4 | * |
| 5 | * Copyright (C) 2005 Adaptec, Inc. All rights reserved. |
| 6 | * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> |
| 7 | */ |
| 8 | |
| 9 | #ifndef _AIC94XX_HWI_H_ |
| 10 | #define _AIC94XX_HWI_H_ |
| 11 | |
| 12 | #include <linux/interrupt.h> |
| 13 | #include <linux/pci.h> |
| 14 | #include <linux/dma-mapping.h> |
| 15 | |
| 16 | #include <scsi/libsas.h> |
| 17 | |
| 18 | #include "aic94xx.h" |
| 19 | #include "aic94xx_sas.h" |
| 20 | |
| 21 | /* Define ASD_MAX_PHYS to the maximum phys ever. Currently 8. */ |
| 22 | #define ASD_MAX_PHYS 8 |
| 23 | #define ASD_PCBA_SN_SIZE 12 |
| 24 | |
| 25 | struct asd_ha_addrspace { |
| 26 | void __iomem *addr; |
| 27 | unsigned long start; /* pci resource start */ |
| 28 | unsigned long len; /* pci resource len */ |
| 29 | unsigned long flags; /* pci resource flags */ |
| 30 | |
| 31 | /* addresses internal to the host adapter */ |
| 32 | u32 swa_base; /* mmspace 1 (MBAR1) uses this only */ |
| 33 | u32 swb_base; |
| 34 | u32 swc_base; |
| 35 | }; |
| 36 | |
| 37 | struct bios_struct { |
| 38 | int present; |
| 39 | u8 maj; |
| 40 | u8 min; |
| 41 | u32 bld; |
| 42 | }; |
| 43 | |
| 44 | struct unit_element_struct { |
| 45 | u16 num; |
| 46 | u16 size; |
| 47 | void *area; |
| 48 | }; |
| 49 | |
| 50 | struct flash_struct { |
| 51 | u32 bar; |
| 52 | int present; |
| 53 | int wide; |
| 54 | u8 manuf; |
| 55 | u8 dev_id; |
| 56 | u8 sec_prot; |
| 57 | u8 method; |
| 58 | |
| 59 | u32 dir_offs; |
| 60 | }; |
| 61 | |
| 62 | struct asd_phy_desc { |
| 63 | /* From CTRL-A settings, then set to what is appropriate */ |
| 64 | u8 sas_addr[SAS_ADDR_SIZE]; |
| 65 | u8 max_sas_lrate; |
| 66 | u8 min_sas_lrate; |
| 67 | u8 max_sata_lrate; |
| 68 | u8 min_sata_lrate; |
| 69 | u8 flags; |
| 70 | #define ASD_CRC_DIS 1 |
| 71 | #define ASD_SATA_SPINUP_HOLD 2 |
| 72 | |
| 73 | u8 phy_control_0; /* mode 5 reg 0x160 */ |
| 74 | u8 phy_control_1; /* mode 5 reg 0x161 */ |
| 75 | u8 phy_control_2; /* mode 5 reg 0x162 */ |
| 76 | u8 phy_control_3; /* mode 5 reg 0x163 */ |
| 77 | }; |
| 78 | |
| 79 | struct asd_dma_tok { |
| 80 | void *vaddr; |
| 81 | dma_addr_t dma_handle; |
| 82 | size_t size; |
| 83 | }; |
| 84 | |
| 85 | struct hw_profile { |
| 86 | struct bios_struct bios; |
| 87 | struct unit_element_struct ue; |
| 88 | struct flash_struct flash; |
| 89 | |
| 90 | u8 sas_addr[SAS_ADDR_SIZE]; |
| 91 | char pcba_sn[ASD_PCBA_SN_SIZE+1]; |
| 92 | |
| 93 | u8 enabled_phys; /* mask of enabled phys */ |
| 94 | struct asd_phy_desc phy_desc[ASD_MAX_PHYS]; |
| 95 | u32 max_scbs; /* absolute sequencer scb queue size */ |
| 96 | struct asd_dma_tok *scb_ext; |
| 97 | u32 max_ddbs; |
| 98 | struct asd_dma_tok *ddb_ext; |
| 99 | |
| 100 | spinlock_t ddb_lock; |
| 101 | void *ddb_bitmap; |
| 102 | |
| 103 | int num_phys; /* ENABLEABLE */ |
| 104 | int max_phys; /* REPORTED + ENABLEABLE */ |
| 105 | |
| 106 | unsigned addr_range; /* max # of addrs; max # of possible ports */ |
| 107 | unsigned port_name_base; |
| 108 | unsigned dev_name_base; |
| 109 | unsigned sata_name_base; |
| 110 | }; |
| 111 | |
| 112 | struct asd_ascb { |
| 113 | struct list_head list; |
| 114 | struct asd_ha_struct *ha; |
| 115 | |
| 116 | struct scb *scb; /* equals dma_scb->vaddr */ |
| 117 | struct asd_dma_tok dma_scb; |
| 118 | struct asd_dma_tok *sg_arr; |
| 119 | |
| 120 | void (*tasklet_complete)(struct asd_ascb *, struct done_list_struct *); |
| 121 | u8 uldd_timer:1; |
| 122 | |
| 123 | /* internally generated command */ |
| 124 | struct timer_list timer; |
| 125 | struct completion *completion; |
| 126 | u8 tag_valid:1; |
| 127 | __be16 tag; /* error recovery only */ |
| 128 | |
| 129 | /* If this is an Empty SCB, index of first edb in seq->edb_arr. */ |
| 130 | int edb_index; |
| 131 | |
| 132 | /* Used by the timer timeout function. */ |
| 133 | int tc_index; |
| 134 | |
| 135 | void *uldd_task; |
| 136 | }; |
| 137 | |
| 138 | #define ASD_DL_SIZE_BITS 0x8 |
| 139 | #define ASD_DL_SIZE (1<<(2+ASD_DL_SIZE_BITS)) |
| 140 | #define ASD_DEF_DL_TOGGLE 0x01 |
| 141 | |
| 142 | struct asd_seq_data { |
| 143 | spinlock_t pend_q_lock; |
| 144 | u16 scbpro; |
| 145 | int pending; |
| 146 | struct list_head pend_q; |
| 147 | int can_queue; /* per adapter */ |
| 148 | struct asd_dma_tok next_scb; /* next scb to be delivered to CSEQ */ |
| 149 | |
| 150 | spinlock_t tc_index_lock; |
| 151 | void **tc_index_array; |
| 152 | void *tc_index_bitmap; |
| 153 | int tc_index_bitmap_bits; |
| 154 | |
| 155 | struct tasklet_struct dl_tasklet; |
| 156 | struct done_list_struct *dl; /* array of done list entries, equals */ |
| 157 | struct asd_dma_tok *actual_dl; /* actual_dl->vaddr */ |
| 158 | int dl_toggle; |
| 159 | int dl_next; |
| 160 | |
| 161 | int num_edbs; |
| 162 | struct asd_dma_tok **edb_arr; |
| 163 | int num_escbs; |
| 164 | struct asd_ascb **escb_arr; /* array of pointers to escbs */ |
| 165 | }; |
| 166 | |
| 167 | /* This is an internal port structure. These are used to get accurate |
| 168 | * phy_mask for updating DDB 0. |
| 169 | */ |
| 170 | struct asd_port { |
| 171 | u8 sas_addr[SAS_ADDR_SIZE]; |
| 172 | u8 attached_sas_addr[SAS_ADDR_SIZE]; |
| 173 | u32 phy_mask; |
| 174 | int num_phys; |
| 175 | }; |
| 176 | |
| 177 | /* This is the Host Adapter structure. It describes the hardware |
| 178 | * SAS adapter. |
| 179 | */ |
| 180 | struct asd_ha_struct { |
| 181 | struct pci_dev *pcidev; |
| 182 | const char *name; |
| 183 | |
| 184 | struct sas_ha_struct sas_ha; |
| 185 | |
| 186 | u8 revision_id; |
| 187 | |
| 188 | int iospace; |
| 189 | spinlock_t iolock; |
| 190 | struct asd_ha_addrspace io_handle[2]; |
| 191 | |
| 192 | struct hw_profile hw_prof; |
| 193 | |
| 194 | struct asd_phy phys[ASD_MAX_PHYS]; |
| 195 | spinlock_t asd_ports_lock; |
| 196 | struct asd_port asd_ports[ASD_MAX_PHYS]; |
| 197 | struct asd_sas_port ports[ASD_MAX_PHYS]; |
| 198 | |
| 199 | struct dma_pool *scb_pool; |
| 200 | |
| 201 | struct asd_seq_data seq; /* sequencer related */ |
| 202 | u32 bios_status; |
| 203 | const struct firmware *bios_image; |
| 204 | }; |
| 205 | |
| 206 | /* ---------- Common macros ---------- */ |
| 207 | |
| 208 | #define ASD_BUSADDR_LO(__dma_handle) ((u32)(__dma_handle)) |
| 209 | #define ASD_BUSADDR_HI(__dma_handle) (((sizeof(dma_addr_t))==8) \ |
| 210 | ? ((u32)((__dma_handle) >> 32)) \ |
| 211 | : ((u32)0)) |
| 212 | |
| 213 | #define dev_to_asd_ha(__dev) pci_get_drvdata(to_pci_dev(__dev)) |
| 214 | #define SCB_SITE_VALID(__site_no) (((__site_no) & 0xF0FF) != 0x00FF \ |
| 215 | && ((__site_no) & 0xF0FF) > 0x001F) |
| 216 | /* For each bit set in __lseq_mask, set __lseq to equal the bit |
| 217 | * position of the set bit and execute the statement following. |
| 218 | * __mc is the temporary mask, used as a mask "counter". |
| 219 | */ |
| 220 | #define for_each_sequencer(__lseq_mask, __mc, __lseq) \ |
| 221 | for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\ |
| 222 | if (((__mc) & 1)) |
| 223 | #define for_each_phy(__lseq_mask, __mc, __lseq) \ |
| 224 | for ((__mc)=(__lseq_mask),(__lseq)=0;(__mc)!=0;(__lseq++),(__mc)>>=1)\ |
| 225 | if (((__mc) & 1)) |
| 226 | |
| 227 | #define PHY_ENABLED(_HA, _I) ((_HA)->hw_prof.enabled_phys & (1<<(_I))) |
| 228 | |
| 229 | /* ---------- DMA allocs ---------- */ |
| 230 | |
| 231 | static inline struct asd_dma_tok *asd_dmatok_alloc(gfp_t flags) |
| 232 | { |
| 233 | return kmem_cache_alloc(asd_dma_token_cache, flags); |
| 234 | } |
| 235 | |
| 236 | static inline void asd_dmatok_free(struct asd_dma_tok *token) |
| 237 | { |
| 238 | kmem_cache_free(s: asd_dma_token_cache, objp: token); |
| 239 | } |
| 240 | |
| 241 | static inline struct asd_dma_tok *asd_alloc_coherent(struct asd_ha_struct * |
| 242 | asd_ha, size_t size, |
| 243 | gfp_t flags) |
| 244 | { |
| 245 | struct asd_dma_tok *token = asd_dmatok_alloc(flags); |
| 246 | if (token) { |
| 247 | token->size = size; |
| 248 | token->vaddr = dma_alloc_coherent(dev: &asd_ha->pcidev->dev, |
| 249 | size: token->size, |
| 250 | dma_handle: &token->dma_handle, |
| 251 | gfp: flags); |
| 252 | if (!token->vaddr) { |
| 253 | asd_dmatok_free(token); |
| 254 | token = NULL; |
| 255 | } |
| 256 | } |
| 257 | return token; |
| 258 | } |
| 259 | |
| 260 | static inline void asd_free_coherent(struct asd_ha_struct *asd_ha, |
| 261 | struct asd_dma_tok *token) |
| 262 | { |
| 263 | if (token) { |
| 264 | dma_free_coherent(dev: &asd_ha->pcidev->dev, size: token->size, |
| 265 | cpu_addr: token->vaddr, dma_handle: token->dma_handle); |
| 266 | asd_dmatok_free(token); |
| 267 | } |
| 268 | } |
| 269 | |
| 270 | static inline void asd_init_ascb(struct asd_ha_struct *asd_ha, |
| 271 | struct asd_ascb *ascb) |
| 272 | { |
| 273 | INIT_LIST_HEAD(list: &ascb->list); |
| 274 | ascb->scb = ascb->dma_scb.vaddr; |
| 275 | ascb->ha = asd_ha; |
| 276 | timer_setup(&ascb->timer, NULL, 0); |
| 277 | ascb->tc_index = -1; |
| 278 | } |
| 279 | |
| 280 | /* Must be called with the tc_index_lock held! |
| 281 | */ |
| 282 | static inline void asd_tc_index_release(struct asd_seq_data *seq, int index) |
| 283 | { |
| 284 | seq->tc_index_array[index] = NULL; |
| 285 | clear_bit(nr: index, addr: seq->tc_index_bitmap); |
| 286 | } |
| 287 | |
| 288 | /* Must be called with the tc_index_lock held! |
| 289 | */ |
| 290 | static inline int asd_tc_index_get(struct asd_seq_data *seq, void *ptr) |
| 291 | { |
| 292 | int index; |
| 293 | |
| 294 | index = find_first_zero_bit(addr: seq->tc_index_bitmap, |
| 295 | size: seq->tc_index_bitmap_bits); |
| 296 | if (index == seq->tc_index_bitmap_bits) |
| 297 | return -1; |
| 298 | |
| 299 | seq->tc_index_array[index] = ptr; |
| 300 | set_bit(nr: index, addr: seq->tc_index_bitmap); |
| 301 | |
| 302 | return index; |
| 303 | } |
| 304 | |
| 305 | /* Must be called with the tc_index_lock held! |
| 306 | */ |
| 307 | static inline void *asd_tc_index_find(struct asd_seq_data *seq, int index) |
| 308 | { |
| 309 | return seq->tc_index_array[index]; |
| 310 | } |
| 311 | |
| 312 | /** |
| 313 | * asd_ascb_free -- free a single aSCB after is has completed |
| 314 | * @ascb: pointer to the aSCB of interest |
| 315 | * |
| 316 | * This frees an aSCB after it has been executed/completed by |
| 317 | * the sequencer. |
| 318 | */ |
| 319 | static inline void asd_ascb_free(struct asd_ascb *ascb) |
| 320 | { |
| 321 | if (ascb) { |
| 322 | struct asd_ha_struct *asd_ha = ascb->ha; |
| 323 | unsigned long flags; |
| 324 | |
| 325 | BUG_ON(!list_empty(&ascb->list)); |
| 326 | spin_lock_irqsave(&ascb->ha->seq.tc_index_lock, flags); |
| 327 | asd_tc_index_release(seq: &ascb->ha->seq, index: ascb->tc_index); |
| 328 | spin_unlock_irqrestore(lock: &ascb->ha->seq.tc_index_lock, flags); |
| 329 | dma_pool_free(pool: asd_ha->scb_pool, vaddr: ascb->dma_scb.vaddr, |
| 330 | addr: ascb->dma_scb.dma_handle); |
| 331 | kmem_cache_free(s: asd_ascb_cache, objp: ascb); |
| 332 | } |
| 333 | } |
| 334 | |
| 335 | /** |
| 336 | * asd_ascb_list_free -- free a list of ascbs |
| 337 | * @ascb_list: a list of ascbs |
| 338 | * |
| 339 | * This function will free a list of ascbs allocated by asd_ascb_alloc_list. |
| 340 | * It is used when say the scb queueing function returned QUEUE_FULL, |
| 341 | * and we do not need the ascbs any more. |
| 342 | */ |
| 343 | static inline void asd_ascb_free_list(struct asd_ascb *ascb_list) |
| 344 | { |
| 345 | LIST_HEAD(list); |
| 346 | struct list_head *n, *pos; |
| 347 | |
| 348 | __list_add(new: &list, prev: ascb_list->list.prev, next: &ascb_list->list); |
| 349 | list_for_each_safe(pos, n, &list) { |
| 350 | list_del_init(entry: pos); |
| 351 | asd_ascb_free(list_entry(pos, struct asd_ascb, list)); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | /* ---------- Function declarations ---------- */ |
| 356 | |
| 357 | int asd_init_hw(struct asd_ha_struct *asd_ha); |
| 358 | irqreturn_t asd_hw_isr(int irq, void *dev_id); |
| 359 | |
| 360 | |
| 361 | struct asd_ascb *asd_ascb_alloc_list(struct asd_ha_struct |
| 362 | *asd_ha, int *num, |
| 363 | gfp_t gfp_mask); |
| 364 | |
| 365 | int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, |
| 366 | int num); |
| 367 | int asd_post_escb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb, |
| 368 | int num); |
| 369 | |
| 370 | int asd_init_post_escbs(struct asd_ha_struct *asd_ha); |
| 371 | void asd_build_control_phy(struct asd_ascb *ascb, int phy_id, u8 subfunc); |
| 372 | void asd_control_led(struct asd_ha_struct *asd_ha, int phy_id, int op); |
| 373 | void asd_turn_led(struct asd_ha_struct *asd_ha, int phy_id, int op); |
| 374 | int asd_enable_phys(struct asd_ha_struct *asd_ha, const u8 phy_mask); |
| 375 | |
| 376 | void asd_ascb_timedout(struct timer_list *t); |
| 377 | int asd_chip_hardrst(struct asd_ha_struct *asd_ha); |
| 378 | |
| 379 | #endif |
| 380 | |