There are three basic modifications to allow NetWare to run your HAM driver on multiple processors:
The following sections elaborate on the above basic modifications and illustrate the proper methods of altering your storage (HAM or CDM) driver to make it MP-aware (multiprocessor aware).
NPA_Register_HAM_Module( &npaHandle, novellAssignedModuleID, loadHandle, HAM_Check_Option, HAM_Software_Hot_Replace, HAM_ISR, HAM_Execute_HACB, HAM_Abort_HACB, (instanceNumber | 0x00010000));
or to a NPA_Register_CDM_Module in a CDM as follows:
NPA_Register_CDM_Module( &npaHandle, novellAssignedModuleID, loadHandle, CDM_Check_Option, CDM_Execute_Message, CDM_Inquiry, (instanceNumber | 0x00010000));
Do not modify the instance number directly, as in
instanceNumber |= 0x000100000;
After NWPA detects this bit is set, your HAM driver code executes on multiple processors in multiprocessor systems, for all instances of the driver. Your HAM driver then receives requests on threads originating from any processor. After this, pass InstanceNumber to the functions that need it, as usual.
NOTE:Note: The MP bit is recognized only on the first instance of the driver load, but is effective for all subsequent instances. Do not use any other bit in the high word of the instance number for any reason. They are all reserved by NWPA.
Before:
deviceCount++; numberOfInstances--; length += 6; width -= 17; DoSwap(&status, &result); //swaps values in 2 variables
After
NPA_Inc(&deviceCount); NPA_Dec(&numberOfInstances); NPA_Add(&length, 6); NPA_Sub(&width, 17); previousStatus = NPA_Xchg(&status, result);
NOTE:Atomic lock operations are not supported on 8-bit or 16-bit variables.
An example follows:
Before:
struct DeviceStruct *device; struct HACBStruct *HACB; ... HACB = queue->firstHACB; // needs protection device = (struct DeviceStruct *) HACB->deviceHandle; if (HACB == 0) // no need to protect this compare { InitializeDeviceParameters(device); CheckForDeviceReady(device); } else { queue->firstHACB = HACB; // needs protection HACB->nextHACB->prevHACB = NULL; // needs protection ExecuteHACB(device, HACB); }
After:
struct QueueStruct // add a “status” field to your structure { ... LONG lockStatus; // simply an unsigned long ... }; struct DeviceStruct *device; struct HACBStruct *HACB; ... NPA_SpinLockInit(&queue->lockStatus); // initialize each lock status variable // only once in your code...preferably // during initialization of the structure // structure to which the lock status // variable belongs ... NPA_SpinLock(&queue->lockStatus); // protect all local elements used after // this line HACB = queue->firstHACB; // this line is now protected device = (struct DeviceStruct *) HACB->deviceHandle; if (HACB == 0) { NPA_SpinUnlock(&queue->lockStatus); // remove the protection InitializeDeviceParameters(device); // do not lock during CheckForDeviceReady(device); // time-expensive functions } else { queue->firstHACB = HACB; // this line is now protected HACB->nextHACB->prevHACB = NULL; // this line is now protected NPA_SpinUnlock(&queue->lockStatus); // remove the protection ExecuteHACB(device, HACB); }
NOTE:If you lock the same “status” variable in your ISR that you lock elsewhere in your code, you must use NPA_SpinLockDisable or NPA_SpinTryLockDisable (to disable interrupts) and NPA_SpinUnlockRestore on the same status variable in your code outside your ISR. An example of this follows, assuming queue->lockStatus is being used in the ISR and the following code is outside your ISR:
NPA_SpinLockInit(&queue->lockStatus); ... LONG CPUFlags; struct DeviceStruct *device; ... CPUFlags = NPA_SpinLockDisable(&queue->lockStatus); HACB = queue->firstHACB; device = (struct DeviceStruct *)HACB->deviceHandle; if (HACB == 0) { NPA_SpinUnlockRestore(&queue->lockStatus, CPUFlags); InitializeDeviceParameters(device); CheckForDeviceReady(device); } else { queue->firstHACB = HACB; HACB->nextHACB->prevHACB = NULL; NPA_SpinUnlockRestore(&queue->lockStatus, CPUFlags); ExecuteHACB(device, HACB); }
These MP functions are available in NetWare 4 Support Pack 8 and greater, NetWare 5.0 Support Pack 2 and greater, and in all versions of NetWare 5.1 and greater.