1*2908d778SJames Bottomley /* 2*2908d778SJames Bottomley * Aic94xx SAS/SATA driver sequencer interface. 3*2908d778SJames Bottomley * 4*2908d778SJames Bottomley * Copyright (C) 2005 Adaptec, Inc. All rights reserved. 5*2908d778SJames Bottomley * Copyright (C) 2005 Luben Tuikov <luben_tuikov@adaptec.com> 6*2908d778SJames Bottomley * 7*2908d778SJames Bottomley * Parts of this code adapted from David Chaw's adp94xx_seq.c. 8*2908d778SJames Bottomley * 9*2908d778SJames Bottomley * This file is licensed under GPLv2. 10*2908d778SJames Bottomley * 11*2908d778SJames Bottomley * This file is part of the aic94xx driver. 12*2908d778SJames Bottomley * 13*2908d778SJames Bottomley * The aic94xx driver is free software; you can redistribute it and/or 14*2908d778SJames Bottomley * modify it under the terms of the GNU General Public License as 15*2908d778SJames Bottomley * published by the Free Software Foundation; version 2 of the 16*2908d778SJames Bottomley * License. 17*2908d778SJames Bottomley * 18*2908d778SJames Bottomley * The aic94xx driver is distributed in the hope that it will be useful, 19*2908d778SJames Bottomley * but WITHOUT ANY WARRANTY; without even the implied warranty of 20*2908d778SJames Bottomley * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 21*2908d778SJames Bottomley * General Public License for more details. 22*2908d778SJames Bottomley * 23*2908d778SJames Bottomley * You should have received a copy of the GNU General Public License 24*2908d778SJames Bottomley * along with the aic94xx driver; if not, write to the Free Software 25*2908d778SJames Bottomley * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 26*2908d778SJames Bottomley * 27*2908d778SJames Bottomley */ 28*2908d778SJames Bottomley 29*2908d778SJames Bottomley #include <linux/delay.h> 30*2908d778SJames Bottomley #include <linux/pci.h> 31*2908d778SJames Bottomley #include <linux/firmware.h> 32*2908d778SJames Bottomley #include "aic94xx_reg.h" 33*2908d778SJames Bottomley #include "aic94xx_hwi.h" 34*2908d778SJames Bottomley 35*2908d778SJames Bottomley #include "aic94xx_seq.h" 36*2908d778SJames Bottomley #include "aic94xx_dump.h" 37*2908d778SJames Bottomley 38*2908d778SJames Bottomley /* It takes no more than 0.05 us for an instruction 39*2908d778SJames Bottomley * to complete. So waiting for 1 us should be more than 40*2908d778SJames Bottomley * plenty. 41*2908d778SJames Bottomley */ 42*2908d778SJames Bottomley #define PAUSE_DELAY 1 43*2908d778SJames Bottomley #define PAUSE_TRIES 1000 44*2908d778SJames Bottomley 45*2908d778SJames Bottomley static const struct firmware *sequencer_fw; 46*2908d778SJames Bottomley static const char *sequencer_version; 47*2908d778SJames Bottomley static u16 cseq_vecs[CSEQ_NUM_VECS], lseq_vecs[LSEQ_NUM_VECS], mode2_task, 48*2908d778SJames Bottomley cseq_idle_loop, lseq_idle_loop; 49*2908d778SJames Bottomley static u8 *cseq_code, *lseq_code; 50*2908d778SJames Bottomley static u32 cseq_code_size, lseq_code_size; 51*2908d778SJames Bottomley 52*2908d778SJames Bottomley static u16 first_scb_site_no = 0xFFFF; 53*2908d778SJames Bottomley static u16 last_scb_site_no; 54*2908d778SJames Bottomley 55*2908d778SJames Bottomley /* ---------- Pause/Unpause CSEQ/LSEQ ---------- */ 56*2908d778SJames Bottomley 57*2908d778SJames Bottomley /** 58*2908d778SJames Bottomley * asd_pause_cseq - pause the central sequencer 59*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 60*2908d778SJames Bottomley * 61*2908d778SJames Bottomley * Return 0 on success, negative on failure. 62*2908d778SJames Bottomley */ 63*2908d778SJames Bottomley int asd_pause_cseq(struct asd_ha_struct *asd_ha) 64*2908d778SJames Bottomley { 65*2908d778SJames Bottomley int count = PAUSE_TRIES; 66*2908d778SJames Bottomley u32 arp2ctl; 67*2908d778SJames Bottomley 68*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 69*2908d778SJames Bottomley if (arp2ctl & PAUSED) 70*2908d778SJames Bottomley return 0; 71*2908d778SJames Bottomley 72*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl | EPAUSE); 73*2908d778SJames Bottomley do { 74*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 75*2908d778SJames Bottomley if (arp2ctl & PAUSED) 76*2908d778SJames Bottomley return 0; 77*2908d778SJames Bottomley udelay(PAUSE_DELAY); 78*2908d778SJames Bottomley } while (--count > 0); 79*2908d778SJames Bottomley 80*2908d778SJames Bottomley ASD_DPRINTK("couldn't pause CSEQ\n"); 81*2908d778SJames Bottomley return -1; 82*2908d778SJames Bottomley } 83*2908d778SJames Bottomley 84*2908d778SJames Bottomley /** 85*2908d778SJames Bottomley * asd_unpause_cseq - unpause the central sequencer. 86*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure. 87*2908d778SJames Bottomley * 88*2908d778SJames Bottomley * Return 0 on success, negative on error. 89*2908d778SJames Bottomley */ 90*2908d778SJames Bottomley int asd_unpause_cseq(struct asd_ha_struct *asd_ha) 91*2908d778SJames Bottomley { 92*2908d778SJames Bottomley u32 arp2ctl; 93*2908d778SJames Bottomley int count = PAUSE_TRIES; 94*2908d778SJames Bottomley 95*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 96*2908d778SJames Bottomley if (!(arp2ctl & PAUSED)) 97*2908d778SJames Bottomley return 0; 98*2908d778SJames Bottomley 99*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CARP2CTL, arp2ctl & ~EPAUSE); 100*2908d778SJames Bottomley do { 101*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, CARP2CTL); 102*2908d778SJames Bottomley if (!(arp2ctl & PAUSED)) 103*2908d778SJames Bottomley return 0; 104*2908d778SJames Bottomley udelay(PAUSE_DELAY); 105*2908d778SJames Bottomley } while (--count > 0); 106*2908d778SJames Bottomley 107*2908d778SJames Bottomley ASD_DPRINTK("couldn't unpause the CSEQ\n"); 108*2908d778SJames Bottomley return -1; 109*2908d778SJames Bottomley } 110*2908d778SJames Bottomley 111*2908d778SJames Bottomley /** 112*2908d778SJames Bottomley * asd_seq_pause_lseq - pause a link sequencer 113*2908d778SJames Bottomley * @asd_ha: pointer to a host adapter structure 114*2908d778SJames Bottomley * @lseq: link sequencer of interest 115*2908d778SJames Bottomley * 116*2908d778SJames Bottomley * Return 0 on success, negative on error. 117*2908d778SJames Bottomley */ 118*2908d778SJames Bottomley static inline int asd_seq_pause_lseq(struct asd_ha_struct *asd_ha, int lseq) 119*2908d778SJames Bottomley { 120*2908d778SJames Bottomley u32 arp2ctl; 121*2908d778SJames Bottomley int count = PAUSE_TRIES; 122*2908d778SJames Bottomley 123*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 124*2908d778SJames Bottomley if (arp2ctl & PAUSED) 125*2908d778SJames Bottomley return 0; 126*2908d778SJames Bottomley 127*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl | EPAUSE); 128*2908d778SJames Bottomley do { 129*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 130*2908d778SJames Bottomley if (arp2ctl & PAUSED) 131*2908d778SJames Bottomley return 0; 132*2908d778SJames Bottomley udelay(PAUSE_DELAY); 133*2908d778SJames Bottomley } while (--count > 0); 134*2908d778SJames Bottomley 135*2908d778SJames Bottomley ASD_DPRINTK("couldn't pause LSEQ %d\n", lseq); 136*2908d778SJames Bottomley return -1; 137*2908d778SJames Bottomley } 138*2908d778SJames Bottomley 139*2908d778SJames Bottomley /** 140*2908d778SJames Bottomley * asd_pause_lseq - pause the link sequencer(s) 141*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 142*2908d778SJames Bottomley * @lseq_mask: mask of link sequencers of interest 143*2908d778SJames Bottomley * 144*2908d778SJames Bottomley * Return 0 on success, negative on failure. 145*2908d778SJames Bottomley */ 146*2908d778SJames Bottomley int asd_pause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) 147*2908d778SJames Bottomley { 148*2908d778SJames Bottomley int lseq; 149*2908d778SJames Bottomley int err = 0; 150*2908d778SJames Bottomley 151*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) { 152*2908d778SJames Bottomley err = asd_seq_pause_lseq(asd_ha, lseq); 153*2908d778SJames Bottomley if (err) 154*2908d778SJames Bottomley return err; 155*2908d778SJames Bottomley } 156*2908d778SJames Bottomley 157*2908d778SJames Bottomley return err; 158*2908d778SJames Bottomley } 159*2908d778SJames Bottomley 160*2908d778SJames Bottomley /** 161*2908d778SJames Bottomley * asd_seq_unpause_lseq - unpause a link sequencer 162*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 163*2908d778SJames Bottomley * @lseq: link sequencer of interest 164*2908d778SJames Bottomley * 165*2908d778SJames Bottomley * Return 0 on success, negative on error. 166*2908d778SJames Bottomley */ 167*2908d778SJames Bottomley static inline int asd_seq_unpause_lseq(struct asd_ha_struct *asd_ha, int lseq) 168*2908d778SJames Bottomley { 169*2908d778SJames Bottomley u32 arp2ctl; 170*2908d778SJames Bottomley int count = PAUSE_TRIES; 171*2908d778SJames Bottomley 172*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 173*2908d778SJames Bottomley if (!(arp2ctl & PAUSED)) 174*2908d778SJames Bottomley return 0; 175*2908d778SJames Bottomley 176*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmARP2CTL(lseq), arp2ctl & ~EPAUSE); 177*2908d778SJames Bottomley do { 178*2908d778SJames Bottomley arp2ctl = asd_read_reg_dword(asd_ha, LmARP2CTL(lseq)); 179*2908d778SJames Bottomley if (!(arp2ctl & PAUSED)) 180*2908d778SJames Bottomley return 0; 181*2908d778SJames Bottomley udelay(PAUSE_DELAY); 182*2908d778SJames Bottomley } while (--count > 0); 183*2908d778SJames Bottomley 184*2908d778SJames Bottomley ASD_DPRINTK("couldn't unpause LSEQ %d\n", lseq); 185*2908d778SJames Bottomley return 0; 186*2908d778SJames Bottomley } 187*2908d778SJames Bottomley 188*2908d778SJames Bottomley 189*2908d778SJames Bottomley /** 190*2908d778SJames Bottomley * asd_unpause_lseq - unpause the link sequencer(s) 191*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 192*2908d778SJames Bottomley * @lseq_mask: mask of link sequencers of interest 193*2908d778SJames Bottomley * 194*2908d778SJames Bottomley * Return 0 on success, negative on failure. 195*2908d778SJames Bottomley */ 196*2908d778SJames Bottomley int asd_unpause_lseq(struct asd_ha_struct *asd_ha, u8 lseq_mask) 197*2908d778SJames Bottomley { 198*2908d778SJames Bottomley int lseq; 199*2908d778SJames Bottomley int err = 0; 200*2908d778SJames Bottomley 201*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) { 202*2908d778SJames Bottomley err = asd_seq_unpause_lseq(asd_ha, lseq); 203*2908d778SJames Bottomley if (err) 204*2908d778SJames Bottomley return err; 205*2908d778SJames Bottomley } 206*2908d778SJames Bottomley 207*2908d778SJames Bottomley return err; 208*2908d778SJames Bottomley } 209*2908d778SJames Bottomley 210*2908d778SJames Bottomley /* ---------- Downloading CSEQ/LSEQ microcode ---------- */ 211*2908d778SJames Bottomley 212*2908d778SJames Bottomley static int asd_verify_cseq(struct asd_ha_struct *asd_ha, const u8 *_prog, 213*2908d778SJames Bottomley u32 size) 214*2908d778SJames Bottomley { 215*2908d778SJames Bottomley u32 addr = CSEQ_RAM_REG_BASE_ADR; 216*2908d778SJames Bottomley const u32 *prog = (u32 *) _prog; 217*2908d778SJames Bottomley u32 i; 218*2908d778SJames Bottomley 219*2908d778SJames Bottomley for (i = 0; i < size; i += 4, prog++, addr += 4) { 220*2908d778SJames Bottomley u32 val = asd_read_reg_dword(asd_ha, addr); 221*2908d778SJames Bottomley 222*2908d778SJames Bottomley if (le32_to_cpu(*prog) != val) { 223*2908d778SJames Bottomley asd_printk("%s: cseq verify failed at %u " 224*2908d778SJames Bottomley "read:0x%x, wanted:0x%x\n", 225*2908d778SJames Bottomley pci_name(asd_ha->pcidev), 226*2908d778SJames Bottomley i, val, le32_to_cpu(*prog)); 227*2908d778SJames Bottomley return -1; 228*2908d778SJames Bottomley } 229*2908d778SJames Bottomley } 230*2908d778SJames Bottomley ASD_DPRINTK("verified %d bytes, passed\n", size); 231*2908d778SJames Bottomley return 0; 232*2908d778SJames Bottomley } 233*2908d778SJames Bottomley 234*2908d778SJames Bottomley /** 235*2908d778SJames Bottomley * asd_verify_lseq - verify the microcode of a link sequencer 236*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 237*2908d778SJames Bottomley * @_prog: pointer to the microcode 238*2908d778SJames Bottomley * @size: size of the microcode in bytes 239*2908d778SJames Bottomley * @lseq: link sequencer of interest 240*2908d778SJames Bottomley * 241*2908d778SJames Bottomley * The link sequencer code is accessed in 4 KB pages, which are selected 242*2908d778SJames Bottomley * by setting LmRAMPAGE (bits 8 and 9) of the LmBISTCTL1 register. 243*2908d778SJames Bottomley * The 10 KB LSEQm instruction code is mapped, page at a time, at 244*2908d778SJames Bottomley * LmSEQRAM address. 245*2908d778SJames Bottomley */ 246*2908d778SJames Bottomley static int asd_verify_lseq(struct asd_ha_struct *asd_ha, const u8 *_prog, 247*2908d778SJames Bottomley u32 size, int lseq) 248*2908d778SJames Bottomley { 249*2908d778SJames Bottomley #define LSEQ_CODEPAGE_SIZE 4096 250*2908d778SJames Bottomley int pages = (size + LSEQ_CODEPAGE_SIZE - 1) / LSEQ_CODEPAGE_SIZE; 251*2908d778SJames Bottomley u32 page; 252*2908d778SJames Bottomley const u32 *prog = (u32 *) _prog; 253*2908d778SJames Bottomley 254*2908d778SJames Bottomley for (page = 0; page < pages; page++) { 255*2908d778SJames Bottomley u32 i; 256*2908d778SJames Bottomley 257*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmBISTCTL1(lseq), 258*2908d778SJames Bottomley page << LmRAMPAGE_LSHIFT); 259*2908d778SJames Bottomley for (i = 0; size > 0 && i < LSEQ_CODEPAGE_SIZE; 260*2908d778SJames Bottomley i += 4, prog++, size-=4) { 261*2908d778SJames Bottomley 262*2908d778SJames Bottomley u32 val = asd_read_reg_dword(asd_ha, LmSEQRAM(lseq)+i); 263*2908d778SJames Bottomley 264*2908d778SJames Bottomley if (le32_to_cpu(*prog) != val) { 265*2908d778SJames Bottomley asd_printk("%s: LSEQ%d verify failed " 266*2908d778SJames Bottomley "page:%d, offs:%d\n", 267*2908d778SJames Bottomley pci_name(asd_ha->pcidev), 268*2908d778SJames Bottomley lseq, page, i); 269*2908d778SJames Bottomley return -1; 270*2908d778SJames Bottomley } 271*2908d778SJames Bottomley } 272*2908d778SJames Bottomley } 273*2908d778SJames Bottomley ASD_DPRINTK("LSEQ%d verified %d bytes, passed\n", lseq, 274*2908d778SJames Bottomley (int)((u8 *)prog-_prog)); 275*2908d778SJames Bottomley return 0; 276*2908d778SJames Bottomley } 277*2908d778SJames Bottomley 278*2908d778SJames Bottomley /** 279*2908d778SJames Bottomley * asd_verify_seq -- verify CSEQ/LSEQ microcode 280*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 281*2908d778SJames Bottomley * @prog: pointer to microcode 282*2908d778SJames Bottomley * @size: size of the microcode 283*2908d778SJames Bottomley * @lseq_mask: if 0, verify CSEQ microcode, else mask of LSEQs of interest 284*2908d778SJames Bottomley * 285*2908d778SJames Bottomley * Return 0 if microcode is correct, negative on mismatch. 286*2908d778SJames Bottomley */ 287*2908d778SJames Bottomley static int asd_verify_seq(struct asd_ha_struct *asd_ha, const u8 *prog, 288*2908d778SJames Bottomley u32 size, u8 lseq_mask) 289*2908d778SJames Bottomley { 290*2908d778SJames Bottomley if (lseq_mask == 0) 291*2908d778SJames Bottomley return asd_verify_cseq(asd_ha, prog, size); 292*2908d778SJames Bottomley else { 293*2908d778SJames Bottomley int lseq, err; 294*2908d778SJames Bottomley 295*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) { 296*2908d778SJames Bottomley err = asd_verify_lseq(asd_ha, prog, size, lseq); 297*2908d778SJames Bottomley if (err) 298*2908d778SJames Bottomley return err; 299*2908d778SJames Bottomley } 300*2908d778SJames Bottomley } 301*2908d778SJames Bottomley 302*2908d778SJames Bottomley return 0; 303*2908d778SJames Bottomley } 304*2908d778SJames Bottomley #define ASD_DMA_MODE_DOWNLOAD 305*2908d778SJames Bottomley #ifdef ASD_DMA_MODE_DOWNLOAD 306*2908d778SJames Bottomley /* This is the size of the CSEQ Mapped instruction page */ 307*2908d778SJames Bottomley #define MAX_DMA_OVLY_COUNT ((1U << 14)-1) 308*2908d778SJames Bottomley static int asd_download_seq(struct asd_ha_struct *asd_ha, 309*2908d778SJames Bottomley const u8 * const prog, u32 size, u8 lseq_mask) 310*2908d778SJames Bottomley { 311*2908d778SJames Bottomley u32 comstaten; 312*2908d778SJames Bottomley u32 reg; 313*2908d778SJames Bottomley int page; 314*2908d778SJames Bottomley const int pages = (size + MAX_DMA_OVLY_COUNT - 1) / MAX_DMA_OVLY_COUNT; 315*2908d778SJames Bottomley struct asd_dma_tok *token; 316*2908d778SJames Bottomley int err = 0; 317*2908d778SJames Bottomley 318*2908d778SJames Bottomley if (size % 4) { 319*2908d778SJames Bottomley asd_printk("sequencer program not multiple of 4\n"); 320*2908d778SJames Bottomley return -1; 321*2908d778SJames Bottomley } 322*2908d778SJames Bottomley 323*2908d778SJames Bottomley asd_pause_cseq(asd_ha); 324*2908d778SJames Bottomley asd_pause_lseq(asd_ha, 0xFF); 325*2908d778SJames Bottomley 326*2908d778SJames Bottomley /* save, disable and clear interrupts */ 327*2908d778SJames Bottomley comstaten = asd_read_reg_dword(asd_ha, COMSTATEN); 328*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, COMSTATEN, 0); 329*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, COMSTAT, COMSTAT_MASK); 330*2908d778SJames Bottomley 331*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CHIMINTEN, RST_CHIMINTEN); 332*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CHIMINT, CHIMINT_MASK); 333*2908d778SJames Bottomley 334*2908d778SJames Bottomley token = asd_alloc_coherent(asd_ha, MAX_DMA_OVLY_COUNT, GFP_KERNEL); 335*2908d778SJames Bottomley if (!token) { 336*2908d778SJames Bottomley asd_printk("out of memory for dma SEQ download\n"); 337*2908d778SJames Bottomley err = -ENOMEM; 338*2908d778SJames Bottomley goto out; 339*2908d778SJames Bottomley } 340*2908d778SJames Bottomley ASD_DPRINTK("dma-ing %d bytes\n", size); 341*2908d778SJames Bottomley 342*2908d778SJames Bottomley for (page = 0; page < pages; page++) { 343*2908d778SJames Bottomley int i; 344*2908d778SJames Bottomley u32 left = min(size-page*MAX_DMA_OVLY_COUNT, 345*2908d778SJames Bottomley (u32)MAX_DMA_OVLY_COUNT); 346*2908d778SJames Bottomley 347*2908d778SJames Bottomley memcpy(token->vaddr, prog + page*MAX_DMA_OVLY_COUNT, left); 348*2908d778SJames Bottomley asd_write_reg_addr(asd_ha, OVLYDMAADR, token->dma_handle); 349*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, OVLYDMACNT, left); 350*2908d778SJames Bottomley reg = !page ? RESETOVLYDMA : 0; 351*2908d778SJames Bottomley reg |= (STARTOVLYDMA | OVLYHALTERR); 352*2908d778SJames Bottomley reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); 353*2908d778SJames Bottomley /* Start DMA. */ 354*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); 355*2908d778SJames Bottomley 356*2908d778SJames Bottomley for (i = PAUSE_TRIES*100; i > 0; i--) { 357*2908d778SJames Bottomley u32 dmadone = asd_read_reg_dword(asd_ha, OVLYDMACTL); 358*2908d778SJames Bottomley if (!(dmadone & OVLYDMAACT)) 359*2908d778SJames Bottomley break; 360*2908d778SJames Bottomley udelay(PAUSE_DELAY); 361*2908d778SJames Bottomley } 362*2908d778SJames Bottomley } 363*2908d778SJames Bottomley 364*2908d778SJames Bottomley reg = asd_read_reg_dword(asd_ha, COMSTAT); 365*2908d778SJames Bottomley if (!(reg & OVLYDMADONE) || (reg & OVLYERR) 366*2908d778SJames Bottomley || (asd_read_reg_dword(asd_ha, CHIMINT) & DEVEXCEPT_MASK)){ 367*2908d778SJames Bottomley asd_printk("%s: error DMA-ing sequencer code\n", 368*2908d778SJames Bottomley pci_name(asd_ha->pcidev)); 369*2908d778SJames Bottomley err = -ENODEV; 370*2908d778SJames Bottomley } 371*2908d778SJames Bottomley 372*2908d778SJames Bottomley asd_free_coherent(asd_ha, token); 373*2908d778SJames Bottomley out: 374*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, COMSTATEN, comstaten); 375*2908d778SJames Bottomley 376*2908d778SJames Bottomley return err ? : asd_verify_seq(asd_ha, prog, size, lseq_mask); 377*2908d778SJames Bottomley } 378*2908d778SJames Bottomley #else /* ASD_DMA_MODE_DOWNLOAD */ 379*2908d778SJames Bottomley static int asd_download_seq(struct asd_ha_struct *asd_ha, const u8 *_prog, 380*2908d778SJames Bottomley u32 size, u8 lseq_mask) 381*2908d778SJames Bottomley { 382*2908d778SJames Bottomley int i; 383*2908d778SJames Bottomley u32 reg = 0; 384*2908d778SJames Bottomley const u32 *prog = (u32 *) _prog; 385*2908d778SJames Bottomley 386*2908d778SJames Bottomley if (size % 4) { 387*2908d778SJames Bottomley asd_printk("sequencer program not multiple of 4\n"); 388*2908d778SJames Bottomley return -1; 389*2908d778SJames Bottomley } 390*2908d778SJames Bottomley 391*2908d778SJames Bottomley asd_pause_cseq(asd_ha); 392*2908d778SJames Bottomley asd_pause_lseq(asd_ha, 0xFF); 393*2908d778SJames Bottomley 394*2908d778SJames Bottomley reg |= (lseq_mask ? (((u32)lseq_mask) << 8) : OVLYCSEQ); 395*2908d778SJames Bottomley reg |= PIOCMODE; 396*2908d778SJames Bottomley 397*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, OVLYDMACNT, size); 398*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); 399*2908d778SJames Bottomley 400*2908d778SJames Bottomley ASD_DPRINTK("downloading %s sequencer%s in PIO mode...\n", 401*2908d778SJames Bottomley lseq_mask ? "LSEQ" : "CSEQ", lseq_mask ? "s" : ""); 402*2908d778SJames Bottomley 403*2908d778SJames Bottomley for (i = 0; i < size; i += 4, prog++) 404*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, SPIODATA, *prog); 405*2908d778SJames Bottomley 406*2908d778SJames Bottomley reg = (reg & ~PIOCMODE) | OVLYHALTERR; 407*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, OVLYDMACTL, reg); 408*2908d778SJames Bottomley 409*2908d778SJames Bottomley return asd_verify_seq(asd_ha, _prog, size, lseq_mask); 410*2908d778SJames Bottomley } 411*2908d778SJames Bottomley #endif /* ASD_DMA_MODE_DOWNLOAD */ 412*2908d778SJames Bottomley 413*2908d778SJames Bottomley /** 414*2908d778SJames Bottomley * asd_seq_download_seqs - download the sequencer microcode 415*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 416*2908d778SJames Bottomley * 417*2908d778SJames Bottomley * Download the central and link sequencer microcode. 418*2908d778SJames Bottomley */ 419*2908d778SJames Bottomley static int asd_seq_download_seqs(struct asd_ha_struct *asd_ha) 420*2908d778SJames Bottomley { 421*2908d778SJames Bottomley int err; 422*2908d778SJames Bottomley 423*2908d778SJames Bottomley if (!asd_ha->hw_prof.enabled_phys) { 424*2908d778SJames Bottomley asd_printk("%s: no enabled phys!\n", pci_name(asd_ha->pcidev)); 425*2908d778SJames Bottomley return -ENODEV; 426*2908d778SJames Bottomley } 427*2908d778SJames Bottomley 428*2908d778SJames Bottomley /* Download the CSEQ */ 429*2908d778SJames Bottomley ASD_DPRINTK("downloading CSEQ...\n"); 430*2908d778SJames Bottomley err = asd_download_seq(asd_ha, cseq_code, cseq_code_size, 0); 431*2908d778SJames Bottomley if (err) { 432*2908d778SJames Bottomley asd_printk("CSEQ download failed:%d\n", err); 433*2908d778SJames Bottomley return err; 434*2908d778SJames Bottomley } 435*2908d778SJames Bottomley 436*2908d778SJames Bottomley /* Download the Link Sequencers code. All of the Link Sequencers 437*2908d778SJames Bottomley * microcode can be downloaded at the same time. 438*2908d778SJames Bottomley */ 439*2908d778SJames Bottomley ASD_DPRINTK("downloading LSEQs...\n"); 440*2908d778SJames Bottomley err = asd_download_seq(asd_ha, lseq_code, lseq_code_size, 441*2908d778SJames Bottomley asd_ha->hw_prof.enabled_phys); 442*2908d778SJames Bottomley if (err) { 443*2908d778SJames Bottomley /* Try it one at a time */ 444*2908d778SJames Bottomley u8 lseq; 445*2908d778SJames Bottomley u8 lseq_mask = asd_ha->hw_prof.enabled_phys; 446*2908d778SJames Bottomley 447*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) { 448*2908d778SJames Bottomley err = asd_download_seq(asd_ha, lseq_code, 449*2908d778SJames Bottomley lseq_code_size, 1<<lseq); 450*2908d778SJames Bottomley if (err) 451*2908d778SJames Bottomley break; 452*2908d778SJames Bottomley } 453*2908d778SJames Bottomley } 454*2908d778SJames Bottomley if (err) 455*2908d778SJames Bottomley asd_printk("LSEQs download failed:%d\n", err); 456*2908d778SJames Bottomley 457*2908d778SJames Bottomley return err; 458*2908d778SJames Bottomley } 459*2908d778SJames Bottomley 460*2908d778SJames Bottomley /* ---------- Initializing the chip, chip memory, etc. ---------- */ 461*2908d778SJames Bottomley 462*2908d778SJames Bottomley /** 463*2908d778SJames Bottomley * asd_init_cseq_mip - initialize CSEQ mode independent pages 4-7 464*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 465*2908d778SJames Bottomley */ 466*2908d778SJames Bottomley static void asd_init_cseq_mip(struct asd_ha_struct *asd_ha) 467*2908d778SJames Bottomley { 468*2908d778SJames Bottomley /* CSEQ Mode Independent, page 4 setup. */ 469*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_EXE_HEAD, 0xFFFF); 470*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_EXE_TAIL, 0xFFFF); 471*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_DONE_HEAD, 0xFFFF); 472*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_DONE_TAIL, 0xFFFF); 473*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_SEND_HEAD, 0xFFFF); 474*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_SEND_TAIL, 0xFFFF); 475*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_HEAD, 0xFFFF); 476*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_DMA2CHIM_TAIL, 0xFFFF); 477*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_COPY_HEAD, 0xFFFF); 478*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_COPY_TAIL, 0xFFFF); 479*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_REG0, 0); 480*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_REG1, 0); 481*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_REG2, 0); 482*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_LINK_CTL_Q_MAP, 0); 483*2908d778SJames Bottomley { 484*2908d778SJames Bottomley u8 con = asd_read_reg_byte(asd_ha, CCONEXIST); 485*2908d778SJames Bottomley u8 val = hweight8(con); 486*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_MAX_CSEQ_MODE, (val<<4)|val); 487*2908d778SJames Bottomley } 488*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_FREE_LIST_HACK_COUNT, 0); 489*2908d778SJames Bottomley 490*2908d778SJames Bottomley /* CSEQ Mode independent, page 5 setup. */ 491*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE, 0); 492*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_QUEUE+4, 0); 493*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT, 0); 494*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EST_NEXUS_REQ_COUNT+4, 0); 495*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_HEAD, 0xFFFF); 496*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_EST_NEXUS_TAIL, 0xFFFF); 497*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_NEED_EST_NEXUS_SCB, 0); 498*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_HEAD, 0); 499*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_REQ_TAIL, 0); 500*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_EST_NEXUS_SCB_OFFSET, 0); 501*2908d778SJames Bottomley 502*2908d778SJames Bottomley /* CSEQ Mode independent, page 6 setup. */ 503*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR0, 0); 504*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_RET_ADDR1, 0); 505*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_INT_ROUT_SCBPTR, 0); 506*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_INT_ROUT_MODE, 0); 507*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_ISR_SCRATCH_FLAGS, 0); 508*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_SINDEX, 0); 509*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_ISR_SAVE_DINDEX, 0); 510*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_HEAD, 0xFFFF); 511*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_MONIRTT_TAIL, 0xFFFF); 512*2908d778SJames Bottomley /* Calculate the free scb mask. */ 513*2908d778SJames Bottomley { 514*2908d778SJames Bottomley u16 cmdctx = asd_get_cmdctx_size(asd_ha); 515*2908d778SJames Bottomley cmdctx = (~((cmdctx/128)-1)) >> 8; 516*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_FREE_SCB_MASK, (u8)cmdctx); 517*2908d778SJames Bottomley } 518*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_HEAD, 519*2908d778SJames Bottomley first_scb_site_no); 520*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_BUILTIN_FREE_SCB_TAIL, 521*2908d778SJames Bottomley last_scb_site_no); 522*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_HEAD, 0xFFFF); 523*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_EXTENDED_FREE_SCB_TAIL, 0xFFFF); 524*2908d778SJames Bottomley 525*2908d778SJames Bottomley /* CSEQ Mode independent, page 7 setup. */ 526*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE, 0); 527*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_QUEUE+4, 0); 528*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT, 0); 529*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_EMPTY_REQ_COUNT+4, 0); 530*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_HEAD, 0xFFFF); 531*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_Q_EMPTY_TAIL, 0xFFFF); 532*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_NEED_EMPTY_SCB, 0); 533*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_HEAD, 0); 534*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_EMPTY_REQ_TAIL, 0); 535*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_EMPTY_SCB_OFFSET, 0); 536*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_PRIMITIVE_DATA, 0); 537*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_TIMEOUT_CONST, 0); 538*2908d778SJames Bottomley } 539*2908d778SJames Bottomley 540*2908d778SJames Bottomley /** 541*2908d778SJames Bottomley * asd_init_cseq_mdp - initialize CSEQ Mode dependent pages 542*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 543*2908d778SJames Bottomley */ 544*2908d778SJames Bottomley static void asd_init_cseq_mdp(struct asd_ha_struct *asd_ha) 545*2908d778SJames Bottomley { 546*2908d778SJames Bottomley int i; 547*2908d778SJames Bottomley int moffs; 548*2908d778SJames Bottomley 549*2908d778SJames Bottomley moffs = CSEQ_PAGE_SIZE * 2; 550*2908d778SJames Bottomley 551*2908d778SJames Bottomley /* CSEQ Mode dependent, modes 0-7, page 0 setup. */ 552*2908d778SJames Bottomley for (i = 0; i < 8; i++) { 553*2908d778SJames Bottomley asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SINDEX, 0); 554*2908d778SJames Bottomley asd_write_reg_word(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCBPTR, 0); 555*2908d778SJames Bottomley asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_HEAD, 0xFFFF); 556*2908d778SJames Bottomley asd_write_reg_word(asd_ha, i*moffs+CSEQ_Q_LINK_TAIL, 0xFFFF); 557*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, i*moffs+CSEQ_LRM_SAVE_SCRPAGE, 0); 558*2908d778SJames Bottomley } 559*2908d778SJames Bottomley 560*2908d778SJames Bottomley /* CSEQ Mode dependent, mode 0-7, page 1 and 2 shall be ignored. */ 561*2908d778SJames Bottomley 562*2908d778SJames Bottomley /* CSEQ Mode dependent, mode 8, page 0 setup. */ 563*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_RET_ADDR, 0xFFFF); 564*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_RET_SCBPTR, 0); 565*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_SAVE_SCBPTR, 0); 566*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_EMPTY_TRANS_CTX, 0); 567*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_RESP_LEN, 0); 568*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_TMF_SCBPTR, 0); 569*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_GLOBAL_PREV_SCB, 0); 570*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_GLOBAL_HEAD, 0); 571*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_CLEAR_LU_HEAD, 0); 572*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_TMF_OPCODE, 0); 573*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_SCRATCH_FLAGS, 0); 574*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_HSB_SITE, 0); 575*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_SCB_SITE, 576*2908d778SJames Bottomley (u16)last_scb_site_no+1); 577*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CSEQ_FIRST_INV_DDB_SITE, 578*2908d778SJames Bottomley (u16)asd_ha->hw_prof.max_ddbs); 579*2908d778SJames Bottomley 580*2908d778SJames Bottomley /* CSEQ Mode dependent, mode 8, page 1 setup. */ 581*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR, 0); 582*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CLEAR + 4, 0); 583*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK, 0); 584*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_LUN_TO_CHECK + 4, 0); 585*2908d778SJames Bottomley 586*2908d778SJames Bottomley /* CSEQ Mode dependent, mode 8, page 2 setup. */ 587*2908d778SJames Bottomley /* Tell the sequencer the bus address of the first SCB. */ 588*2908d778SJames Bottomley asd_write_reg_addr(asd_ha, CSEQ_HQ_NEW_POINTER, 589*2908d778SJames Bottomley asd_ha->seq.next_scb.dma_handle); 590*2908d778SJames Bottomley ASD_DPRINTK("First SCB dma_handle: 0x%llx\n", 591*2908d778SJames Bottomley (unsigned long long)asd_ha->seq.next_scb.dma_handle); 592*2908d778SJames Bottomley 593*2908d778SJames Bottomley /* Tell the sequencer the first Done List entry address. */ 594*2908d778SJames Bottomley asd_write_reg_addr(asd_ha, CSEQ_HQ_DONE_BASE, 595*2908d778SJames Bottomley asd_ha->seq.actual_dl->dma_handle); 596*2908d778SJames Bottomley 597*2908d778SJames Bottomley /* Initialize the Q_DONE_POINTER with the least significant 598*2908d778SJames Bottomley * 4 bytes of the first Done List address. */ 599*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQ_HQ_DONE_POINTER, 600*2908d778SJames Bottomley ASD_BUSADDR_LO(asd_ha->seq.actual_dl->dma_handle)); 601*2908d778SJames Bottomley 602*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQ_HQ_DONE_PASS, ASD_DEF_DL_TOGGLE); 603*2908d778SJames Bottomley 604*2908d778SJames Bottomley /* CSEQ Mode dependent, mode 8, page 3 shall be ignored. */ 605*2908d778SJames Bottomley } 606*2908d778SJames Bottomley 607*2908d778SJames Bottomley /** 608*2908d778SJames Bottomley * asd_init_cseq_scratch -- setup and init CSEQ 609*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 610*2908d778SJames Bottomley * 611*2908d778SJames Bottomley * Setup and initialize Central sequencers. Initialiaze the mode 612*2908d778SJames Bottomley * independent and dependent scratch page to the default settings. 613*2908d778SJames Bottomley */ 614*2908d778SJames Bottomley static void asd_init_cseq_scratch(struct asd_ha_struct *asd_ha) 615*2908d778SJames Bottomley { 616*2908d778SJames Bottomley asd_init_cseq_mip(asd_ha); 617*2908d778SJames Bottomley asd_init_cseq_mdp(asd_ha); 618*2908d778SJames Bottomley } 619*2908d778SJames Bottomley 620*2908d778SJames Bottomley /** 621*2908d778SJames Bottomley * asd_init_lseq_mip -- initialize LSEQ Mode independent pages 0-3 622*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 623*2908d778SJames Bottomley */ 624*2908d778SJames Bottomley static void asd_init_lseq_mip(struct asd_ha_struct *asd_ha, u8 lseq) 625*2908d778SJames Bottomley { 626*2908d778SJames Bottomley int i; 627*2908d778SJames Bottomley 628*2908d778SJames Bottomley /* LSEQ Mode independent page 0 setup. */ 629*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_HEAD(lseq), 0xFFFF); 630*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_Q_TGTXFR_TAIL(lseq), 0xFFFF); 631*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_LINK_NUMBER(lseq), lseq); 632*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SCRATCH_FLAGS(lseq), 633*2908d778SJames Bottomley ASD_NOTIFY_ENABLE_SPINUP); 634*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_CONNECTION_STATE(lseq),0x08000000); 635*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_CONCTL(lseq), 0); 636*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_CONSTAT(lseq), 0); 637*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_CONNECTION_MODES(lseq), 0); 638*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_REG1_ISR(lseq), 0); 639*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_REG2_ISR(lseq), 0); 640*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_REG3_ISR(lseq), 0); 641*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq), 0); 642*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_REG0_ISR(lseq)+4, 0); 643*2908d778SJames Bottomley 644*2908d778SJames Bottomley /* LSEQ Mode independent page 1 setup. */ 645*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR0(lseq), 0xFFFF); 646*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR1(lseq), 0xFFFF); 647*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR2(lseq), 0xFFFF); 648*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EST_NEXUS_SCBPTR3(lseq), 0xFFFF); 649*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE0(lseq), 0); 650*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE1(lseq), 0); 651*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE2(lseq), 0); 652*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_OPCODE3(lseq), 0); 653*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_HEAD(lseq), 0); 654*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_SCB_TAIL(lseq), 0); 655*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EST_NEXUS_BUF_AVAIL(lseq), 0); 656*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_TIMEOUT_CONST(lseq), 0); 657*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_SINDEX(lseq), 0); 658*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_ISR_SAVE_DINDEX(lseq), 0); 659*2908d778SJames Bottomley 660*2908d778SJames Bottomley /* LSEQ Mode Independent page 2 setup. */ 661*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR0(lseq), 0xFFFF); 662*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR1(lseq), 0xFFFF); 663*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR2(lseq), 0xFFFF); 664*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EMPTY_SCB_PTR3(lseq), 0xFFFF); 665*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD0(lseq), 0); 666*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD1(lseq), 0); 667*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD2(lseq), 0); 668*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_OPCD3(lseq), 0); 669*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_HEAD(lseq), 0); 670*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_SCB_TAIL(lseq), 0); 671*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_EMPTY_BUFS_AVAIL(lseq), 0); 672*2908d778SJames Bottomley for (i = 0; i < 12; i += 4) 673*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_ATA_SCR_REGS(lseq) + i, 0); 674*2908d778SJames Bottomley 675*2908d778SJames Bottomley /* LSEQ Mode Independent page 3 setup. */ 676*2908d778SJames Bottomley 677*2908d778SJames Bottomley /* Device present timer timeout */ 678*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TMR_TOUT_CONST(lseq), 679*2908d778SJames Bottomley ASD_DEV_PRESENT_TIMEOUT); 680*2908d778SJames Bottomley 681*2908d778SJames Bottomley /* SATA interlock timer disabled */ 682*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_SATA_INTERLOCK_TIMEOUT(lseq), 683*2908d778SJames Bottomley ASD_SATA_INTERLOCK_TIMEOUT); 684*2908d778SJames Bottomley 685*2908d778SJames Bottomley /* STP shutdown timer timeout constant, IGNORED by the sequencer, 686*2908d778SJames Bottomley * always 0. */ 687*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMEOUT(lseq), 688*2908d778SJames Bottomley ASD_STP_SHUTDOWN_TIMEOUT); 689*2908d778SJames Bottomley 690*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_SRST_ASSERT_TIMEOUT(lseq), 691*2908d778SJames Bottomley ASD_SRST_ASSERT_TIMEOUT); 692*2908d778SJames Bottomley 693*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMEOUT(lseq), 694*2908d778SJames Bottomley ASD_RCV_FIS_TIMEOUT); 695*2908d778SJames Bottomley 696*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_ONE_MILLISEC_TIMEOUT(lseq), 697*2908d778SJames Bottomley ASD_ONE_MILLISEC_TIMEOUT); 698*2908d778SJames Bottomley 699*2908d778SJames Bottomley /* COM_INIT timer */ 700*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_TEN_MS_COMINIT_TIMEOUT(lseq), 701*2908d778SJames Bottomley ASD_TEN_MILLISEC_TIMEOUT); 702*2908d778SJames Bottomley 703*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMEOUT(lseq), 704*2908d778SJames Bottomley ASD_SMP_RCV_TIMEOUT); 705*2908d778SJames Bottomley } 706*2908d778SJames Bottomley 707*2908d778SJames Bottomley /** 708*2908d778SJames Bottomley * asd_init_lseq_mdp -- initialize LSEQ mode dependent pages. 709*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 710*2908d778SJames Bottomley */ 711*2908d778SJames Bottomley static void asd_init_lseq_mdp(struct asd_ha_struct *asd_ha, int lseq) 712*2908d778SJames Bottomley { 713*2908d778SJames Bottomley int i; 714*2908d778SJames Bottomley u32 moffs; 715*2908d778SJames Bottomley u16 ret_addr[] = { 716*2908d778SJames Bottomley 0xFFFF, /* mode 0 */ 717*2908d778SJames Bottomley 0xFFFF, /* mode 1 */ 718*2908d778SJames Bottomley mode2_task, /* mode 2 */ 719*2908d778SJames Bottomley 0, 720*2908d778SJames Bottomley 0xFFFF, /* mode 4/5 */ 721*2908d778SJames Bottomley 0xFFFF, /* mode 4/5 */ 722*2908d778SJames Bottomley }; 723*2908d778SJames Bottomley 724*2908d778SJames Bottomley /* 725*2908d778SJames Bottomley * Mode 0,1,2 and 4/5 have common field on page 0 for the first 726*2908d778SJames Bottomley * 14 bytes. 727*2908d778SJames Bottomley */ 728*2908d778SJames Bottomley for (i = 0; i < 3; i++) { 729*2908d778SJames Bottomley moffs = i * LSEQ_MODE_SCRATCH_SIZE; 730*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR(lseq)+moffs, 731*2908d778SJames Bottomley ret_addr[i]); 732*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_REG0_MODE(lseq)+moffs, 0); 733*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_MODE_FLAGS(lseq)+moffs, 0); 734*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR2(lseq)+moffs,0xFFFF); 735*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_RET_ADDR1(lseq)+moffs,0xFFFF); 736*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_OPCODE_TO_CSEQ(lseq)+moffs,0); 737*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_DATA_TO_CSEQ(lseq)+moffs,0); 738*2908d778SJames Bottomley } 739*2908d778SJames Bottomley /* 740*2908d778SJames Bottomley * Mode 5 page 0 overlaps the same scratch page with Mode 0 page 3. 741*2908d778SJames Bottomley */ 742*2908d778SJames Bottomley asd_write_reg_word(asd_ha, 743*2908d778SJames Bottomley LmSEQ_RET_ADDR(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 744*2908d778SJames Bottomley ret_addr[5]); 745*2908d778SJames Bottomley asd_write_reg_word(asd_ha, 746*2908d778SJames Bottomley LmSEQ_REG0_MODE(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); 747*2908d778SJames Bottomley asd_write_reg_word(asd_ha, 748*2908d778SJames Bottomley LmSEQ_MODE_FLAGS(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); 749*2908d778SJames Bottomley asd_write_reg_word(asd_ha, 750*2908d778SJames Bottomley LmSEQ_RET_ADDR2(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); 751*2908d778SJames Bottomley asd_write_reg_word(asd_ha, 752*2908d778SJames Bottomley LmSEQ_RET_ADDR1(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0xFFFF); 753*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, 754*2908d778SJames Bottomley LmSEQ_OPCODE_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET,0); 755*2908d778SJames Bottomley asd_write_reg_word(asd_ha, 756*2908d778SJames Bottomley LmSEQ_DATA_TO_CSEQ(lseq)+LSEQ_MODE5_PAGE0_OFFSET, 0); 757*2908d778SJames Bottomley 758*2908d778SJames Bottomley /* LSEQ Mode dependent 0, page 0 setup. */ 759*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_DDB_SITE(lseq), 760*2908d778SJames Bottomley (u16)asd_ha->hw_prof.max_ddbs); 761*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_EMPTY_TRANS_CTX(lseq), 0); 762*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_RESP_LEN(lseq), 0); 763*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_FIRST_INV_SCB_SITE(lseq), 764*2908d778SJames Bottomley (u16)last_scb_site_no+1); 765*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq), 766*2908d778SJames Bottomley (u16) LmM0INTEN_MASK & 0xFFFF0000 >> 16); 767*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_INTEN_SAVE(lseq) + 2, 768*2908d778SJames Bottomley (u16) LmM0INTEN_MASK & 0xFFFF); 769*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_FRM_LEN(lseq), 0); 770*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_PROTOCOL(lseq), 0); 771*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_RESP_STATUS(lseq), 0); 772*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_LAST_LOADED_SGE(lseq), 0); 773*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_SAVE_SCBPTR(lseq), 0); 774*2908d778SJames Bottomley 775*2908d778SJames Bottomley /* LSEQ mode dependent, mode 1, page 0 setup. */ 776*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_Q_XMIT_HEAD(lseq), 0xFFFF); 777*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_M1_EMPTY_TRANS_CTX(lseq), 0); 778*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_INI_CONN_TAG(lseq), 0); 779*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_FAILED_OPEN_STATUS(lseq), 0); 780*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_XMIT_REQUEST_TYPE(lseq), 0); 781*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_M1_RESP_STATUS(lseq), 0); 782*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_M1_LAST_LOADED_SGE(lseq), 0); 783*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_M1_SAVE_SCBPTR(lseq), 0); 784*2908d778SJames Bottomley 785*2908d778SJames Bottomley /* LSEQ Mode dependent mode 2, page 0 setup */ 786*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_PORT_COUNTER(lseq), 0); 787*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_PM_TABLE_PTR(lseq), 0); 788*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_SATA_INTERLOCK_TMR_SAVE(lseq), 0); 789*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_IP_BITL(lseq), 0); 790*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_COPY_SMP_CONN_TAG(lseq), 0); 791*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_P0M2_OFFS1AH(lseq), 0); 792*2908d778SJames Bottomley 793*2908d778SJames Bottomley /* LSEQ Mode dependent, mode 4/5, page 0 setup. */ 794*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_STATUS(lseq), 0); 795*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_MODE(lseq), 0); 796*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_Q_LINK_HEAD(lseq), 0xFFFF); 797*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_LINK_RST_ERR(lseq), 0); 798*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SAVED_OOB_SIGNALS(lseq), 0); 799*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SAS_RESET_MODE(lseq), 0); 800*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_LINK_RESET_RETRY_COUNT(lseq), 0); 801*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_NUM_LINK_RESET_RETRIES(lseq), 0); 802*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_OOB_INT_ENABLES(lseq), 0); 803*2908d778SJames Bottomley /* 804*2908d778SJames Bottomley * Set the desired interval between transmissions of the NOTIFY 805*2908d778SJames Bottomley * (ENABLE SPINUP) primitive. Must be initilized to val - 1. 806*2908d778SJames Bottomley */ 807*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_TIMEOUT(lseq), 808*2908d778SJames Bottomley ASD_NOTIFY_TIMEOUT - 1); 809*2908d778SJames Bottomley /* No delay for the first NOTIFY to be sent to the attached target. */ 810*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_NOTIFY_TIMER_DOWN_COUNT(lseq), 811*2908d778SJames Bottomley ASD_NOTIFY_DOWN_COUNT); 812*2908d778SJames Bottomley 813*2908d778SJames Bottomley /* LSEQ Mode dependent, mode 0 and 1, page 1 setup. */ 814*2908d778SJames Bottomley for (i = 0; i < 2; i++) { 815*2908d778SJames Bottomley int j; 816*2908d778SJames Bottomley /* Start from Page 1 of Mode 0 and 1. */ 817*2908d778SJames Bottomley moffs = LSEQ_PAGE_SIZE + i*LSEQ_MODE_SCRATCH_SIZE; 818*2908d778SJames Bottomley /* All the fields of page 1 can be intialized to 0. */ 819*2908d778SJames Bottomley for (j = 0; j < LSEQ_PAGE_SIZE; j += 4) 820*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSCRATCH(lseq)+moffs+j,0); 821*2908d778SJames Bottomley } 822*2908d778SJames Bottomley 823*2908d778SJames Bottomley /* LSEQ Mode dependent, mode 2, page 1 setup. */ 824*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_INVALID_DWORD_COUNT(lseq), 0); 825*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_DISPARITY_ERROR_COUNT(lseq), 0); 826*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_LOSS_OF_SYNC_COUNT(lseq), 0); 827*2908d778SJames Bottomley 828*2908d778SJames Bottomley /* LSEQ Mode dependent, mode 4/5, page 1. */ 829*2908d778SJames Bottomley for (i = 0; i < LSEQ_PAGE_SIZE; i+=4) 830*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq)+i, 0); 831*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_FRAME_TYPE_MASK(lseq), 0xFF); 832*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq), 0xFF); 833*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+1,0xFF); 834*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_HASHED_DEST_ADDR_MASK(lseq)+2,0xFF); 835*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq), 0xFF); 836*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+1, 0xFF); 837*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_HASHED_SRC_ADDR_MASK(lseq)+2, 0xFF); 838*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_DATA_OFFSET(lseq), 0xFFFFFFFF); 839*2908d778SJames Bottomley 840*2908d778SJames Bottomley /* LSEQ Mode dependent, mode 0, page 2 setup. */ 841*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_SMP_RCV_TIMER_TERM_TS(lseq), 0); 842*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_DEVICE_BITS(lseq), 0); 843*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmSEQ_SDB_DDB(lseq), 0); 844*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SDB_NUM_TAGS(lseq), 0); 845*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSEQ_SDB_CURR_TAG(lseq), 0); 846*2908d778SJames Bottomley 847*2908d778SJames Bottomley /* LSEQ Mode Dependent 1, page 2 setup. */ 848*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq), 0); 849*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_TX_ID_ADDR_FRAME(lseq)+4, 0); 850*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_OPEN_TIMER_TERM_TS(lseq), 0); 851*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_SRST_AS_TIMER_TERM_TS(lseq), 0); 852*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_LAST_LOADED_SG_EL(lseq), 0); 853*2908d778SJames Bottomley 854*2908d778SJames Bottomley /* LSEQ Mode Dependent 2, page 2 setup. */ 855*2908d778SJames Bottomley /* The LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS is IGNORED by the sequencer, 856*2908d778SJames Bottomley * i.e. always 0. */ 857*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_STP_SHUTDOWN_TIMER_TERM_TS(lseq),0); 858*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_CLOSE_TIMER_TERM_TS(lseq), 0); 859*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_BREAK_TIMER_TERM_TS(lseq), 0); 860*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_DWS_RESET_TIMER_TERM_TS(lseq), 0); 861*2908d778SJames Bottomley asd_write_reg_dword(asd_ha,LmSEQ_SATA_INTERLOCK_TIMER_TERM_TS(lseq),0); 862*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_MCTL_TIMER_TERM_TS(lseq), 0); 863*2908d778SJames Bottomley 864*2908d778SJames Bottomley /* LSEQ Mode Dependent 4/5, page 2 setup. */ 865*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_COMINIT_TIMER_TERM_TS(lseq), 0); 866*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_RCV_ID_TIMER_TERM_TS(lseq), 0); 867*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_RCV_FIS_TIMER_TERM_TS(lseq), 0); 868*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmSEQ_DEV_PRES_TIMER_TERM_TS(lseq), 0); 869*2908d778SJames Bottomley } 870*2908d778SJames Bottomley 871*2908d778SJames Bottomley /** 872*2908d778SJames Bottomley * asd_init_lseq_scratch -- setup and init link sequencers 873*2908d778SJames Bottomley * @asd_ha: pointer to host adapter struct 874*2908d778SJames Bottomley */ 875*2908d778SJames Bottomley static void asd_init_lseq_scratch(struct asd_ha_struct *asd_ha) 876*2908d778SJames Bottomley { 877*2908d778SJames Bottomley u8 lseq; 878*2908d778SJames Bottomley u8 lseq_mask; 879*2908d778SJames Bottomley 880*2908d778SJames Bottomley lseq_mask = asd_ha->hw_prof.enabled_phys; 881*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) { 882*2908d778SJames Bottomley asd_init_lseq_mip(asd_ha, lseq); 883*2908d778SJames Bottomley asd_init_lseq_mdp(asd_ha, lseq); 884*2908d778SJames Bottomley } 885*2908d778SJames Bottomley } 886*2908d778SJames Bottomley 887*2908d778SJames Bottomley /** 888*2908d778SJames Bottomley * asd_init_scb_sites -- initialize sequencer SCB sites (memory). 889*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 890*2908d778SJames Bottomley * 891*2908d778SJames Bottomley * This should be done before initializing common CSEQ and LSEQ 892*2908d778SJames Bottomley * scratch since those areas depend on some computed values here, 893*2908d778SJames Bottomley * last_scb_site_no, etc. 894*2908d778SJames Bottomley */ 895*2908d778SJames Bottomley static void asd_init_scb_sites(struct asd_ha_struct *asd_ha) 896*2908d778SJames Bottomley { 897*2908d778SJames Bottomley u16 site_no; 898*2908d778SJames Bottomley u16 max_scbs = 0; 899*2908d778SJames Bottomley 900*2908d778SJames Bottomley for (site_no = asd_ha->hw_prof.max_scbs-1; 901*2908d778SJames Bottomley site_no != (u16) -1; 902*2908d778SJames Bottomley site_no--) { 903*2908d778SJames Bottomley u16 i; 904*2908d778SJames Bottomley 905*2908d778SJames Bottomley /* Initialize all fields in the SCB site to 0. */ 906*2908d778SJames Bottomley for (i = 0; i < ASD_SCB_SIZE; i += 4) 907*2908d778SJames Bottomley asd_scbsite_write_dword(asd_ha, site_no, i, 0); 908*2908d778SJames Bottomley 909*2908d778SJames Bottomley /* Workaround needed by SEQ to fix a SATA issue is to exclude 910*2908d778SJames Bottomley * certain SCB sites from the free list. */ 911*2908d778SJames Bottomley if (!SCB_SITE_VALID(site_no)) 912*2908d778SJames Bottomley continue; 913*2908d778SJames Bottomley 914*2908d778SJames Bottomley if (last_scb_site_no == 0) 915*2908d778SJames Bottomley last_scb_site_no = site_no; 916*2908d778SJames Bottomley 917*2908d778SJames Bottomley /* For every SCB site, we need to initialize the 918*2908d778SJames Bottomley * following fields: Q_NEXT, SCB_OPCODE, SCB_FLAGS, 919*2908d778SJames Bottomley * and SG Element Flag. */ 920*2908d778SJames Bottomley 921*2908d778SJames Bottomley /* Q_NEXT field of the last SCB is invalidated. */ 922*2908d778SJames Bottomley asd_scbsite_write_word(asd_ha, site_no, 0, first_scb_site_no); 923*2908d778SJames Bottomley 924*2908d778SJames Bottomley /* Initialize SCB Site Opcode field to invalid. */ 925*2908d778SJames Bottomley asd_scbsite_write_byte(asd_ha, site_no, 926*2908d778SJames Bottomley offsetof(struct scb_header, opcode), 927*2908d778SJames Bottomley 0xFF); 928*2908d778SJames Bottomley 929*2908d778SJames Bottomley /* Initialize SCB Site Flags field to mean a response 930*2908d778SJames Bottomley * frame has been received. This means inadvertent 931*2908d778SJames Bottomley * frames received to be dropped. */ 932*2908d778SJames Bottomley asd_scbsite_write_byte(asd_ha, site_no, 0x49, 0x01); 933*2908d778SJames Bottomley 934*2908d778SJames Bottomley first_scb_site_no = site_no; 935*2908d778SJames Bottomley max_scbs++; 936*2908d778SJames Bottomley } 937*2908d778SJames Bottomley asd_ha->hw_prof.max_scbs = max_scbs; 938*2908d778SJames Bottomley ASD_DPRINTK("max_scbs:%d\n", asd_ha->hw_prof.max_scbs); 939*2908d778SJames Bottomley ASD_DPRINTK("first_scb_site_no:0x%x\n", first_scb_site_no); 940*2908d778SJames Bottomley ASD_DPRINTK("last_scb_site_no:0x%x\n", last_scb_site_no); 941*2908d778SJames Bottomley } 942*2908d778SJames Bottomley 943*2908d778SJames Bottomley /** 944*2908d778SJames Bottomley * asd_init_cseq_cio - initialize CSEQ CIO registers 945*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 946*2908d778SJames Bottomley */ 947*2908d778SJames Bottomley static void asd_init_cseq_cio(struct asd_ha_struct *asd_ha) 948*2908d778SJames Bottomley { 949*2908d778SJames Bottomley int i; 950*2908d778SJames Bottomley 951*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQCOMINTEN, 0); 952*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQDLCTL, ASD_DL_SIZE_BITS); 953*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQDLOFFS, 0); 954*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSEQDLOFFS+1, 0); 955*2908d778SJames Bottomley asd_ha->seq.scbpro = 0; 956*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, SCBPRO, 0); 957*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CSEQCON, 0); 958*2908d778SJames Bottomley 959*2908d778SJames Bottomley /* Intialize CSEQ Mode 11 Interrupt Vectors. 960*2908d778SJames Bottomley * The addresses are 16 bit wide and in dword units. 961*2908d778SJames Bottomley * The values of their macros are in byte units. 962*2908d778SJames Bottomley * Thus we have to divide by 4. */ 963*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CM11INTVEC0, cseq_vecs[0]); 964*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CM11INTVEC1, cseq_vecs[1]); 965*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CM11INTVEC2, cseq_vecs[2]); 966*2908d778SJames Bottomley 967*2908d778SJames Bottomley /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ 968*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CARP2INTEN, EN_ARP2HALTC); 969*2908d778SJames Bottomley 970*2908d778SJames Bottomley /* Initialize CSEQ Scratch Page to 0x04. */ 971*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CSCRATCHPAGE, 0x04); 972*2908d778SJames Bottomley 973*2908d778SJames Bottomley /* Initialize CSEQ Mode[0-8] Dependent registers. */ 974*2908d778SJames Bottomley /* Initialize Scratch Page to 0. */ 975*2908d778SJames Bottomley for (i = 0; i < 9; i++) 976*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CMnSCRATCHPAGE(i), 0); 977*2908d778SJames Bottomley 978*2908d778SJames Bottomley /* Reset the ARP2 Program Count. */ 979*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); 980*2908d778SJames Bottomley 981*2908d778SJames Bottomley for (i = 0; i < 8; i++) { 982*2908d778SJames Bottomley /* Intialize Mode n Link m Interrupt Enable. */ 983*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CMnINTEN(i), EN_CMnRSPMBXF); 984*2908d778SJames Bottomley /* Initialize Mode n Request Mailbox. */ 985*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CMnREQMBX(i), 0); 986*2908d778SJames Bottomley } 987*2908d778SJames Bottomley } 988*2908d778SJames Bottomley 989*2908d778SJames Bottomley /** 990*2908d778SJames Bottomley * asd_init_lseq_cio -- initialize LmSEQ CIO registers 991*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 992*2908d778SJames Bottomley */ 993*2908d778SJames Bottomley static void asd_init_lseq_cio(struct asd_ha_struct *asd_ha, int lseq) 994*2908d778SJames Bottomley { 995*2908d778SJames Bottomley u8 *sas_addr; 996*2908d778SJames Bottomley int i; 997*2908d778SJames Bottomley 998*2908d778SJames Bottomley /* Enable ARP2HALTC (ARP2 Halted from Halt Code Write). */ 999*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmARP2INTEN(lseq), EN_ARP2HALTC); 1000*2908d778SJames Bottomley 1001*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmSCRATCHPAGE(lseq), 0); 1002*2908d778SJames Bottomley 1003*2908d778SJames Bottomley /* Initialize Mode 0,1, and 2 SCRATCHPAGE to 0. */ 1004*2908d778SJames Bottomley for (i = 0; i < 3; i++) 1005*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, i), 0); 1006*2908d778SJames Bottomley 1007*2908d778SJames Bottomley /* Initialize Mode 5 SCRATCHPAGE to 0. */ 1008*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnSCRATCHPAGE(lseq, 5), 0); 1009*2908d778SJames Bottomley 1010*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmRSPMBX(lseq), 0); 1011*2908d778SJames Bottomley /* Initialize Mode 0,1,2 and 5 Interrupt Enable and 1012*2908d778SJames Bottomley * Interrupt registers. */ 1013*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 0), LmM0INTEN_MASK); 1014*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINT(lseq, 0), 0xFFFFFFFF); 1015*2908d778SJames Bottomley /* Mode 1 */ 1016*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 1), LmM1INTEN_MASK); 1017*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINT(lseq, 1), 0xFFFFFFFF); 1018*2908d778SJames Bottomley /* Mode 2 */ 1019*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 2), LmM2INTEN_MASK); 1020*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINT(lseq, 2), 0xFFFFFFFF); 1021*2908d778SJames Bottomley /* Mode 5 */ 1022*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINTEN(lseq, 5), LmM5INTEN_MASK); 1023*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnINT(lseq, 5), 0xFFFFFFFF); 1024*2908d778SJames Bottomley 1025*2908d778SJames Bottomley /* Enable HW Timer status. */ 1026*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmHWTSTATEN(lseq), LmHWTSTATEN_MASK); 1027*2908d778SJames Bottomley 1028*2908d778SJames Bottomley /* Enable Primitive Status 0 and 1. */ 1029*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmPRIMSTAT0EN(lseq), LmPRIMSTAT0EN_MASK); 1030*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmPRIMSTAT1EN(lseq), LmPRIMSTAT1EN_MASK); 1031*2908d778SJames Bottomley 1032*2908d778SJames Bottomley /* Enable Frame Error. */ 1033*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmFRMERREN(lseq), LmFRMERREN_MASK); 1034*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnHOLDLVL(lseq, 0), 0x50); 1035*2908d778SJames Bottomley 1036*2908d778SJames Bottomley /* Initialize Mode 0 Transfer Level to 512. */ 1037*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 0), LmMnXFRLVL_512); 1038*2908d778SJames Bottomley /* Initialize Mode 1 Transfer Level to 256. */ 1039*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnXFRLVL(lseq, 1), LmMnXFRLVL_256); 1040*2908d778SJames Bottomley 1041*2908d778SJames Bottomley /* Initialize Program Count. */ 1042*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); 1043*2908d778SJames Bottomley 1044*2908d778SJames Bottomley /* Enable Blind SG Move. */ 1045*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMODECTL(lseq), LmBLIND48); 1046*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3SATATIMER(lseq), 1047*2908d778SJames Bottomley ASD_SATA_INTERLOCK_TIMEOUT); 1048*2908d778SJames Bottomley 1049*2908d778SJames Bottomley (void) asd_read_reg_dword(asd_ha, LmREQMBX(lseq)); 1050*2908d778SJames Bottomley 1051*2908d778SJames Bottomley /* Clear Primitive Status 0 and 1. */ 1052*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmPRMSTAT0(lseq), 0xFFFFFFFF); 1053*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmPRMSTAT1(lseq), 0xFFFFFFFF); 1054*2908d778SJames Bottomley 1055*2908d778SJames Bottomley /* Clear HW Timer status. */ 1056*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmHWTSTAT(lseq), 0xFF); 1057*2908d778SJames Bottomley 1058*2908d778SJames Bottomley /* Clear DMA Errors for Mode 0 and 1. */ 1059*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 0), 0xFF); 1060*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnDMAERRS(lseq, 1), 0xFF); 1061*2908d778SJames Bottomley 1062*2908d778SJames Bottomley /* Clear SG DMA Errors for Mode 0 and 1. */ 1063*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 0), 0xFF); 1064*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnSGDMAERRS(lseq, 1), 0xFF); 1065*2908d778SJames Bottomley 1066*2908d778SJames Bottomley /* Clear Mode 0 Buffer Parity Error. */ 1067*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnBUFSTAT(lseq, 0), LmMnBUFPERR); 1068*2908d778SJames Bottomley 1069*2908d778SJames Bottomley /* Clear Mode 0 Frame Error register. */ 1070*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmMnFRMERR(lseq, 0), 0xFFFFFFFF); 1071*2908d778SJames Bottomley 1072*2908d778SJames Bottomley /* Reset LSEQ external interrupt arbiter. */ 1073*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmARP2INTCTL(lseq), RSTINTCTL); 1074*2908d778SJames Bottomley 1075*2908d778SJames Bottomley /* Set the Phy SAS for the LmSEQ WWN. */ 1076*2908d778SJames Bottomley sas_addr = asd_ha->phys[lseq].phy_desc->sas_addr; 1077*2908d778SJames Bottomley for (i = 0; i < SAS_ADDR_SIZE; i++) 1078*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmWWN(lseq) + i, sas_addr[i]); 1079*2908d778SJames Bottomley 1080*2908d778SJames Bottomley /* Set the Transmit Size to 1024 bytes, 0 = 256 Dwords. */ 1081*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnXMTSIZE(lseq, 1), 0); 1082*2908d778SJames Bottomley 1083*2908d778SJames Bottomley /* Set the Bus Inactivity Time Limit Timer. */ 1084*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmBITL_TIMER(lseq), 9); 1085*2908d778SJames Bottomley 1086*2908d778SJames Bottomley /* Enable SATA Port Multiplier. */ 1087*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmMnSATAFS(lseq, 1), 0x80); 1088*2908d778SJames Bottomley 1089*2908d778SJames Bottomley /* Initialize Interrupt Vector[0-10] address in Mode 3. 1090*2908d778SJames Bottomley * See the comment on CSEQ_INT_* */ 1091*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC0(lseq), lseq_vecs[0]); 1092*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC1(lseq), lseq_vecs[1]); 1093*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC2(lseq), lseq_vecs[2]); 1094*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC3(lseq), lseq_vecs[3]); 1095*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC4(lseq), lseq_vecs[4]); 1096*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC5(lseq), lseq_vecs[5]); 1097*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC6(lseq), lseq_vecs[6]); 1098*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC7(lseq), lseq_vecs[7]); 1099*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC8(lseq), lseq_vecs[8]); 1100*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC9(lseq), lseq_vecs[9]); 1101*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmM3INTVEC10(lseq), lseq_vecs[10]); 1102*2908d778SJames Bottomley /* 1103*2908d778SJames Bottomley * Program the Link LED control, applicable only for 1104*2908d778SJames Bottomley * Chip Rev. B or later. 1105*2908d778SJames Bottomley */ 1106*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, LmCONTROL(lseq), 1107*2908d778SJames Bottomley (LEDTIMER | LEDMODE_TXRX | LEDTIMERS_100ms)); 1108*2908d778SJames Bottomley 1109*2908d778SJames Bottomley /* Set the Align Rate for SAS and STP mode. */ 1110*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmM1SASALIGN(lseq), SAS_ALIGN_DEFAULT); 1111*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, LmM1STPALIGN(lseq), STP_ALIGN_DEFAULT); 1112*2908d778SJames Bottomley } 1113*2908d778SJames Bottomley 1114*2908d778SJames Bottomley 1115*2908d778SJames Bottomley /** 1116*2908d778SJames Bottomley * asd_post_init_cseq -- clear CSEQ Mode n Int. status and Response mailbox 1117*2908d778SJames Bottomley * @asd_ha: pointer to host adapter struct 1118*2908d778SJames Bottomley */ 1119*2908d778SJames Bottomley static void asd_post_init_cseq(struct asd_ha_struct *asd_ha) 1120*2908d778SJames Bottomley { 1121*2908d778SJames Bottomley int i; 1122*2908d778SJames Bottomley 1123*2908d778SJames Bottomley for (i = 0; i < 8; i++) 1124*2908d778SJames Bottomley asd_write_reg_dword(asd_ha, CMnINT(i), 0xFFFFFFFF); 1125*2908d778SJames Bottomley for (i = 0; i < 8; i++) 1126*2908d778SJames Bottomley asd_read_reg_dword(asd_ha, CMnRSPMBX(i)); 1127*2908d778SJames Bottomley /* Reset the external interrupt arbiter. */ 1128*2908d778SJames Bottomley asd_write_reg_byte(asd_ha, CARP2INTCTL, RSTINTCTL); 1129*2908d778SJames Bottomley } 1130*2908d778SJames Bottomley 1131*2908d778SJames Bottomley /** 1132*2908d778SJames Bottomley * asd_init_ddb_0 -- initialize DDB 0 1133*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 1134*2908d778SJames Bottomley * 1135*2908d778SJames Bottomley * Initialize DDB site 0 which is used internally by the sequencer. 1136*2908d778SJames Bottomley */ 1137*2908d778SJames Bottomley static void asd_init_ddb_0(struct asd_ha_struct *asd_ha) 1138*2908d778SJames Bottomley { 1139*2908d778SJames Bottomley int i; 1140*2908d778SJames Bottomley 1141*2908d778SJames Bottomley /* Zero out the DDB explicitly */ 1142*2908d778SJames Bottomley for (i = 0; i < sizeof(struct asd_ddb_seq_shared); i+=4) 1143*2908d778SJames Bottomley asd_ddbsite_write_dword(asd_ha, 0, i, 0); 1144*2908d778SJames Bottomley 1145*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1146*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, q_free_ddb_head), 0); 1147*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1148*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, q_free_ddb_tail), 1149*2908d778SJames Bottomley asd_ha->hw_prof.max_ddbs-1); 1150*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1151*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, q_free_ddb_cnt), 0); 1152*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1153*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, q_used_ddb_head), 0xFFFF); 1154*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1155*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, q_used_ddb_tail), 0xFFFF); 1156*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1157*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, shared_mem_lock), 0); 1158*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1159*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, smp_conn_tag), 0); 1160*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1161*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, est_nexus_buf_cnt), 0); 1162*2908d778SJames Bottomley asd_ddbsite_write_word(asd_ha, 0, 1163*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, est_nexus_buf_thresh), 1164*2908d778SJames Bottomley asd_ha->hw_prof.num_phys * 2); 1165*2908d778SJames Bottomley asd_ddbsite_write_byte(asd_ha, 0, 1166*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, settable_max_contexts),0); 1167*2908d778SJames Bottomley asd_ddbsite_write_byte(asd_ha, 0, 1168*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, conn_not_active), 0xFF); 1169*2908d778SJames Bottomley asd_ddbsite_write_byte(asd_ha, 0, 1170*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, phy_is_up), 0x00); 1171*2908d778SJames Bottomley /* DDB 0 is reserved */ 1172*2908d778SJames Bottomley set_bit(0, asd_ha->hw_prof.ddb_bitmap); 1173*2908d778SJames Bottomley } 1174*2908d778SJames Bottomley 1175*2908d778SJames Bottomley /** 1176*2908d778SJames Bottomley * asd_seq_setup_seqs -- setup and initialize central and link sequencers 1177*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 1178*2908d778SJames Bottomley */ 1179*2908d778SJames Bottomley static void asd_seq_setup_seqs(struct asd_ha_struct *asd_ha) 1180*2908d778SJames Bottomley { 1181*2908d778SJames Bottomley int lseq; 1182*2908d778SJames Bottomley u8 lseq_mask; 1183*2908d778SJames Bottomley 1184*2908d778SJames Bottomley /* Initialize SCB sites. Done first to compute some values which 1185*2908d778SJames Bottomley * the rest of the init code depends on. */ 1186*2908d778SJames Bottomley asd_init_scb_sites(asd_ha); 1187*2908d778SJames Bottomley 1188*2908d778SJames Bottomley /* Initialize CSEQ Scratch RAM registers. */ 1189*2908d778SJames Bottomley asd_init_cseq_scratch(asd_ha); 1190*2908d778SJames Bottomley 1191*2908d778SJames Bottomley /* Initialize LmSEQ Scratch RAM registers. */ 1192*2908d778SJames Bottomley asd_init_lseq_scratch(asd_ha); 1193*2908d778SJames Bottomley 1194*2908d778SJames Bottomley /* Initialize CSEQ CIO registers. */ 1195*2908d778SJames Bottomley asd_init_cseq_cio(asd_ha); 1196*2908d778SJames Bottomley 1197*2908d778SJames Bottomley asd_init_ddb_0(asd_ha); 1198*2908d778SJames Bottomley 1199*2908d778SJames Bottomley /* Initialize LmSEQ CIO registers. */ 1200*2908d778SJames Bottomley lseq_mask = asd_ha->hw_prof.enabled_phys; 1201*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) 1202*2908d778SJames Bottomley asd_init_lseq_cio(asd_ha, lseq); 1203*2908d778SJames Bottomley asd_post_init_cseq(asd_ha); 1204*2908d778SJames Bottomley } 1205*2908d778SJames Bottomley 1206*2908d778SJames Bottomley 1207*2908d778SJames Bottomley /** 1208*2908d778SJames Bottomley * asd_seq_start_cseq -- start the central sequencer, CSEQ 1209*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 1210*2908d778SJames Bottomley */ 1211*2908d778SJames Bottomley static int asd_seq_start_cseq(struct asd_ha_struct *asd_ha) 1212*2908d778SJames Bottomley { 1213*2908d778SJames Bottomley /* Reset the ARP2 instruction to location zero. */ 1214*2908d778SJames Bottomley asd_write_reg_word(asd_ha, CPRGMCNT, cseq_idle_loop); 1215*2908d778SJames Bottomley 1216*2908d778SJames Bottomley /* Unpause the CSEQ */ 1217*2908d778SJames Bottomley return asd_unpause_cseq(asd_ha); 1218*2908d778SJames Bottomley } 1219*2908d778SJames Bottomley 1220*2908d778SJames Bottomley /** 1221*2908d778SJames Bottomley * asd_seq_start_lseq -- start a link sequencer 1222*2908d778SJames Bottomley * @asd_ha: pointer to host adapter structure 1223*2908d778SJames Bottomley * @lseq: the link sequencer of interest 1224*2908d778SJames Bottomley */ 1225*2908d778SJames Bottomley static int asd_seq_start_lseq(struct asd_ha_struct *asd_ha, int lseq) 1226*2908d778SJames Bottomley { 1227*2908d778SJames Bottomley /* Reset the ARP2 instruction to location zero. */ 1228*2908d778SJames Bottomley asd_write_reg_word(asd_ha, LmPRGMCNT(lseq), lseq_idle_loop); 1229*2908d778SJames Bottomley 1230*2908d778SJames Bottomley /* Unpause the LmSEQ */ 1231*2908d778SJames Bottomley return asd_seq_unpause_lseq(asd_ha, lseq); 1232*2908d778SJames Bottomley } 1233*2908d778SJames Bottomley 1234*2908d778SJames Bottomley static int asd_request_firmware(struct asd_ha_struct *asd_ha) 1235*2908d778SJames Bottomley { 1236*2908d778SJames Bottomley int err, i; 1237*2908d778SJames Bottomley struct sequencer_file_header header, *hdr_ptr; 1238*2908d778SJames Bottomley u32 csum = 0; 1239*2908d778SJames Bottomley u16 *ptr_cseq_vecs, *ptr_lseq_vecs; 1240*2908d778SJames Bottomley 1241*2908d778SJames Bottomley if (sequencer_fw) 1242*2908d778SJames Bottomley /* already loaded */ 1243*2908d778SJames Bottomley return 0; 1244*2908d778SJames Bottomley 1245*2908d778SJames Bottomley err = request_firmware(&sequencer_fw, 1246*2908d778SJames Bottomley SAS_RAZOR_SEQUENCER_FW_FILE, 1247*2908d778SJames Bottomley &asd_ha->pcidev->dev); 1248*2908d778SJames Bottomley if (err) 1249*2908d778SJames Bottomley return err; 1250*2908d778SJames Bottomley 1251*2908d778SJames Bottomley hdr_ptr = (struct sequencer_file_header *)sequencer_fw->data; 1252*2908d778SJames Bottomley 1253*2908d778SJames Bottomley header.csum = le32_to_cpu(hdr_ptr->csum); 1254*2908d778SJames Bottomley header.major = le32_to_cpu(hdr_ptr->major); 1255*2908d778SJames Bottomley header.minor = le32_to_cpu(hdr_ptr->minor); 1256*2908d778SJames Bottomley sequencer_version = hdr_ptr->version; 1257*2908d778SJames Bottomley header.cseq_table_offset = le32_to_cpu(hdr_ptr->cseq_table_offset); 1258*2908d778SJames Bottomley header.cseq_table_size = le32_to_cpu(hdr_ptr->cseq_table_size); 1259*2908d778SJames Bottomley header.lseq_table_offset = le32_to_cpu(hdr_ptr->lseq_table_offset); 1260*2908d778SJames Bottomley header.lseq_table_size = le32_to_cpu(hdr_ptr->lseq_table_size); 1261*2908d778SJames Bottomley header.cseq_code_offset = le32_to_cpu(hdr_ptr->cseq_code_offset); 1262*2908d778SJames Bottomley header.cseq_code_size = le32_to_cpu(hdr_ptr->cseq_code_size); 1263*2908d778SJames Bottomley header.lseq_code_offset = le32_to_cpu(hdr_ptr->lseq_code_offset); 1264*2908d778SJames Bottomley header.lseq_code_size = le32_to_cpu(hdr_ptr->lseq_code_size); 1265*2908d778SJames Bottomley header.mode2_task = le16_to_cpu(hdr_ptr->mode2_task); 1266*2908d778SJames Bottomley header.cseq_idle_loop = le16_to_cpu(hdr_ptr->cseq_idle_loop); 1267*2908d778SJames Bottomley header.lseq_idle_loop = le16_to_cpu(hdr_ptr->lseq_idle_loop); 1268*2908d778SJames Bottomley 1269*2908d778SJames Bottomley for (i = sizeof(header.csum); i < sequencer_fw->size; i++) 1270*2908d778SJames Bottomley csum += sequencer_fw->data[i]; 1271*2908d778SJames Bottomley 1272*2908d778SJames Bottomley if (csum != header.csum) { 1273*2908d778SJames Bottomley asd_printk("Firmware file checksum mismatch\n"); 1274*2908d778SJames Bottomley return -EINVAL; 1275*2908d778SJames Bottomley } 1276*2908d778SJames Bottomley 1277*2908d778SJames Bottomley if (header.cseq_table_size != CSEQ_NUM_VECS || 1278*2908d778SJames Bottomley header.lseq_table_size != LSEQ_NUM_VECS) { 1279*2908d778SJames Bottomley asd_printk("Firmware file table size mismatch\n"); 1280*2908d778SJames Bottomley return -EINVAL; 1281*2908d778SJames Bottomley } 1282*2908d778SJames Bottomley 1283*2908d778SJames Bottomley ptr_cseq_vecs = (u16 *)&sequencer_fw->data[header.cseq_table_offset]; 1284*2908d778SJames Bottomley ptr_lseq_vecs = (u16 *)&sequencer_fw->data[header.lseq_table_offset]; 1285*2908d778SJames Bottomley mode2_task = header.mode2_task; 1286*2908d778SJames Bottomley cseq_idle_loop = header.cseq_idle_loop; 1287*2908d778SJames Bottomley lseq_idle_loop = header.lseq_idle_loop; 1288*2908d778SJames Bottomley 1289*2908d778SJames Bottomley for (i = 0; i < CSEQ_NUM_VECS; i++) 1290*2908d778SJames Bottomley cseq_vecs[i] = le16_to_cpu(ptr_cseq_vecs[i]); 1291*2908d778SJames Bottomley 1292*2908d778SJames Bottomley for (i = 0; i < LSEQ_NUM_VECS; i++) 1293*2908d778SJames Bottomley lseq_vecs[i] = le16_to_cpu(ptr_lseq_vecs[i]); 1294*2908d778SJames Bottomley 1295*2908d778SJames Bottomley cseq_code = &sequencer_fw->data[header.cseq_code_offset]; 1296*2908d778SJames Bottomley cseq_code_size = header.cseq_code_size; 1297*2908d778SJames Bottomley lseq_code = &sequencer_fw->data[header.lseq_code_offset]; 1298*2908d778SJames Bottomley lseq_code_size = header.lseq_code_size; 1299*2908d778SJames Bottomley 1300*2908d778SJames Bottomley return 0; 1301*2908d778SJames Bottomley } 1302*2908d778SJames Bottomley 1303*2908d778SJames Bottomley int asd_init_seqs(struct asd_ha_struct *asd_ha) 1304*2908d778SJames Bottomley { 1305*2908d778SJames Bottomley int err; 1306*2908d778SJames Bottomley 1307*2908d778SJames Bottomley err = asd_request_firmware(asd_ha); 1308*2908d778SJames Bottomley 1309*2908d778SJames Bottomley if (err) { 1310*2908d778SJames Bottomley asd_printk("Failed to load sequencer firmware file %s, error %d\n", 1311*2908d778SJames Bottomley SAS_RAZOR_SEQUENCER_FW_FILE, err); 1312*2908d778SJames Bottomley return err; 1313*2908d778SJames Bottomley } 1314*2908d778SJames Bottomley 1315*2908d778SJames Bottomley asd_printk("using sequencer %s\n", sequencer_version); 1316*2908d778SJames Bottomley err = asd_seq_download_seqs(asd_ha); 1317*2908d778SJames Bottomley if (err) { 1318*2908d778SJames Bottomley asd_printk("couldn't download sequencers for %s\n", 1319*2908d778SJames Bottomley pci_name(asd_ha->pcidev)); 1320*2908d778SJames Bottomley return err; 1321*2908d778SJames Bottomley } 1322*2908d778SJames Bottomley 1323*2908d778SJames Bottomley asd_seq_setup_seqs(asd_ha); 1324*2908d778SJames Bottomley 1325*2908d778SJames Bottomley return 0; 1326*2908d778SJames Bottomley } 1327*2908d778SJames Bottomley 1328*2908d778SJames Bottomley int asd_start_seqs(struct asd_ha_struct *asd_ha) 1329*2908d778SJames Bottomley { 1330*2908d778SJames Bottomley int err; 1331*2908d778SJames Bottomley u8 lseq_mask; 1332*2908d778SJames Bottomley int lseq; 1333*2908d778SJames Bottomley 1334*2908d778SJames Bottomley err = asd_seq_start_cseq(asd_ha); 1335*2908d778SJames Bottomley if (err) { 1336*2908d778SJames Bottomley asd_printk("couldn't start CSEQ for %s\n", 1337*2908d778SJames Bottomley pci_name(asd_ha->pcidev)); 1338*2908d778SJames Bottomley return err; 1339*2908d778SJames Bottomley } 1340*2908d778SJames Bottomley 1341*2908d778SJames Bottomley lseq_mask = asd_ha->hw_prof.enabled_phys; 1342*2908d778SJames Bottomley for_each_sequencer(lseq_mask, lseq_mask, lseq) { 1343*2908d778SJames Bottomley err = asd_seq_start_lseq(asd_ha, lseq); 1344*2908d778SJames Bottomley if (err) { 1345*2908d778SJames Bottomley asd_printk("coudln't start LSEQ %d for %s\n", lseq, 1346*2908d778SJames Bottomley pci_name(asd_ha->pcidev)); 1347*2908d778SJames Bottomley return err; 1348*2908d778SJames Bottomley } 1349*2908d778SJames Bottomley } 1350*2908d778SJames Bottomley 1351*2908d778SJames Bottomley return 0; 1352*2908d778SJames Bottomley } 1353*2908d778SJames Bottomley 1354*2908d778SJames Bottomley /** 1355*2908d778SJames Bottomley * asd_update_port_links -- update port_map_by_links and phy_is_up 1356*2908d778SJames Bottomley * @sas_phy: pointer to the phy which has been added to a port 1357*2908d778SJames Bottomley * 1358*2908d778SJames Bottomley * 1) When a link reset has completed and we got BYTES DMAED with a 1359*2908d778SJames Bottomley * valid frame we call this function for that phy, to indicate that 1360*2908d778SJames Bottomley * the phy is up, i.e. we update the phy_is_up in DDB 0. The 1361*2908d778SJames Bottomley * sequencer checks phy_is_up when pending SCBs are to be sent, and 1362*2908d778SJames Bottomley * when an open address frame has been received. 1363*2908d778SJames Bottomley * 1364*2908d778SJames Bottomley * 2) When we know of ports, we call this function to update the map 1365*2908d778SJames Bottomley * of phys participaing in that port, i.e. we update the 1366*2908d778SJames Bottomley * port_map_by_links in DDB 0. When a HARD_RESET primitive has been 1367*2908d778SJames Bottomley * received, the sequencer disables all phys in that port. 1368*2908d778SJames Bottomley * port_map_by_links is also used as the conn_mask byte in the 1369*2908d778SJames Bottomley * initiator/target port DDB. 1370*2908d778SJames Bottomley */ 1371*2908d778SJames Bottomley void asd_update_port_links(struct asd_sas_phy *sas_phy) 1372*2908d778SJames Bottomley { 1373*2908d778SJames Bottomley struct asd_ha_struct *asd_ha = sas_phy->ha->lldd_ha; 1374*2908d778SJames Bottomley const u8 phy_mask = (u8) sas_phy->port->phy_mask; 1375*2908d778SJames Bottomley u8 phy_is_up; 1376*2908d778SJames Bottomley u8 mask; 1377*2908d778SJames Bottomley int i, err; 1378*2908d778SJames Bottomley 1379*2908d778SJames Bottomley for_each_phy(phy_mask, mask, i) 1380*2908d778SJames Bottomley asd_ddbsite_write_byte(asd_ha, 0, 1381*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, 1382*2908d778SJames Bottomley port_map_by_links)+i,phy_mask); 1383*2908d778SJames Bottomley 1384*2908d778SJames Bottomley for (i = 0; i < 12; i++) { 1385*2908d778SJames Bottomley phy_is_up = asd_ddbsite_read_byte(asd_ha, 0, 1386*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, phy_is_up)); 1387*2908d778SJames Bottomley err = asd_ddbsite_update_byte(asd_ha, 0, 1388*2908d778SJames Bottomley offsetof(struct asd_ddb_seq_shared, phy_is_up), 1389*2908d778SJames Bottomley phy_is_up, 1390*2908d778SJames Bottomley phy_is_up | phy_mask); 1391*2908d778SJames Bottomley if (!err) 1392*2908d778SJames Bottomley break; 1393*2908d778SJames Bottomley else if (err == -EFAULT) { 1394*2908d778SJames Bottomley asd_printk("phy_is_up: parity error in DDB 0\n"); 1395*2908d778SJames Bottomley break; 1396*2908d778SJames Bottomley } 1397*2908d778SJames Bottomley } 1398*2908d778SJames Bottomley 1399*2908d778SJames Bottomley if (err) 1400*2908d778SJames Bottomley asd_printk("couldn't update DDB 0:error:%d\n", err); 1401*2908d778SJames Bottomley } 1402