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