linux/drivers/scsi/sym53c8xx_2/sym_fw.c
<<
>>
Prefs
   1/*
   2 * Device driver for the SYMBIOS/LSILOGIC 53C8XX and 53C1010 family 
   3 * of PCI-SCSI IO processors.
   4 *
   5 * Copyright (C) 1999-2001  Gerard Roudier <groudier@free.fr>
   6 *
   7 * This driver is derived from the Linux sym53c8xx driver.
   8 * Copyright (C) 1998-2000  Gerard Roudier
   9 *
  10 * The sym53c8xx driver is derived from the ncr53c8xx driver that had been 
  11 * a port of the FreeBSD ncr driver to Linux-1.2.13.
  12 *
  13 * The original ncr driver has been written for 386bsd and FreeBSD by
  14 *         Wolfgang Stanglmeier        <wolf@cologne.de>
  15 *         Stefan Esser                <se@mi.Uni-Koeln.de>
  16 * Copyright (C) 1994  Wolfgang Stanglmeier
  17 *
  18 * Other major contributions:
  19 *
  20 * NVRAM detection and reading.
  21 * Copyright (C) 1997 Richard Waltham <dormouse@farsrobt.demon.co.uk>
  22 *
  23 *-----------------------------------------------------------------------------
  24 *
  25 * This program is free software; you can redistribute it and/or modify
  26 * it under the terms of the GNU General Public License as published by
  27 * the Free Software Foundation; either version 2 of the License, or
  28 * (at your option) any later version.
  29 *
  30 * This program is distributed in the hope that it will be useful,
  31 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  32 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  33 * GNU General Public License for more details.
  34 *
  35 * You should have received a copy of the GNU General Public License
  36 * along with this program; if not, write to the Free Software
  37 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  38 */
  39
  40#include "sym_glue.h"
  41
  42/*
  43 *  Macros used for all firmwares.
  44 */
  45#define SYM_GEN_A(s, label)     ((short) offsetof(s, label)),
  46#define SYM_GEN_B(s, label)     ((short) offsetof(s, label)),
  47#define SYM_GEN_Z(s, label)     ((short) offsetof(s, label)),
  48#define PADDR_A(label)          SYM_GEN_PADDR_A(struct SYM_FWA_SCR, label)
  49#define PADDR_B(label)          SYM_GEN_PADDR_B(struct SYM_FWB_SCR, label)
  50
  51
  52#if     SYM_CONF_GENERIC_SUPPORT
  53/*
  54 *  Allocate firmware #1 script area.
  55 */
  56#define SYM_FWA_SCR             sym_fw1a_scr
  57#define SYM_FWB_SCR             sym_fw1b_scr
  58#define SYM_FWZ_SCR             sym_fw1z_scr
  59#include "sym_fw1.h"
  60static struct sym_fwa_ofs sym_fw1a_ofs = {
  61        SYM_GEN_FW_A(struct SYM_FWA_SCR)
  62};
  63static struct sym_fwb_ofs sym_fw1b_ofs = {
  64        SYM_GEN_FW_B(struct SYM_FWB_SCR)
  65};
  66static struct sym_fwz_ofs sym_fw1z_ofs = {
  67        SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
  68};
  69#undef  SYM_FWA_SCR
  70#undef  SYM_FWB_SCR
  71#undef  SYM_FWZ_SCR
  72#endif  /* SYM_CONF_GENERIC_SUPPORT */
  73
  74/*
  75 *  Allocate firmware #2 script area.
  76 */
  77#define SYM_FWA_SCR             sym_fw2a_scr
  78#define SYM_FWB_SCR             sym_fw2b_scr
  79#define SYM_FWZ_SCR             sym_fw2z_scr
  80#include "sym_fw2.h"
  81static struct sym_fwa_ofs sym_fw2a_ofs = {
  82        SYM_GEN_FW_A(struct SYM_FWA_SCR)
  83};
  84static struct sym_fwb_ofs sym_fw2b_ofs = {
  85        SYM_GEN_FW_B(struct SYM_FWB_SCR)
  86        SYM_GEN_B(struct SYM_FWB_SCR, start64)
  87        SYM_GEN_B(struct SYM_FWB_SCR, pm_handle)
  88};
  89static struct sym_fwz_ofs sym_fw2z_ofs = {
  90        SYM_GEN_FW_Z(struct SYM_FWZ_SCR)
  91};
  92#undef  SYM_FWA_SCR
  93#undef  SYM_FWB_SCR
  94#undef  SYM_FWZ_SCR
  95
  96#undef  SYM_GEN_A
  97#undef  SYM_GEN_B
  98#undef  SYM_GEN_Z
  99#undef  PADDR_A
 100#undef  PADDR_B
 101
 102#if     SYM_CONF_GENERIC_SUPPORT
 103/*
 104 *  Patch routine for firmware #1.
 105 */
 106static void
 107sym_fw1_patch(struct Scsi_Host *shost)
 108{
 109        struct sym_hcb *np = sym_get_hcb(shost);
 110        struct sym_fw1a_scr *scripta0;
 111        struct sym_fw1b_scr *scriptb0;
 112
 113        scripta0 = (struct sym_fw1a_scr *) np->scripta0;
 114        scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
 115
 116        /*
 117         *  Remove LED support if not needed.
 118         */
 119        if (!(np->features & FE_LED0)) {
 120                scripta0->idle[0]       = cpu_to_scr(SCR_NO_OP);
 121                scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
 122                scripta0->start[0]      = cpu_to_scr(SCR_NO_OP);
 123        }
 124
 125#ifdef SYM_CONF_IARB_SUPPORT
 126        /*
 127         *    If user does not want to use IMMEDIATE ARBITRATION
 128         *    when we are reselected while attempting to arbitrate,
 129         *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
 130         */
 131        if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
 132                scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
 133#endif
 134        /*
 135         *  Patch some data in SCRIPTS.
 136         *  - start and done queue initial bus address.
 137         *  - target bus address table bus address.
 138         */
 139        scriptb0->startpos[0]   = cpu_to_scr(np->squeue_ba);
 140        scriptb0->done_pos[0]   = cpu_to_scr(np->dqueue_ba);
 141        scriptb0->targtbl[0]    = cpu_to_scr(np->targtbl_ba);
 142}
 143#endif  /* SYM_CONF_GENERIC_SUPPORT */
 144
 145/*
 146 *  Patch routine for firmware #2.
 147 */
 148static void
 149sym_fw2_patch(struct Scsi_Host *shost)
 150{
 151        struct sym_data *sym_data = shost_priv(shost);
 152        struct pci_dev *pdev = sym_data->pdev;
 153        struct sym_hcb *np = sym_data->ncb;
 154        struct sym_fw2a_scr *scripta0;
 155        struct sym_fw2b_scr *scriptb0;
 156
 157        scripta0 = (struct sym_fw2a_scr *) np->scripta0;
 158        scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
 159
 160        /*
 161         *  Remove LED support if not needed.
 162         */
 163        if (!(np->features & FE_LED0)) {
 164                scripta0->idle[0]       = cpu_to_scr(SCR_NO_OP);
 165                scripta0->reselected[0] = cpu_to_scr(SCR_NO_OP);
 166                scripta0->start[0]      = cpu_to_scr(SCR_NO_OP);
 167        }
 168
 169#if   SYM_CONF_DMA_ADDRESSING_MODE == 2
 170        /*
 171         *  Remove useless 64 bit DMA specific SCRIPTS, 
 172         *  when this feature is not available.
 173         */
 174        if (!use_dac(np)) {
 175                scripta0->is_dmap_dirty[0] = cpu_to_scr(SCR_NO_OP);
 176                scripta0->is_dmap_dirty[1] = 0;
 177                scripta0->is_dmap_dirty[2] = cpu_to_scr(SCR_NO_OP);
 178                scripta0->is_dmap_dirty[3] = 0;
 179        }
 180#endif
 181
 182#ifdef SYM_CONF_IARB_SUPPORT
 183        /*
 184         *    If user does not want to use IMMEDIATE ARBITRATION
 185         *    when we are reselected while attempting to arbitrate,
 186         *    patch the SCRIPTS accordingly with a SCRIPT NO_OP.
 187         */
 188        if (!SYM_CONF_SET_IARB_ON_ARB_LOST)
 189                scripta0->ungetjob[0] = cpu_to_scr(SCR_NO_OP);
 190#endif
 191        /*
 192         *  Patch some variable in SCRIPTS.
 193         *  - start and done queue initial bus address.
 194         *  - target bus address table bus address.
 195         */
 196        scriptb0->startpos[0]   = cpu_to_scr(np->squeue_ba);
 197        scriptb0->done_pos[0]   = cpu_to_scr(np->dqueue_ba);
 198        scriptb0->targtbl[0]    = cpu_to_scr(np->targtbl_ba);
 199
 200        /*
 201         *  Remove the load of SCNTL4 on reselection if not a C10.
 202         */
 203        if (!(np->features & FE_C10)) {
 204                scripta0->resel_scntl4[0] = cpu_to_scr(SCR_NO_OP);
 205                scripta0->resel_scntl4[1] = cpu_to_scr(0);
 206        }
 207
 208        /*
 209         *  Remove a couple of work-arounds specific to C1010 if 
 210         *  they are not desirable. See `sym_fw2.h' for more details.
 211         */
 212        if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_66 &&
 213              pdev->revision < 0x1 &&
 214              np->pciclk_khz < 60000)) {
 215                scripta0->datao_phase[0] = cpu_to_scr(SCR_NO_OP);
 216                scripta0->datao_phase[1] = cpu_to_scr(0);
 217        }
 218        if (!(pdev->device == PCI_DEVICE_ID_LSI_53C1010_33 /* &&
 219              pdev->revision < 0xff */)) {
 220                scripta0->sel_done[0] = cpu_to_scr(SCR_NO_OP);
 221                scripta0->sel_done[1] = cpu_to_scr(0);
 222        }
 223
 224        /*
 225         *  Patch some other variables in SCRIPTS.
 226         *  These ones are loaded by the SCRIPTS processor.
 227         */
 228        scriptb0->pm0_data_addr[0] =
 229                cpu_to_scr(np->scripta_ba + 
 230                           offsetof(struct sym_fw2a_scr, pm0_data));
 231        scriptb0->pm1_data_addr[0] =
 232                cpu_to_scr(np->scripta_ba + 
 233                           offsetof(struct sym_fw2a_scr, pm1_data));
 234}
 235
 236/*
 237 *  Fill the data area in scripts.
 238 *  To be done for all firmwares.
 239 */
 240static void
 241sym_fw_fill_data (u32 *in, u32 *out)
 242{
 243        int     i;
 244
 245        for (i = 0; i < SYM_CONF_MAX_SG; i++) {
 246                *in++  = SCR_CHMOV_TBL ^ SCR_DATA_IN;
 247                *in++  = offsetof (struct sym_dsb, data[i]);
 248                *out++ = SCR_CHMOV_TBL ^ SCR_DATA_OUT;
 249                *out++ = offsetof (struct sym_dsb, data[i]);
 250        }
 251}
 252
 253/*
 254 *  Setup useful script bus addresses.
 255 *  To be done for all firmwares.
 256 */
 257static void 
 258sym_fw_setup_bus_addresses(struct sym_hcb *np, struct sym_fw *fw)
 259{
 260        u32 *pa;
 261        u_short *po;
 262        int i;
 263
 264        /*
 265         *  Build the bus address table for script A 
 266         *  from the script A offset table.
 267         */
 268        po = (u_short *) fw->a_ofs;
 269        pa = (u32 *) &np->fwa_bas;
 270        for (i = 0 ; i < sizeof(np->fwa_bas)/sizeof(u32) ; i++)
 271                pa[i] = np->scripta_ba + po[i];
 272
 273        /*
 274         *  Same for script B.
 275         */
 276        po = (u_short *) fw->b_ofs;
 277        pa = (u32 *) &np->fwb_bas;
 278        for (i = 0 ; i < sizeof(np->fwb_bas)/sizeof(u32) ; i++)
 279                pa[i] = np->scriptb_ba + po[i];
 280
 281        /*
 282         *  Same for script Z.
 283         */
 284        po = (u_short *) fw->z_ofs;
 285        pa = (u32 *) &np->fwz_bas;
 286        for (i = 0 ; i < sizeof(np->fwz_bas)/sizeof(u32) ; i++)
 287                pa[i] = np->scriptz_ba + po[i];
 288}
 289
 290#if     SYM_CONF_GENERIC_SUPPORT
 291/*
 292 *  Setup routine for firmware #1.
 293 */
 294static void 
 295sym_fw1_setup(struct sym_hcb *np, struct sym_fw *fw)
 296{
 297        struct sym_fw1a_scr *scripta0;
 298        struct sym_fw1b_scr *scriptb0;
 299
 300        scripta0 = (struct sym_fw1a_scr *) np->scripta0;
 301        scriptb0 = (struct sym_fw1b_scr *) np->scriptb0;
 302
 303        /*
 304         *  Fill variable parts in scripts.
 305         */
 306        sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
 307
 308        /*
 309         *  Setup bus addresses used from the C code..
 310         */
 311        sym_fw_setup_bus_addresses(np, fw);
 312}
 313#endif  /* SYM_CONF_GENERIC_SUPPORT */
 314
 315/*
 316 *  Setup routine for firmware #2.
 317 */
 318static void 
 319sym_fw2_setup(struct sym_hcb *np, struct sym_fw *fw)
 320{
 321        struct sym_fw2a_scr *scripta0;
 322        struct sym_fw2b_scr *scriptb0;
 323
 324        scripta0 = (struct sym_fw2a_scr *) np->scripta0;
 325        scriptb0 = (struct sym_fw2b_scr *) np->scriptb0;
 326
 327        /*
 328         *  Fill variable parts in scripts.
 329         */
 330        sym_fw_fill_data(scripta0->data_in, scripta0->data_out);
 331
 332        /*
 333         *  Setup bus addresses used from the C code..
 334         */
 335        sym_fw_setup_bus_addresses(np, fw);
 336}
 337
 338/*
 339 *  Allocate firmware descriptors.
 340 */
 341#if     SYM_CONF_GENERIC_SUPPORT
 342static struct sym_fw sym_fw1 = SYM_FW_ENTRY(sym_fw1, "NCR-generic");
 343#endif  /* SYM_CONF_GENERIC_SUPPORT */
 344static struct sym_fw sym_fw2 = SYM_FW_ENTRY(sym_fw2, "LOAD/STORE-based");
 345
 346/*
 347 *  Find the most appropriate firmware for a chip.
 348 */
 349struct sym_fw * 
 350sym_find_firmware(struct sym_chip *chip)
 351{
 352        if (chip->features & FE_LDSTR)
 353                return &sym_fw2;
 354#if     SYM_CONF_GENERIC_SUPPORT
 355        else if (!(chip->features & (FE_PFEN|FE_NOPM|FE_DAC)))
 356                return &sym_fw1;
 357#endif
 358        else
 359                return NULL;
 360}
 361
 362/*
 363 *  Bind a script to physical addresses.
 364 */
 365void sym_fw_bind_script(struct sym_hcb *np, u32 *start, int len)
 366{
 367        u32 opcode, new, old, tmp1, tmp2;
 368        u32 *end, *cur;
 369        int relocs;
 370
 371        cur = start;
 372        end = start + len/4;
 373
 374        while (cur < end) {
 375
 376                opcode = *cur;
 377
 378                /*
 379                 *  If we forget to change the length
 380                 *  in scripts, a field will be
 381                 *  padded with 0. This is an illegal
 382                 *  command.
 383                 */
 384                if (opcode == 0) {
 385                        printf ("%s: ERROR0 IN SCRIPT at %d.\n",
 386                                sym_name(np), (int) (cur-start));
 387                        ++cur;
 388                        continue;
 389                };
 390
 391                /*
 392                 *  We use the bogus value 0xf00ff00f ;-)
 393                 *  to reserve data area in SCRIPTS.
 394                 */
 395                if (opcode == SCR_DATA_ZERO) {
 396                        *cur++ = 0;
 397                        continue;
 398                }
 399
 400                if (DEBUG_FLAGS & DEBUG_SCRIPT)
 401                        printf ("%d:  <%x>\n", (int) (cur-start),
 402                                (unsigned)opcode);
 403
 404                /*
 405                 *  We don't have to decode ALL commands
 406                 */
 407                switch (opcode >> 28) {
 408                case 0xf:
 409                        /*
 410                         *  LOAD / STORE DSA relative, don't relocate.
 411                         */
 412                        relocs = 0;
 413                        break;
 414                case 0xe:
 415                        /*
 416                         *  LOAD / STORE absolute.
 417                         */
 418                        relocs = 1;
 419                        break;
 420                case 0xc:
 421                        /*
 422                         *  COPY has TWO arguments.
 423                         */
 424                        relocs = 2;
 425                        tmp1 = cur[1];
 426                        tmp2 = cur[2];
 427                        if ((tmp1 ^ tmp2) & 3) {
 428                                printf ("%s: ERROR1 IN SCRIPT at %d.\n",
 429                                        sym_name(np), (int) (cur-start));
 430                        }
 431                        /*
 432                         *  If PREFETCH feature not enabled, remove 
 433                         *  the NO FLUSH bit if present.
 434                         */
 435                        if ((opcode & SCR_NO_FLUSH) &&
 436                            !(np->features & FE_PFEN)) {
 437                                opcode = (opcode & ~SCR_NO_FLUSH);
 438                        }
 439                        break;
 440                case 0x0:
 441                        /*
 442                         *  MOVE/CHMOV (absolute address)
 443                         */
 444                        if (!(np->features & FE_WIDE))
 445                                opcode = (opcode | OPC_MOVE);
 446                        relocs = 1;
 447                        break;
 448                case 0x1:
 449                        /*
 450                         *  MOVE/CHMOV (table indirect)
 451                         */
 452                        if (!(np->features & FE_WIDE))
 453                                opcode = (opcode | OPC_MOVE);
 454                        relocs = 0;
 455                        break;
 456#ifdef SYM_CONF_TARGET_ROLE_SUPPORT
 457                case 0x2:
 458                        /*
 459                         *  MOVE/CHMOV in target role (absolute address)
 460                         */
 461                        opcode &= ~0x20000000;
 462                        if (!(np->features & FE_WIDE))
 463                                opcode = (opcode & ~OPC_TCHMOVE);
 464                        relocs = 1;
 465                        break;
 466                case 0x3:
 467                        /*
 468                         *  MOVE/CHMOV in target role (table indirect)
 469                         */
 470                        opcode &= ~0x20000000;
 471                        if (!(np->features & FE_WIDE))
 472                                opcode = (opcode & ~OPC_TCHMOVE);
 473                        relocs = 0;
 474                        break;
 475#endif
 476                case 0x8:
 477                        /*
 478                         *  JUMP / CALL
 479                         *  don't relocate if relative :-)
 480                         */
 481                        if (opcode & 0x00800000)
 482                                relocs = 0;
 483                        else if ((opcode & 0xf8400000) == 0x80400000)/*JUMP64*/
 484                                relocs = 2;
 485                        else
 486                                relocs = 1;
 487                        break;
 488                case 0x4:
 489                case 0x5:
 490                case 0x6:
 491                case 0x7:
 492                        relocs = 1;
 493                        break;
 494                default:
 495                        relocs = 0;
 496                        break;
 497                };
 498
 499                /*
 500                 *  Scriptify:) the opcode.
 501                 */
 502                *cur++ = cpu_to_scr(opcode);
 503
 504                /*
 505                 *  If no relocation, assume 1 argument 
 506                 *  and just scriptize:) it.
 507                 */
 508                if (!relocs) {
 509                        *cur = cpu_to_scr(*cur);
 510                        ++cur;
 511                        continue;
 512                }
 513
 514                /*
 515                 *  Otherwise performs all needed relocations.
 516                 */
 517                while (relocs--) {
 518                        old = *cur;
 519
 520                        switch (old & RELOC_MASK) {
 521                        case RELOC_REGISTER:
 522                                new = (old & ~RELOC_MASK) + np->mmio_ba;
 523                                break;
 524                        case RELOC_LABEL_A:
 525                                new = (old & ~RELOC_MASK) + np->scripta_ba;
 526                                break;
 527                        case RELOC_LABEL_B:
 528                                new = (old & ~RELOC_MASK) + np->scriptb_ba;
 529                                break;
 530                        case RELOC_SOFTC:
 531                                new = (old & ~RELOC_MASK) + np->hcb_ba;
 532                                break;
 533                        case 0:
 534                                /*
 535                                 *  Don't relocate a 0 address.
 536                                 *  They are mostly used for patched or 
 537                                 *  script self-modified areas.
 538                                 */
 539                                if (old == 0) {
 540                                        new = old;
 541                                        break;
 542                                }
 543                                /* fall through */
 544                        default:
 545                                new = 0;
 546                                panic("sym_fw_bind_script: "
 547                                      "weird relocation %x\n", old);
 548                                break;
 549                        }
 550
 551                        *cur++ = cpu_to_scr(new);
 552                }
 553        };
 554}
 555