Source Code for scanscsi.c
// **************************************************************************
//
// Adaptec, Inc.
//
// ASPI Developer's Kit
// Copyright 1992-1994
//
// **************************************************************************
//
// This software contains the valuable trade secrets of Adaptec.
// The software is protected under copyright laws as an
// unpublished work of Adaptec. Notice is for informational
// purposes only and does not imply publication. The user of this
// software may make copies of the software for use with parts
// manufactures by Adaptec or under license from Adaptec and for
// no other use.
//
// **************************************************************************
//
// Program Names: SCAN16.EXE SCAN32.EXE
//
// Version: v2.0 v2.0
//
// Source Code: SCANSCSI.C SCANSCSI.C
// SCANSCSI.RC SCANSCSI.RC
// RESOURCE.H RESOURCE.H
// SCAN16.DEF SCAN32.DEF
// SCAN16.MAK SCAN32.MAK
// SCSIDEFS.H SCSIDEFS.H
// WINASPI.H WNASPI32.H
//
// Description: The ASPI test utility programs included here
// will run on Windows 3.0 or later. The utility
// SCAN32.EXE was written for Windows 95 using the
// ASPI for WIN32 specifications. Both programs
// open a window and loop continuously while
// displaying all of the SCSI devices found on the
// SCSI bus. The user can exit at any time by
// pressing ALT F4 or by selecting EXIT from the
// applications menu. The user can enable and
// disable, on a per target basis, which SCSI targets
// should get scanned.
// You should have a basic understanding of writing
// Windows applications before looking at this
// source code.
// Note that this sample code does minimal error
// checking and no timeout handling. Your application
// should be more robust. This code also demonstrates
// the polling and posting techniques of determining
// the completion of the SCSI command. REFER TO THE
// "ASPI FOR WINDOWS" SPECIFICATION FOR MORE
// INFORMATION.
//
//
// **************************************************************************
#pragma pack(1)
#include <windows.h>
#include <string.h>
#include "resource.h"
#include "scsidefs.h"
#ifdef WIN32
#include "wnaspi32.h"
#else
#include "winaspi.h"
#endif
#ifdef WIN32
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
#else
long FAR PASCAL WndProc(HWND,UINT,UINT,LONG);
#endif
void ScanNextTarget(HWND);
#ifdef WIN32
void ASPIPostProc(PSRB_ExecSCSICmd);
void DisplaySCSIID (HWND,void *);
#else
void _loadds __far __pascal ASPIPostProc(LPSRB);
void DisplaySCSIID (HWND,SRB_ExecSCSICmd6 far *);
#endif
HWND PostHWND;
WORD NumAdapters;
RECT rect;
int UsePosting;
char szAppName[] = "SCANSCSI" ;
int cxChar,cyChar;
#ifndef WIN32
FARPROC lpfnASPIPostProc;
#endif
// **************************************************************************
//
// WINMAIN
//
// **************************************************************************
int PASCAL WinMain(HANDLE hInstance, HANDLE hPrevInstance,
LPSTR lpszCmdParam, int nCmdShow)
{
HWND hwnd;
MSG msg ;
WNDCLASS wndclass ;
#ifdef WIN32
DWORD ASPIStatus;
#else
WORD ASPIStatus;
#endif
if (!hPrevInstance)
{
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (hInstance,MAKEINTRESOURCE(SCANSCSI)) ;
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = GetStockObject (WHITE_BRUSH);
wndclass.lpszMenuName = MAKEINTRESOURCE(Menu1);
wndclass.lpszClassName = szAppName ;
RegisterClass (&wndclass) ;
}
hwnd = CreateWindow (
szAppName, // window class name
"SCANSCSI", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, // initial x position
CW_USEDEFAULT, // initial y position
CW_USEDEFAULT, // initial x size
CW_USEDEFAULT, // initial y size
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
ShowWindow (hwnd, nCmdShow) ;
// **************************************************************************
// *
// * Here we check to make sure that ASPI for Windows is resident.
// * If ASPI for Windows or ASPI for WIN32 is not resident it is
// * suggested that you provide more user feedback/help than what is
// * shown in this sample code.
// *
// **************************************************************************
#ifdef WIN32
ASPIStatus = GetASPI32SupportInfo();
switch (HIBYTE(LOWORD(ASPIStatus)))
#else
ASPIStatus = GetASPISupportInfo();
switch (HIBYTE(ASPIStatus))
#endif
{
case SS_COMP: // ASPI for Windows is resident.
#ifdef WIN32
NumAdapters = (LOWORD(LOBYTE(ASPIStatus)));
#else
NumAdapters = LOBYTE(ASPIStatus);
#endif
MessageBox(hwnd,"ASPI for Windows is resident!",
szAppName,MB_ICONINFORMATION);
break;
default:
MessageBox(hwnd,"ASPI for Windows not available!",
szAppName,MB_ICONSTOP);
return 0;
}
// **************************************************************************
// *
// * This code demonstrates the posting abilities of ASPI for Windows
// * as well as the polling technique. Ask the user which method they
// * would like to use to indicate completion of the SCSI request.
// *
// **************************************************************************
UsePosting = MessageBox(hwnd,"Use ASPI for Windows Posting?",
szAppName,
MB_YESNO | MB_ICONQUESTION);
#ifndef WIN32 // NOTE: No need to lock buffers in WIN32.
LockData(0);
lpfnASPIPostProc = MakeProcInstance ((FARPROC)ASPIPostProc, hInstance);
#endif
PostHWND = hwnd;
if (UsePosting == IDYES)
{
ScanNextTarget(hwnd);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
}
else
{
while (TRUE)
{
if (PeekMessage (&msg,NULL,0,0,PM_REMOVE))
{
if (msg.message == WM_QUIT)
break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else // While the processor is free, check
ScanNextTarget(hwnd); // the SCSI bus status.
}
}
ScanNextTarget(0); // Finish any pending ASPI requests
return msg.wParam ;
}
// **************************************************************************
// *
// * Procedure: WndProc()
// *
// **************************************************************************
#ifdef WIN32
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,
LPARAM lParam)
#else
long __far __pascal _export WndProc(HWND hwnd,UINT message,WPARAM
wParam,LPARAM lParam)
#endif
{
HDC hdc;
PAINTSTRUCT ps;
TEXTMETRIC tm;
HMENU hMenu;
static short cxClient, cyClient;
int i=0;
WORD status;
#ifdef WIN32
SRB_ExecSCSICmd *SRBPtr;
#else
SRB_ExecSCSICmd6 far *SRBPtr;
#endif
switch (message)
{
case WM_CREATE:
hdc = GetDC(hwnd);
SelectObject(hdc,GetStockObject(SYSTEM_FIXED_FONT));
GetTextMetrics(hdc,&tm);
cxChar = tm.tmAveCharWidth;
cyChar = tm.tmHeight;
ReleaseDC(hwnd,hdc);
rect.top = 0;
return 0;
case WM_PAINT:
InvalidateRect(hwnd,NULL,TRUE);
hdc = BeginPaint(hwnd,&ps) ;
EndPaint (hwnd,&ps) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
rect.right = LOWORD(lParam);
rect.bottom = HIWORD(lParam);
UpdateWindow(hwnd);
return 0;
case WM_COMMAND:
hMenu = GetMenu(hwnd);
switch (wParam)
{
case ID_FILE_EXIT:
SendMessage(hwnd,WM_CLOSE,0,0L);
return 0;
default:
// 10 = target #0
// 11 = target #1
// 12 = target #2
// 13 = target #3
// 14 = target #4
// 15 = target #5
// 16 = target #6
// 17 = target #7
// Toggle the SCSI target scan status (ENABLED/DISABELD)
if ((wParam >= 10 && wParam <= 17) ||
(wParam >= 20 && wParam <= 27))
{
status = GetMenuState(hMenu,wParam,MF_BYCOMMAND) &
MF_CHECKED;
CheckMenuItem(hMenu,wParam,MF_BYCOMMAND | ((status) ?
MF_UNCHECKED:MF_CHECKED));
}
return 0;
}
case WM_ASPIPOST:
#ifdef WIN32
SRBPtr = (PSRB_ExecSCSICmd)lParam;
#else
SRBPtr = (SRB_ExecSCSICmd6 far *)lParam;
#endif
DisplaySCSIID(hwnd,SRBPtr);
ScanNextTarget(hwnd);
return 0;
case WM_DESTROY:
PostQuitMessage(0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
// **************************************************************************
//
// Function: ScanNextTarget
//
// Description: If polling is enabled, this function is called
// whenever Windows is idle. If a SCSI Inquiry command
// is still in progress, this routine will return
// control back to the caller to free up the CPU. If
// POSTING is enabled, this function is called when the
// SCSI Inquiry command has completed.
//
// hwnd - This parameter contains the Window handle where the
// device names should be listed. If hwnd equals zero,
// this indicates that we're exiting this program and this
// routine should return only after all outstanding ASPI
// requests have completed.
//
// Returns - Nothing
//
// **************************************************************************
void ScanNextTarget(HWND hwnd)
{
HMENU hMenu;
static WORD SRBIsPending=FALSE;
static BYTE target_id=7,adapter_id=0;
static char InquiryBuffer[100];
WORD status, j;
#ifdef WIN32
static SRB_ExecSCSICmd ExecSRB;
#else
static SRB_ExecSCSICmd6 ExecSRB;
#endif
// If the user is exiting the program, wait
// until all pending ASPI requests are
if (hwnd==0) // finished.
{
if (SRBIsPending==TRUE)
{
while (ExecSRB.SRB_Status == SS_PENDING);
}
return;
}
// ***************************************************************************
// -
// - If we are still waiting for the previous SCSI Inquiry to finish,
// - simply return back to the caller to free up the CPU.
// -
// ***************************************************************************
if (UsePosting==IDNO && SRBIsPending==TRUE &&
ExecSRB.SRB_Status==SS_PENDING)
{
return;
}
if (SRBIsPending==FALSE || UsePosting==IDYES)
{
hMenu = GetMenu(hwnd);
target_id = (target_id + 1)%8; // Move to next SCSI ID#
if (target_id == 0)
{
adapter_id++;
if (adapter_id >= (BYTE)NumAdapters)
adapter_id = 0;
}
// Here is where we check
for (j=0;j<8;j++) // the menu status.
{
status = GetMenuState(hMenu,target_id+10,MF_BYCOMMAND) &
MF_CHECKED;
if (status == 0)
{
target_id = (target_id + 1) % 8; // Move to next SCSI ID#
if (target_id == 0)
{
adapter_id++;
if (adapter_id = (BYTE)NumAdapters)
{
adapter_id = 0;
}
}
}
else
break;
}
// Now we construct the SCSI Inquiry SRB and send it to ASPI!
if (j == 8) // Return if user disabled scanning of all
{ // SCSI targets.
return;
}
ExecSRB.SRB_Cmd = SC_EXEC_SCSI_CMD;
ExecSRB.SRB_HaId = adapter_id;
ExecSRB.SRB_Flags = SRB_DIR_IN | SRB_DIR_SCSI;
ExecSRB.SRB_Target = target_id;
ExecSRB.SRB_BufPointer = InquiryBuffer;
ExecSRB.SRB_BufLen = 32;
ExecSRB.SRB_SenseLen = SENSE_LEN;
ExecSRB.SRB_CDBLen = 6;
ExecSRB.CDBByte[0] = SCSI_INQUIRY;
ExecSRB.CDBByte[1] = 0;
ExecSRB.CDBByte[2] = 0;
ExecSRB.CDBByte[3] = 0;
ExecSRB.CDBByte[4] = 32;
ExecSRB.CDBByte[5] = 0;
if (UsePosting == IDYES)
{
ExecSRB.SRB_Flags |= SRB_POSTING;
#ifdef WIN32
ExecSRB.SRB_PostProc = (void *)ASPIPostProc;
#else
ExecSRB.SRB_PostProc = lpfnASPIPostProc;
#endif
}
#ifdef WIN32
SendASPI32Command(&ExecSRB);
#else
SendASPICommand((LPSRB)&ExecSRB);
#endif
SRBIsPending = TRUE; // ASPI command in process
return;
}
if (UsePosting == IDNO)
{
SRBIsPending=FALSE; // Inquiry command has completed
DisplaySCSIID(hwnd,&ExecSRB);
}
return;
}
// **************************************************************************
// Function: DisplaySCSIID
//
// Description: This function will scroll the window down and display
// the device name of the target we just sent a SCSI Inquiry
// command.
//
// hwnd - This parameter contains the window handle where the device
// name should be displayed.
//
// ExecSRB - This parameter points to the ASPI SCSI Request Block (SRB)
// which has completed.
//
// Returns: Nothing
// **************************************************************************
#ifdef WIN32
void DisplaySCSIID ( HWND hwnd, SRB_ExecSCSICmd *ExecSRB)
#else
void DisplaySCSIID(HWND hwnd,SRB_ExecSCSICmd6 far *ExecSRB)
#endif
{
HDC hdc;
char string_buf[80];
int string_len;
hdc = GetDC (hwnd);
ScrollDC (hdc, 0, -cyChar, &rect, &rect, NULL, NULL);
SelectObject (hdc, GetStockObject (SYSTEM_FIXED_FONT));
if (ExecSRB->SRB_Status==SS_COMP)
{
wsprintf ( string_buf,
"Host Adapter #%d - SCSI ID #%d: ",
(BYTE) ExecSRB->SRB_HaId,
(BYTE) ExecSRB->SRB_Target );
#ifdef WIN32
strncat(string_buf,&ExecSRB->SRB_BufPointer[8],28);
#else
lstrcat(string_buf,&ExecSRB->SRB_BufPointer[8] );
#endif
string_len = lstrlen(string_buf);
}
else
{
string_len = wsprintf (string_buf,
"Host Adapter #%d - SCSI ID #%d: %-32s",
(BYTE)ExecSRB->SRB_HaId,
(BYTE)ExecSRB->SRB_Target,
(LPSTR)"No Device");
}
TextOut(hdc,cxChar,rect.bottom-cyChar,string_buf,string_len);
ReleaseDC(hwnd,hdc);
ValidateRect(hwnd,NULL);
return;
}
// ***************************************************************************
//
// Function: ASPIPostProc
//
// Description: If POSTING is enabled, this function is called by ASPI
// for Windows when the SCSI request has completed. This
// sample function simply posts a message to our Window
// handle to indicate that the SCSI request has completed.
//
// DoneSRB This parameter points to the ASPI SCSI Request Block (SRB)
// which has completed.
//
// Returns Nothing
//****************************************************************************
#ifdef WIN32
void ASPIPostProc(PSRB_ExecSCSICmd DoneSRB)
{
PostMessage(PostHWND,WM_ASPIPOST,0,(LPARAM)DoneSRB);
return;
}
#else
void _loadds __far __pascal ASPIPostProc(LPSRB DoneSRB)
{
PostMessage (PostHWND,WM_ASPIPOST,
(WORD)((SRB_ExecSCSICmd6 far *)DoneSRB)->SRB_Status,
(DWORD)DoneSRB);
return;
}
#endif