home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / PCI Driver Development Kit / • Samples / Driver Samples / SCSI samples / SCSI 950629 / NCR_DriverProject / Src / DriverDoDriverIO.c < prev    next >
Encoding:
Text File  |  1996-08-20  |  39.4 KB  |  1,082 lines  |  [TEXT/MPCC]

  1. /*                                    DriverDoDriverIO.c                                */
  2. /*
  3.  * DriverDoDriverIO.c
  4.  * Copyright © 1994-95 Apple Computer Inc. All rights reserved.
  5.  *    Edit History
  6.  *    1994.10.24    D3    First DDK release (System A2C1)
  7.  *    1994.12.06    A5    Adding enhancements to the driver:
  8.  *                √    Folder and file reorganization (including changes to MakeFile)
  9.  *                √    Retrieve initiator bus ID from the System Registry (NVRAM property)
  10.  *                    There appears to be a bug (either in my iteration code or in
  11.  *                    the Name Registry, so this has been disabled temporarily.
  12.  *                √    (The TestDriver application will set the property for testing)
  13.  *                √    Implement Supersede/Replace (was compiled out)
  14.  *                √    Call SynchronizeIO in NCRRunScript - this needs to be checked
  15.  *                    by engineering to make sure I did this correctly, as it can't
  16.  *                    easily be checked by minimal testing.
  17.  *                √    Bug: Expansion Manager I/O routines need the device base
  18.  *                    address. (Rewrote GetPCICardBaseAddress and fixed expansion
  19.  *                    Manager calls).
  20.  *    -- below the line -- done only if there's time --
  21.  *                √    Handle discontiguous physical memory in PrepareMemoryForIO
  22.  *                    Support disconnect/reselect and, thereby, concurrent I/O.
  23.  *                    Redo the low-level routines so they can be used in a sample SIM.
  24.  *                √    Implement driver logging using a native "Audit" package.
  25.  *                √    Retrieve the power consumption information from the registry.
  26.  *    -- Waiting for A5
  27.  *                √    Implement Secondary Interrupts
  28.  * 1994.12.12 A4    Changes for the A4 DDK Release:
  29.  *                √    MappingTable is now IOPreparationTable
  30.  * 1994.12.18 A5    DriverGestalt.h is missing from this header release. Copied an
  31.  *                    old version to the folder "::PCICIncludes Temp" - this may change.
  32.  * 1994.12.30 A5+    • NCRDriver.h (the public file) now includes some system headers
  33.  *                    so it can be used independently. No substantive changes.
  34.  *                    • NCRRunScript.c now compiles if interrupts are disabled. No
  35.  *                    substantive changes. 
  36.  *                    • Moved the actual scripts from NCRRunScript.c to a separate file.
  37.  *                    • Removed scatter-gather routines from DriverPrepMemoryUtilities.c
  38.  *                    as they haven't been tested. Revised PrepareSimpleMemoryArea to
  39.  *                    follow the logic (if any) in the the develop article.
  40.  *                    • Revised script preparation for clarity (and debugging). The
  41.  *                    script now initializes constant registers.
  42.  *                    • Select (at compilation) either Memory or I/O access; not both.
  43.  *                    • Bug: CTEST0 was being written as a long, it is a byte.
  44.  *                    • Turn off timers to prevent spurious interrupts.
  45.  *                    • Set DSA to a dummy value for Bus Reset script - it doesn't use
  46.  *                    the DSA.
  47.  *                    • Removed the non-interrupt spin-loop from the script runner.
  48.  *                    Added (temporary) Software Interrupt to see if this fixes the
  49.  *                    QueueSecondaryInterrupt problem (it didn't). Turned on the
  50.  *                    watchdog timer code as it no longer crashes.
  51.  *                    • Parameterized watchdog timer (it hangs in A5).
  52.  * 1995.01.04        • Added TEMP_TEST to strip down the algorithm. This turns off
  53.  *                    PrepareMemoryForIO (the physical address is set to the logical
  54.  *                    address) and creates a minimal (successful) script.
  55.  * 1995.01.13        • Secondary interrupts work.
  56.  *                    • Correctly return power consumption by parsing the registry.
  57.  *                    • Removed many DebugStr's and removed TEMP_TEST. 
  58.  * 1995.01.22        Upgraded to A6. Added the LogLibrary functions. Removed all
  59.  *                    SecondaryInterrupt conditional compilations. Redid the way
  60.  *                    that KillIO terminates the current request as it called a
  61.  *                    secondary interrupt handler from "interrupt level" after a
  62.  *                    timeout. Log some information about the current request.
  63.  *                    • The log shows that the NCR chip -- sometimes -- jumps into
  64.  *                    the middle of a script instruction. Can this be a bus problem?
  65.  *                    Hmm, the problem went away on its own.
  66.  * 1995.01.23        • Fixed the NVRAM bug: I was using RegPropertyName rather than
  67.  *                    RegPropertyNameBuf. The former is a pointer to a character string,
  68.  *                    while the latter is a buffer that can hold a property name.
  69.  * 1995.01.24        • Removed the NVRAM bit from the driver options Control call.
  70.  *                    Added set/get initiator id (PBControl sets it, PBStatus gets it).
  71.  *                    • Cleaned up NVRAM handling. DriverReplaceCmd now fetches the
  72.  *                    initiator ID, if it can be found.
  73.  *                    • Completely rewrote PrepareMemoryForIO handling so the driver
  74.  *                    can re-called from an IOCompletion routine. This precludes
  75.  *                    allocating memory in the driver (outside of open/close). This
  76.  *                    is a massive restructuring of the driver. The new organization
  77.  *                    is described below.
  78.  *                    • Removed the DriverOptions control command: it's served its
  79.  *                    purpose, and no longer illustrates any driver-specific functions.
  80.  *                    • Removed the script log control command. The script log is now
  81.  *                    reset on each command. Hmm, the script log is outliving its
  82.  *                    usefulness, now that the LogLibrary works. Maybe it'll be
  83.  *                    the next to go.
  84.  *                    • Removed the temporary string copy definitions.
  85.  * 1995.02.03        Fixed some bugs: my PrepareMemoryForIO code used the wrong
  86.  *                    variable in one place, leading to memory corruption. Also,
  87.  *                    the atomic operation used to recover the current parameter
  88.  *                    block from the per-request record (in CompleteThisRequest)
  89.  *                    had a re-entrancy bug.
  90.  * 1995.02.06        Synchronous I/O seems to work correctly. Asynchronous I/O
  91.  *                    hangs randomly, possibly because of bugs in the NCR-specific
  92.  *                    code. Added DeviceProbe and AAPL,addresses processing.
  93.  *                    • Removed the NCR logging -- I'm relying on the LogLibrary
  94.  *                    for ongoing status logging.
  95.  *                    • Enabled watchdog timers -- the param block changed.
  96.  * 1995.02.08        • Significant changes to support the new driver organization:
  97.  *                    DMA buffers can only be passed in PBRead or PBWrite commands,
  98.  *                    and buffers must be marked with the ioMapBuffer flag in the
  99.  *                    ioPosMode field.
  100.  *                    • Hmm, Asynch I/O now seems to work.
  101.  * 1995.02.21        Missing break at Close switch statement. Added partial
  102.  *                    I/O preparation.
  103.  * 1995.03.08        • Continue testing PrepareMemoryForIO.
  104.  *                    Single-stepping scripts hang in Bus Reset
  105.  *                    • Added DelayForHardware for 12 PCI clock tick stalls.
  106.  *                    • Removed my SwapLong: now using driver services routine.
  107.  *                    • Support DriverGestaltOn(). Replace now stores the driver
  108.  *                    refNum and deviceID.
  109.  *                    • Remove TempCheckpointIO
  110.  * 1995.03.17        • Reimplemented all Name Registry routines to make them
  111.  *                    independent of the NCR driver.
  112.  *                    • Switched to a different NCR card. This has id "pci1000,4"
  113.  *                    and a different CTEST3 value. It differs from the original
  114.  *                    card in that it is 8-bit only (no wide, no fast). It's
  115.  *                    also quite a bit cheaper.
  116.  *                    • The memory leak problem may be in some other application,
  117.  *                    It doesn't seem to appear in my latest testing.
  118.  *                    • Randomly (after a few thousand trials), the watchdog
  119.  *                    timer fires immediately, rather than after the actual
  120.  *                    time (2 seconds in the test program). In reviewing the code,
  121.  *                    there appears to be a potential race condition in the sequence:
  122.  *                    Start watchdog timer then start I/.O, if this is executed
  123.  *                    from "task" level. To prevent this, I moved all I/O start
  124.  *                    to the secondary interrupt task, where it should have been
  125.  *                    all along.
  126.  *                    • SetInterruptTimer requires an interval, rather than an extact
  127.  *                    finish time. This will be fixed in the documentation.
  128.  *                    • An "engineering build" of the ROMS may have fixed the
  129.  *                    SetInterruptTimer problem. Time will tell.
  130.  *                    • Chip initialization was changed to use a read/modify/write
  131.  *                    sequence to preserve the bits that were set by the Expansion
  132.  *                    Manager.
  133.  *                    • The A8 ROMS require that SendSoftwareInterrupt be run
  134.  *                    from the Secondary Interrupt Handler.
  135.  *                    • There is a minor bug in the SendSoftwareInterrupt sequence:
  136.  *                    CancelTimer should record the amount of time remaining so that
  137.  *                    a subsequent timer restart does not reset the watchdog to its
  138.  *                    original value.
  139.  * 1995.03.29        • Still chasing timer and interrupt problems.
  140.  *                    • Restored SetInterruptTimer's documented behavior (timer
  141.  *                    fires at an epoch, not after an interval.
  142.  *                    • Before re-calling for partial preparation, we must update
  143.  *                    the IOTable's firstPrepared.
  144.  *                    • The Secondary Interrupt handler was confusing administration
  145.  *                    status (from CheckpointIO, for example), with the ioResult value
  146.  *                    that should be passed back to me caller. Hence, "selection timeout"
  147.  *                    was returning "Check Condition" status.
  148.  *                    • Use the driver refNum (converted to an OSType) as the default
  149.  *                    log entry identifier.
  150.  * 1995.04.04        • Added a 'sysz' resource (1 Mbyte) to work around a problem
  151.  *                    when logging is enabled: if three devices are installed, only one
  152.  *                    or two actually get activated. Also, device testing seems to
  153.  *                    hang in strange ways. This was not seen with the non-logging
  154.  *                    version. The value may be incorrect. This worked fine. Switching
  155.  *                    to 256 Kbytes -- still working reasonably well.
  156.  * 1995.04.05        • Debugged memory move test. Everything looks correct, but the
  157.  *                    script doesn't work. I noticed that the actual script is not
  158.  *                    32-bit aligned. Added #pragma options align=power to the headers
  159.  *                    to force the memory move script to be 32-bit aligned. If this
  160.  *                    fails, I'll add a padding halfword. Yup, that did it. Unfortunately,
  161.  *                    this means that all programs using the NCR driver must be
  162.  *                    recompiled. One more bug required a slightly more complex
  163.  *                    control flow through the Secondary Interrupt routine, which is
  164.  *                    starting to look a bit messy. Removing (with an editor) all
  165.  *                    of the test and debug junk would probably make it look better.
  166.  *                    • Revised GetDeviceLogicalAddress to use the structure in PCI.h --
  167.  *                    no substantive changes.
  168.  *                    • Some compilers are rumored to handle functions returning
  169.  *                    structures incorrectly. Store UpTime in a volatile local variable
  170.  *                    if it is to be used in a function call.
  171.  *                    • Added a function to write a message into the registry if
  172.  *                    the initialization sequence failed. It seems that I might have
  173.  *                    had a tiny error in the revised GetDeviceLogicalAddress.
  174.  * 1995.04.11        • The driver doesn't work with VM on -- the script is not always
  175.  *                    in physically-contiguous memory. Copy the script to an allocated
  176.  *                    buffer.
  177.  * 1995.04.12        • Added logging to the CheckForContiguousPhysicalMapping function.
  178.  *                    Bug alert: the memory test hangs if memory is not contiguous.
  179.  * 1995.06.28        Checkpoint the I/O buffer before continuing partial preparation.
  180.  *                    Replace the original preparation code by the DMA support library.
  181.  *                    With luck, this will solve the overall partial preparation and
  182.  *                    virtual memory problems.
  183.  *
  184.  * Preparing Memory
  185.  *        There are three active mapping tables; one for the script, one for the
  186.  *        per-request data (including data shared with the NCR chip), and one for the
  187.  *        user's I/O request. They are allocated as follows:
  188.  *        Script:        When the driver is opened, the script is "prepared" and a
  189.  *                    physical mapping table allocated. Also, a physical mapping table
  190.  *                    will allocated for user I/O requests. This uses a maximum transfer
  191.  *                    count parameter that is currently compiled in, but could easily
  192.  *                    be stored in the Name Registry. This data is released when the
  193.  *                    driver is closed.
  194.  *        PerRequest:    One of these will be allocated when the driver is opened. A future
  195.  *                    modification would allocate some larger number to support fully-
  196.  *                    concurrent I/O requests (i.e. to support disconnect/reselect).
  197.  *                    This table is released when the driver is closed.
  198.  *        User:         The user table is built into the PerRequest record. It will be
  199.  *                    initialized and checkpointed on each I/O request. This will not
  200.  *                    allocate or release memory.
  201.  *
  202.  * Misfeatures
  203.  *        The NCR Script design does not permit concurrent I/O operations, which is
  204.  *        not sufficient for a SCSI device.
  205.  *
  206.  * Open bugs
  207.  * ••• There is a problem in my understanding of the NCR chip that prevents KillIO
  208.  *        from working well. It does work, however, but sometimes leaves the bus busy.
  209.  */
  210. /*    .___________________________________________________________________________________.
  211.       | DoDriverIO, after modification, will be useful for other drivers. It shows the    |
  212.       | overall structure of the driver "top-level," calling handler functions for each    |
  213.     | driver operation. You will have to replace much of the actual driver operation    |
  214.     | with code specific to your particular purpose, but the general structure should    |
  215.     | remain the same.                                                                    |
  216.     |                                                                                    |
  217.       | These routines, after modification, will be useful for other drivers.                |
  218.     |    DriverDoDriverIO        Driver mainline. Calls hardware specific routines        |
  219.     |                            or operation-specific functions as necessary.            |
  220.     |    NameRegistryUtilities    Store and retrieve information from the Name Registery    |
  221.     |    DriverPCIBusUtilities    Utilities to read and write data on the PCI bus. There    |
  222.     |                            are functions for the Configuration registers, and for    |
  223.     |                            both Expansion Manager and direct memory access to        |
  224.     |                            chip registers.                                            |
  225.     |     DriverDebugSupport        Some very crude routines for debugging.                    |
  226.     |    DriverGestaltHandler    Process the PBStatus driver gestalt request                |
  227.     |                                                                                    |
  228.     | These routines are specific to the NCR SCSI interface. You will be able to borrow    |
  229.     | code from them, but will probably rewrite these from scratch for your driver's    |
  230.     | specific needs.                                                                    |
  231.     |    NCRChipManager            Utilities to set values in the NCR chip. This shows how    |
  232.     |                            to use the Expansion Manager routines to read and write    |
  233.     |                            device registers.                                        |
  234.     |    NCRStartScript            Prepare to execute a SCSI bus operation.                |
  235.     |    NCRRunScript            Execute a SCSI bus operation. This file includes the    |
  236.     |                            interrupt service routine.                                |
  237.     |                                                                                    |
  238.     | There is a lot of debugging code in this driver. My programming approach is to    |
  239.     | leave debugging code in the source files, but remove it automatically (by            |
  240.     | #ifdef's) from shipping versions. This is especially important for asynchronous    |
  241.     | device drivers, as they are incompatible with interactive debugging.                |
  242.     .___________________________________________________________________________________.
  243. */
  244.  
  245.  
  246. /* DriverDoDriverIO is a device driver framework that operates using the new driver
  247.  * architecture.
  248.  *
  249.  * The following overall code-flow paths are possible:
  250.  *        Immediate Commands:
  251.  *            Process command. Return an error if the request may stall (but do
  252.  *                not execute or otherwise delay the request).
  253.  *            Return the final I/O request status to the caller.
  254.  *        Other commands:
  255.  *            Process the command.
  256.  *                If it is complete (success or failure) without any delay, call
  257.  *                    IOCommandIsComplete(...) to return a result to the caller
  258.  *                    and return noErr to the Device Manager.
  259.  *                If it requires an asynchronous operation, start the operation and
  260.  *                    return noErr to the Device Manager. When the asynchronous
  261.  *                    operation completes, it will call IOCommandIsComplete.
  262.  *
  263.  * Build instructions (MetroWerks PPC)
  264.  *        Processor
  265.  *            Readonly strings            checked
  266.  *        Linker
  267.  *            Initialization                CFMInitialize
  268.  *            Main                        DoDriverIO
  269.  *            Termination                    CFMTerminate
  270.  *        PEF
  271.  *            Export Symbols                Use .exp file to export the following globals
  272.  *                                            TheDriverDescription
  273.  *                                            DoDriverIO
  274.  *            Expand uninitialized data    checked
  275.  *        Project
  276.  *            Project Type                Shared Library
  277.  *            File Name                    NCRDriver
  278.  *            File Creator                PSSD    -- Our registered creator type
  279.  *            File Type                    shlb
  280.  */
  281.  
  282. #include "NCRDriverPrivate.h"
  283.  
  284. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  285.  * We must export a global DriverDescription record that the new Device Manager
  286.  * will use to configure and instantiate our driver.
  287.  */
  288. /*
  289.  * There is a bug in some versions of the MPW PPCC compiler that cause an error if you
  290.  * try to expand fully-bracketed structures -- this structure is constructed from
  291.  * several other structures.
  292.  */
  293. DriverDescription TheDriverDescription = {
  294.     /*
  295.      * Signature info
  296.      */
  297.     kTheDescriptionSignature,                /* OSType driverDescSignature            */
  298.     kInitialDriverDescriptor,                /* DriverDescVersion driverDescVersion    */
  299.     /*
  300.      * DriverType driverType - these are defined in NCR53C825.h
  301.      */
  302.     kPCIDeviceNamePString,                    /* Name of NCR 53C825 hardware             */
  303.     kPCIRevisionID, kVersionMinor,            /* NumVersion version                    */
  304.     kVersionStageValue, kVersionRevision,
  305.     /*
  306.      * DriverOSRuntime driverOSRuntimeInfo
  307.      */
  308.     0                                        /* RuntimeOptions driverRuntime            */
  309.     | (1 * kDriverIsLoadedUponDiscovery)    /* Loader runtime options                */
  310.     | (1 * kDriverIsOpenedUponLoad)            /* Opened when loaded                    */
  311.     | (0 * kDriverIsUnderExpertControl)        /* I/O expert handles loads/opens        */
  312.     | (0 * kDriverIsConcurrent)                /* Not concurrent yet                    */
  313.     | (0 * kDriverQueuesIOPB),                /* Not internally queued yet            */
  314.     kDriverNamePString,                        /* Str31 driverName    (OpenDriver param)    */
  315.     0, 0, 0, 0, 0, 0, 0, 0,                    /* UInt32 driverDescReserved[8]            */
  316.     /*
  317.      * DriverOSService Information. This section contains a vector count followed by
  318.      * a vector of structures, each defining a driver service.
  319.      */
  320.     1,                                        /*     ServiceCount nServices                */
  321.     /*
  322.      * DriverServiceInfo service[0]
  323.      */
  324.     kServiceCategoryNdrvDriver,                /* OSType serviceCategory                */
  325.     kNdrvTypeIsGeneric,                        /* OSType serviceType                    */
  326.     kVersionMajor, kVersionMinor,            /* NumVersion serviceVersion            */
  327.     kVersionStageValue, kVersionRevision,    /* NumVersion serviceVersion            */
  328. };
  329.  
  330. /*
  331.  * All driver-global information is in a structure defined in NCRDriverPrivate.
  332.  * Note that "modern" drivers do not have access to their dce. In native Power PC
  333.  * environments, the global world is created by the Code Fragment Manager (hmm,
  334.  * perhaps it is created by CFMInitialize).
  335.  */
  336. DriverGlobal                gDriverGlobal;
  337. UInt32                        gPageSize;
  338. UInt32                        gPageMask;
  339.  
  340. OSErr                        CFMInitialize(void);
  341. OSErr                        CFMTerminate(void);
  342.  
  343. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  344.  * CFMInitialize is called by the Code Fragment Manager. This would be a good
  345.  * place to make sure that we should load in the first place -- For example,
  346.  * if necessary hardware isn't present, or there is an operating system conflict,
  347.  * we can return an error and not take up any system memory.
  348.  */
  349. OSErr
  350. CFMInitialize(void)
  351. {
  352. #if USE_LOG_LIBRARY
  353.         LogRecordPtr logRecordPtr;
  354.  
  355.         logRecordPtr = MakeLogRecord(kPCIDeviceNameCString, 256);
  356.         WriteLogEntry(logRecordPtr, 'CFMi', LogStringFormat, "\pDriver CFMInitialize");
  357. #endif
  358.         return (noErr);
  359. }
  360.  
  361. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  362.  * CFMTerminate is called by the Code Fragment Manager when the code segment
  363.  * is about to be trashed. It could dispose of any global data that is not
  364.  * managed by DoDriverIO.
  365.  */
  366. OSErr
  367. CFMTerminate(void)
  368. {
  369. #if USE_LOG_LIBRARY
  370.         LogRecordPtr logRecordPtr;
  371.  
  372.         logRecordPtr = GetLogRecordPtr(kPCIDeviceNameCString);
  373.         WriteLogEntry(logRecordPtr, 'CFMt', LogStringFormat, "\pDriver CFMTerminate");
  374. #endif
  375.         return (noErr);
  376. }
  377.  
  378. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  379.  * DoDriverIO
  380.  *
  381.  * In the new driver environment, DoDriverIO performs all driver
  382.  * functions. It is called with the following parameters:
  383.  *    IOCommandID            A unique reference for this driver request. In
  384.  *                        the emulated environment, this will be the ParamBlkPtr
  385.  *                        passed in from the Device Manager.
  386.  *    IOCommandContents    A union structure that contains information for the
  387.  *                        specific request. For the emulated environment, this
  388.  *                        will contain the following:
  389.  *        Initialize            Driver RefNum and the name registry id for this driver.
  390.  *        Finalize            Driver RefNum and the name registry id for this driver. 
  391.  *        Others                The ParamBlkPtr
  392.  *    IOCommandCode        A switch value that specifies the required function.
  393.  *    IOCommandKind        A bit-mask indicating Synchronous, Asynchronous, and Immediate
  394.  *
  395.  * For Synchronous and Immediate commands, DoDriverIO returns the final status to
  396.  * the Device Manager. For Asynchronous commands, DoDriverIO may return kIOBusyStatus.
  397.  * If it returns busy status, the driver promises to call IOCommandIsComplete when
  398.  * the transaction has completed.
  399.  */
  400. OSErr
  401. DoDriverIO(
  402.         AddressSpaceID            addressSpaceID,
  403.         IOCommandID                ioCommandID,
  404.         IOCommandContents        ioCommandContents,
  405.         IOCommandCode            ioCommandCode,
  406.         IOCommandKind            ioCommandKind
  407. )
  408. {
  409.         OSErr                    status;
  410.  
  411.         /*
  412.          * Note: Initialize, Open, KillIO, Close, and Finalize are either synchronous
  413.          * or immediate. Read, Write, Control, and Status may be immediate,
  414.          * synchronous, or asynchronous.
  415.          */
  416.         Trace(DoDriverIO);
  417.         Timestamp('IOS-');                    /* IOS+ is in the application            */
  418.         switch (ioCommandCode) {
  419.         case kInitializeCommand:            /* Always immediate                        */
  420.             //** SysDebugStr("\p Driver Initialize");
  421. #if USE_LOG_LIBRARY
  422.             /*
  423.              * Because we can (indeed, do) have multiple cards running from the same
  424.              * device driver source, we set the default Log identifier to a unique
  425.              * string by converting the device refNum to a right-justified OSType.
  426.              */
  427.             {
  428.                 Str15            work;
  429.                 StringPtr        workPtr;
  430.  
  431.                 work[4] = 0;
  432.                 AppendSigned(&work[4], ioCommandContents.initialInfo->refNum);
  433.                 workPtr = &work[5];
  434.                 switch (work[4]) {                            /* Kids,            */
  435.                 case 0:        work[1] = ' ';    --workPtr;        /* don't            */
  436.                 case 1:        work[2] = ' ';    --workPtr;        /* try                */
  437.                 case 2:        work[3] = ' ';    --workPtr;        /* this                */
  438.                 case 3:        work[4] = ' ';    --workPtr;        /* at                */
  439.                 default:    break;                            /* home!            */
  440.                 }
  441.                 BlockCopy(workPtr, &GLOBAL.logIdentifier, sizeof (OSType));
  442.             }
  443.             GLOBAL.logRecordPtr = MakeLogRecord(kPCIDeviceNameCString, 256);
  444.             LogString("\pDoDriverIO (Initialize)");
  445.             PreserveLogRecord(GLOBAL.logRecordPtr, FALSE);    /* Wrap-around            */
  446. #endif
  447.             status = DriverInitializeCmd(
  448.                         addressSpaceID, ioCommandContents.initialInfo);
  449.             CheckStatus(status, "\pInitialize failed");
  450.             break;
  451.         case kFinalizeCommand:                /* Always immediate                        */
  452.             //** SysDebugStr("\p Driver Finalize");
  453.             LogString("\pDoDriverIO (Finalize)");
  454.             status = DriverFinalizeCmd(ioCommandContents.finalInfo);
  455.             break;
  456.         case kSupersededCommand:
  457.             //** SysDebugStr("\p Driver Superseded");
  458.             LogString("\pDoDriverIO (Supersede)");
  459.             status = DriverSupersededCmd(ioCommandContents.supersededInfo, FALSE);
  460.             break;
  461.         case kReplaceCommand:                /* replace an old driver                */
  462.             //** SysDebugStr("\p Driver Replace");
  463.             LogString("\pDoDriverIO (Replace)");
  464.             status = DriverReplaceCmd(
  465.                         addressSpaceID, ioCommandContents.replaceInfo, FALSE);
  466.             break;
  467.         case kOpenCommand:                    /* Always immediate                        */
  468.             //** SysDebugStr("\p Driver Open");
  469.             LogString("\pDoDriverIO (Open)");
  470.             status = DriverOpenCmd(addressSpaceID, ioCommandContents.pb);
  471.             CheckStatus(status, "\pOpen failed");
  472.             break;
  473.         case kCloseCommand:                    /* Always immediate                        */
  474.             //** SysDebugStr("\p Driver Close");
  475.             LogString("\pDoDriverIO (Close)");
  476.             status = DriverCloseCmd(ioCommandContents.pb);
  477.             break;
  478.         case kControlCommand:
  479.             //** SysDebugStr("\p Driver Control");
  480.             LogDecimal(
  481.                 ((CntrlParam *) ioCommandContents.pb)->csCode, "\pDoDriverIO (Control)");
  482.             status = DriverControlCmd(
  483.                         addressSpaceID,
  484.                         ioCommandID,
  485.                         ioCommandKind,
  486.                         (CntrlParam *) ioCommandContents.pb
  487.                     );
  488.             break;
  489.         case kStatusCommand:
  490.             //** SysDebugStr("\p Driver Status");
  491.             LogDecimal(
  492.                 ((CntrlParam *) ioCommandContents.pb)->csCode, "\pDoDriverIO (Status)");
  493.             status = DriverStatusCmd(
  494.                         ioCommandID,
  495.                         ioCommandKind,
  496.                         (CntrlParam *) ioCommandContents.pb
  497.                     );
  498.             break;
  499.         case kReadCommand:
  500.             //** SysDebugStr("\p Driver Read");
  501.             status = DriverReadCmd(
  502.                         addressSpaceID,
  503.                         ioCommandID,
  504.                         ioCommandKind,
  505.                         ioCommandContents.pb
  506.                     );
  507.             break;
  508.         case kWriteCommand:
  509.             //** LogString("\p Driver Write");
  510.             status = DriverWriteCmd(
  511.                         addressSpaceID,
  512.                         ioCommandID,
  513.                         ioCommandKind,
  514.                         ioCommandContents.pb
  515.                     );
  516.             break;
  517.         case kKillIOCommand:                /* Always immediate                        */
  518.             //** SysDebugStr("\p Driver Killio");
  519.             LogString("\pDoDriverIO (KillIO)");
  520.             status = DriverKillIOCmd(ioCommandContents.pb);
  521.             break;
  522.         default:
  523.             //** SysDebugStr("\p Driver Bogus");
  524.             LogHex((UInt32) ioCommandCode, "\pUnknown DoDriverIO IOCommandCode");
  525.             status = paramErr;
  526.             break;
  527.         }
  528.         /*
  529.          * Force a valid result for immediate commands -- they must return a valid
  530.          * status to the Driver Manager: returning kIOBusyStatus would be a bug..
  531.          * Non-immediate commands return a status from the lower-level routine. If the
  532.          * status is kIOBusyStatus, we just return -- an asynchronous I/O completion
  533.          * routine will eventually complete the request. If it's some other status, the
  534.          * lower-level routine has completed a non-immediate task, so we call
  535.          * IOCommandIsComplete and return its (presumably noErr) status.
  536.          */
  537.         if ((ioCommandKind & kImmediateIOCommandKind) != 0) {
  538.             ;            /* Immediate commands return the operation status        */
  539.         }
  540.         else if (status == kIOBusyStatus) {
  541.             /*
  542.              * An asynchronous operation is in progress. The driver handler promises
  543.              * to call IOCommandIsComplete when the operation concludes.
  544.              */
  545.             status = noErr;
  546.         }
  547.         else {
  548.             /*
  549.              * Normal command that completed synchronously. Dequeue the user's
  550.              * parameter block.
  551.              */
  552.             Timestamp('IOC+');                /* IOC- is in the test application        */
  553.             status = IOCommandIsComplete(ioCommandID, status);
  554.         }
  555.         return (status);
  556. }
  557.  
  558.  
  559. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  560.  * DriverInitializeCmd
  561.  *
  562.  * The New Driver Manager calls this when the driver is first opened.
  563.  */
  564. OSErr
  565. DriverInitializeCmd(
  566.         AddressSpaceID            addressSpaceID,
  567.         DriverInitInfoPtr        driverInitInfoPtr
  568.     )
  569. {
  570.         OSErr                    status;
  571.         ByteCount                unusedAreaLength;
  572.         static const Nanoseconds    gNsecClockTick12 = { 0, 12 * 33 };
  573.  
  574.         Trace(DriverInitializeCmd);
  575.         gPageSize = GetLogicalPageSize();
  576.         gPageMask = gPageSize - 1;
  577.         GLOBAL.refNum = driverInitInfoPtr->refNum;
  578.         GLOBAL.deviceEntry = driverInitInfoPtr->deviceEntry;
  579.         /*
  580.          * Compute 12 PCI clock ticks in AbsoluteTime units. Currently, we
  581.          * know that the PCI clock cycle is 33 nsec/tick. In the future, we
  582.          * should retrieve the PCI clock speed from the Name Registry.
  583.          */
  584.         GLOBAL.clockTick12 = NanosecondsToAbsolute(gNsecClockTick12);
  585.         GLOBAL.msec250 = DurationToAbsolute(250 * durationMillisecond);
  586.         status = InstallDriverInterruptFunction(
  587.                     &GLOBAL.deviceEntry,
  588.                     PCIInterruptServiceRoutine,
  589.                     &GLOBAL.interruptSetMember,
  590.                     &GLOBAL.interruptSetRefcon,
  591.                     &GLOBAL.interruptServiceFunction,
  592.                     &GLOBAL.interruptEnableFunction,
  593.                     &GLOBAL.interruptDisableFunction
  594.                 );
  595.         CheckStatus(status, "\pInstallDriverInterruptFunction failed");
  596.         if (status == noErr) {
  597.             status = GetDeviceLogicalAddress(
  598.                         &GLOBAL.deviceEntry,
  599. #if USE_MEM_ACCESS
  600.                         kPCIMemoryBaseRegister,
  601. #else
  602.                         kPCIIOBaseRegister,
  603. #endif
  604.                         &GLOBAL.pciCardBaseAddress,
  605.                         &unusedAreaLength
  606.                     );
  607.             CheckStatus(status, "\pGetPCICardBaseAddress failed");
  608.         }
  609.         if (status == noErr)
  610.             status = NCRInitializeChip();
  611.         if (status == noErr)
  612.             status = DriverReplaceCmd(
  613.                         addressSpaceID,
  614.                         (DriverReplaceInfoPtr) driverInitInfoPtr,
  615.                         TRUE
  616.                     );
  617.         if (status != noErr && GLOBAL.interruptDisableFunction != NULL) {
  618.             (*GLOBAL.interruptDisableFunction)(
  619.                         GLOBAL.interruptSetMember,
  620.                         GLOBAL.interruptSetRefcon
  621.                     );
  622.             GLOBAL.interruptDisableFunction = NULL;
  623.         }
  624.         return (status);
  625. }
  626.  
  627. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  628.  * DriverReplaceCmd
  629.  *
  630.  * We are replacing an existing driver -- or are completing an initialization sequence.
  631.  * Retrieve any state information from the Name Registry (we have none), install
  632.  * our interrupt handlers, and activate the device.
  633.  *
  634.  * We don't use the calledFromInitialize parameter, but it's here so that a driver can
  635.  * distinguish between initialization (fetch only the NVRAM parameter) and replacement
  636.  * (fetch state information that may be left-over from the previous incantation).
  637.  */
  638. OSErr
  639. DriverReplaceCmd(
  640.         AddressSpaceID            addressSpaceID,
  641.         DriverReplaceInfoPtr    driverReplaceInfoPtr,
  642.         Boolean                    calledFromInitialize
  643.     )
  644. {
  645.         OSErr                    status;
  646.         NCRDriverInitiatorIDParam pb;
  647.  
  648.         Trace(DriverReplaceCmd);
  649.         UNUSED(addressSpaceID);
  650.         UNUSED(calledFromInitialize);
  651.         GLOBAL.refNum = driverReplaceInfoPtr->refNum;
  652.         GLOBAL.deviceEntry = driverReplaceInfoPtr->deviceEntry;
  653.         PublishDriverDebugInfo();
  654.         CLEAR(pb);
  655.         GLOBAL.initiatorID = kSCSIInitiatorID;
  656.         InitializeSCSIInitiatorID();
  657. //** For debugging, defer PatchScript until the first NCR operation so the test
  658. //** tool can dump the un-compiled script.
  659. //**    status = NCRPatchScript();
  660.         status = noErr;
  661.         if (status == noErr)
  662.             status = DriverGestaltOn(GLOBAL.refNum);
  663.         if (status == noErr)
  664.             status = PrepareMemoryForScript(addressSpaceID);
  665.         if (status == noErr)
  666.             status = CreatePerRequestRecord(addressSpaceID);
  667.         if (status == noErr) {
  668.             /*
  669.              * Initialize the hardware.
  670.              */
  671.             status = NCRResetChip(kNCRResetChipInitialize);
  672.             CheckStatus(status, "\pNCRResetChip failed");
  673.         }
  674.         if (status != noErr)
  675.             PublishInitFailureMsg(status, "\pDriverReplaceCmd failure");
  676.         return (status);
  677. }
  678.  
  679. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  680.  * DriverFinalizeCmd
  681.  *
  682.  * Process a DoDriverIO finalize command.
  683.  */
  684. OSErr
  685. DriverFinalizeCmd(
  686.         DriverFinalInfoPtr        driverFinalInfoPtr
  687.     )
  688. {
  689.         Trace(DriverFinializeCmd);
  690.         (void) DriverSupersededCmd((DriverSupersededInfoPtr) driverFinalInfoPtr, TRUE);
  691.         CLEAR(GLOBAL);
  692.         return (noErr);
  693. }
  694.  
  695. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  696.  * DriverSupersededCmd
  697.  *
  698.  * We are shutting down, or being replaced by a later driver. Wait for all I/O to
  699.  * complete and store volatile state in the Name Registry whree it will be retrieved
  700.  * by our replacement.
  701.  */
  702. OSErr
  703. DriverSupersededCmd(
  704.         DriverSupersededInfoPtr    driverSupersededInfoPtr,
  705.         Boolean                    calledFromFinalize
  706.     )
  707. {
  708.         Trace(DriverSupersededCmd);
  709.         UNUSED(driverSupersededInfoPtr);
  710.         UNUSED(calledFromFinalize);
  711.         /*
  712.          * This duplicates DriverKillIOCmd, the correct algorithm would wait for
  713.          * concurrent I/O to complete. Hmm, what about "infinite wait" I/O, such
  714.          * as would be posted by a modem server or socket listener? Note that
  715.          * this section needs to be extended to handle all pending requests.
  716.          *
  717.          * It's safe to call CompleteThisRequest, as that routine uses an atomic
  718.          * operation that allows it to be called when no request is pending without
  719.          * any possible problems. Since it's a secondary interrupt handler, we
  720.          * need to call it through the Driver Services Library.
  721.          *
  722.          * Warning: GLOBAL.perRequestDataPtr will be NULL if initialization fails
  723.          * and the Driver Manager tries to terminate us. When we permit concurrent
  724.          * requests, this will loop on all per-request records.
  725.          */
  726.         if (GLOBAL.perRequestDataPtr == NULL)
  727.             LogString("\pSupersede called before initialization complete");
  728.         else {
  729.             CancelWatchdogTimer(GLOBAL.perRequestDataPtr);
  730.             (void) NCRResetChip(kNCRStopCurrentScript);
  731.             (void) NCRSecondaryInterruptHandler(
  732.                         GLOBAL.perRequestDataPtr, (void *) abortErr);
  733.             DisposePerRequestRecord(&GLOBAL.perRequestDataPtr);
  734.         }
  735.         DisposePerRequestRecord(&GLOBAL.perRequestDataPtr);
  736.         DisposeMemoryForScript();
  737.         if (GLOBAL.interruptDisableFunction != NULL) {
  738.             (*GLOBAL.interruptDisableFunction)(
  739.                         GLOBAL.interruptSetMember,
  740.                         GLOBAL.interruptSetRefcon
  741.                     );
  742.             GLOBAL.interruptDisableFunction = NULL;
  743.         }
  744.         CLEAR(GLOBAL);
  745.         return (noErr);
  746. }
  747.  
  748. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  749.  * DriverControlCmd
  750.  *
  751.  * Process a PBControl command.
  752.  */
  753. OSErr
  754. DriverControlCmd(
  755.         AddressSpaceID            addressSpaceID,
  756.         IOCommandID                ioCommandID,
  757.         IOCommandKind            ioCommandKind,
  758.         CntrlParam                *pb
  759.     )
  760. {
  761.         OSErr                    status;
  762.         UInt8                    initiatorID;
  763.  
  764.         Trace(DriverControlCmd);
  765.         UNUSED(ioCommandKind);
  766.         switch (pb->csCode) {
  767.         case driverPowerLow:
  768.             status = NCRResetChip(kNCRResetChipPowerDown);
  769.             break;
  770.         case driverPowerHigh:
  771.             status = NCRResetChip(kNCRResetChipPowerUp);
  772.             break;
  773.         case kControlDoSCSIBusReset:
  774.             /*
  775.              * NCRPatchScript is here so that the test program can dump
  776.              * the script in its un-patched format.
  777.              */
  778.             status = NCRPatchScript();        /* TEMP    */
  779.             if (status != noErr) break;        /* TEMP */
  780.             status = NCRStartScript(
  781.                         addressSpaceID,
  782.                         ioCommandID,
  783.                         (ParmBlkPtr) pb,
  784.                         kBusResetScript
  785.                     );
  786.             break;
  787.         case kControlDoSCSIRundown:
  788.             status = NCRPatchScript();        /* TEMP */
  789.             if (status != noErr) break;        /* TEMP */
  790.             status = NCRStartScript(
  791.                         addressSpaceID,
  792.                         ioCommandID,
  793.                         (ParmBlkPtr) pb,
  794.                         kSCSIRundownScript
  795.                     );
  796.             break;
  797.         case kControlGetOrSetInitiatorID:
  798.             initiatorID = ((NCRDriverInitiatorIDParamPtr) pb)->initiatorID;
  799.             status = SetSCSIInitiatorID(initiatorID);
  800.             break;
  801.         case kControlGoodbye:                    /* Unused                            */
  802.             /*
  803.              * We should reset the NCR Chip, but we'll wait for Finalize
  804.              */
  805.             status = noErr;
  806.             break;
  807.         default:
  808.             LogDecimal(pb->csCode, "\pUnknown PBControl csCode");
  809.             status = controlErr;                /* Unknown csCode                    */
  810.             break;
  811.         }
  812.         return (status);
  813. }
  814.  
  815. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  816.  * DriverStatusCmd
  817.  *
  818.  * Process a PBStatus command. We support the driver gestalt call and our private
  819.  * debugging commands.
  820.  */
  821. OSErr
  822. DriverStatusCmd(
  823.         IOCommandID                ioCommandID,
  824.         IOCommandKind            ioCommandKind,
  825.         CntrlParam                *pb
  826.     )
  827. {
  828.         OSErr                    status;
  829.         UInt8                    initiatorID;
  830. #define PB        (*pb)
  831.  
  832.         Trace(DriverStatusCmd);
  833.         UNUSED(ioCommandID);
  834.         UNUSED(ioCommandKind);        /* Always synchronous - actually, we don't care */
  835.         switch (PB.csCode) {
  836.         case csDriverGestaltCode:
  837.             status = DriverGestaltHandler(pb);
  838.             break;
  839.         case kControlGetOrSetInitiatorID:
  840.             status = GetSCSIInitiatorID(&initiatorID);
  841.             if (status == noErr)
  842.                 ((NCRDriverInitiatorIDParamPtr) pb)->initiatorID = initiatorID;
  843.             break;
  844.         default:
  845.             LogDecimal(PB.csCode, "\pUnknown PBStatus csCode");
  846.             status = statusErr;
  847.             break;
  848.         }
  849.         return (status);
  850. #undef PB
  851. }
  852.  
  853. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  854.  * DriverKillIOCmd stops all I/O for this chip. It's a big hammer, use it wisely.
  855.  * This will need revision when we support concurrent I/O as we must stop all
  856.  * pending requests.
  857.  */
  858. OSErr
  859. DriverKillIOCmd(
  860.         ParmBlkPtr                pb
  861.     )
  862. {
  863. #define REQUEST    (GLOBAL.perRequestData)
  864.  
  865.         Trace(DriverKillIOCmd);
  866.         UNUSED(pb);
  867.         /*
  868.          * This presumes that, when NCRResetChip interrupts, it will complete the
  869.          * current request, if any.
  870.          */
  871.         (void) NCRResetChip(kNCRStopCurrentScript);
  872.         return (noErr);
  873. #undef REQUEST
  874. }
  875.  
  876. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  877.  * DriverReadCmd
  878.  *
  879.  * The caller passes the data buffer and buffer length in the IOParam record and
  880.  * a pointer to a SCSI NCRSCSIParam in the ioMisc field.
  881.  */
  882. OSErr
  883. DriverReadCmd(
  884.         AddressSpaceID            addressSpaceID,
  885.         IOCommandID                ioCommandID,
  886.         IOCommandKind            ioCommandKind,
  887.         ParmBlkPtr                pb
  888.     )
  889. {
  890.         OSErr                    status;
  891. #define PB        (pb->ioParam)
  892. #define SCSI    (*((NCRSCSIParamPtr) PB.ioMisc))
  893.  
  894.         Trace(DriverReadCmd);
  895.         UNUSED(ioCommandKind);
  896.         if (PB.ioMisc == NULL)
  897.             status = paramErr;
  898.         else if ((SCSI.driverAction & kNCRDriverOutputAllowed) != 0)
  899.             status = scsiRequestInvalid;
  900.         else {
  901.             status = NCRStartScript(
  902.                         addressSpaceID,
  903.                         ioCommandID,
  904.                         pb,
  905.                         kSCSICommandScript
  906.                     );
  907.         }
  908.         return (status);
  909. #undef PB
  910. #undef SCSI
  911. }
  912.  
  913.  
  914. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  915.  * DriverWriteCmd
  916.  *
  917.  * The caller passes the data buffer and buffer length in the IOParam record and
  918.  * a pointer to a SCSI NCRSCSIParam in the ioMisc field.
  919.  */
  920. OSErr
  921. DriverWriteCmd(
  922.         AddressSpaceID            addressSpaceID,
  923.         IOCommandID                ioCommandID,
  924.         IOCommandKind            ioCommandKind,
  925.         ParmBlkPtr                pb
  926.     )
  927. {
  928.         OSErr                    status;
  929. #define PB        (pb->ioParam)
  930. #define SCSI    (*((NCRSCSIParamPtr) PB.ioMisc))
  931.  
  932.         Trace(DriverWriteCmd);
  933.         UNUSED(ioCommandKind);
  934.         if (PB.ioMisc == NULL)
  935.             status = paramErr;
  936.         else if ((SCSI.driverAction & kNCRDriverInputAllowed) != 0)
  937.             status = scsiRequestInvalid;
  938.         else {
  939.             status = NCRStartScript(
  940.                         addressSpaceID,
  941.                         ioCommandID,
  942.                         pb,
  943.                         kSCSICommandScript
  944.                     );
  945.         }
  946.         return (status);
  947. #undef PB
  948. #undef SCSI
  949. }
  950.  
  951. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  952.  * DriverCloseCmd does nothing..
  953.  */
  954. OSErr
  955. DriverCloseCmd(
  956.         ParmBlkPtr                pb
  957.     )
  958. {
  959.         Trace(DriverCloseCmd);
  960.         UNUSED(pb);
  961.         return (noErr);
  962. }
  963.  
  964. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  965.  * DriverOpenCmd does nothing: remember that many applications will open a device, but
  966.  * never close it..
  967.  */
  968. OSErr
  969. DriverOpenCmd(
  970.         AddressSpaceID            addressSpaceID,
  971.         ParmBlkPtr                pb
  972.     )
  973. {
  974.         Trace(DriverOpenCmd);
  975.         UNUSED(addressSpaceID);
  976.         UNUSED(pb);
  977.         return (noErr);
  978. }
  979.  
  980. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  981.  * GetSCSIInitiatorID
  982.  *
  983.  * Retrieve the initiator ID from the Name Registry. This may be called from the
  984.  * driver Status handler. It does not modify the NCR initiator ID (SetSCSIInitiatorID
  985.  * will do this).
  986.  */
  987. OSErr
  988. GetSCSIInitiatorID(
  989.         UInt8                    *initiatorID
  990.     )
  991. {
  992.         OSErr                    status;
  993.         UInt8                    driverNVRAMRecord[8];
  994.  
  995.         Trace(GetSCSIInitiatorID);
  996.         status = GetDriverNVRAMProperty(
  997.                 &GLOBAL.deviceEntry,
  998.                 kCreatorType,
  999.                 driverNVRAMRecord
  1000.             );
  1001.         if (status == noErr)
  1002.             *initiatorID = driverNVRAMRecord[0];
  1003.         return (status);
  1004. }
  1005.  
  1006. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1007.  * SetSCSIInitiatorID
  1008.  *
  1009.  * Store the initiator ID in our global area. It will take effect on the next SCSI
  1010.  * request: this may cause a subtle race condition if asynchronous I/O is in progress.
  1011.  * This function is really here only to illustrate/test NVRAM configuration.
  1012.  *
  1013.  * Note: because this may create a property in the Name Registry, it must be called
  1014.  * from an application "task" context.
  1015.  */
  1016. OSErr
  1017. SetSCSIInitiatorID(
  1018.         UInt8                    initiatorID
  1019.     )
  1020. {
  1021.         OSErr                    status;
  1022.         UInt8                    driverNVRAMRecord[8];
  1023.  
  1024.         Trace(SetSCSIInitiatorID);
  1025.         if (initiatorID > kMaxSCSIInitiatorID)
  1026.             status = paramErr;
  1027.         else {
  1028.             /*
  1029.              * This should really wait until all I/O is complete.
  1030.              */
  1031.             GLOBAL.initiatorID = initiatorID;
  1032.             CLEAR(driverNVRAMRecord);
  1033.             driverNVRAMRecord[0] = GLOBAL.initiatorID;
  1034.             status = UpdateDriverNVRAMProperty(
  1035.                     &GLOBAL.deviceEntry,
  1036.                     kCreatorType,
  1037.                     driverNVRAMRecord
  1038.                 );
  1039.         }
  1040.         return (status);
  1041. }
  1042.  
  1043. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  1044.  * InitializeSCSIInitiatorID
  1045.  *
  1046.  * Retrieve the initiator ID from our NVRAM property. Called from initialization.
  1047.  */
  1048. void
  1049. InitializeSCSIInitiatorID(void)
  1050. {
  1051.         OSErr                    status;
  1052.         UInt8                    driverNVRAMRecord[8];
  1053.  
  1054.         Trace(InitializeSCSIInitiatorID);
  1055.         CLEAR(driverNVRAMRecord);
  1056.         status = RetrieveDriverNVRAMProperty(
  1057.                     &GLOBAL.deviceEntry,
  1058.                     kCreatorType,
  1059.                     driverNVRAMRecord
  1060.                 );
  1061.         switch (status) {
  1062.         case noErr:                    /* Found in NVRAM                            */
  1063.             GLOBAL.initiatorID = driverNVRAMRecord[0];
  1064.             break;
  1065.         case nrNotFoundErr:            /* Not in NVRAM                                */
  1066.         case paramErr:                /* Deleted bogus NVRAM property                */
  1067.         default:                    /* Some other Name Registry error            */
  1068.             /*
  1069.              * Create the NVRAM property.
  1070.              */
  1071.             CLEAR(driverNVRAMRecord);
  1072.             driverNVRAMRecord[0] = GLOBAL.initiatorID;
  1073.             status = CreateDriverNVRAMProperty(
  1074.                         &GLOBAL.deviceEntry,
  1075.                         kCreatorType,
  1076.                         driverNVRAMRecord
  1077.                     );
  1078.             break;
  1079.         }
  1080.         CheckStatus(status, "\pInitializeSCSIInitiatorID");
  1081. }
  1082.