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