1 /* Copyright 2006-2008 Robert Nelson <robertn@the-nelsons.org>
3 $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
6 This program is free software; you may redistribute and/or modify it under
7 the terms of the GNU General Public License Version 2 as published by the
8 Free Software Foundation.
10 This program is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
12 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
18 * This is the SCSI commands for Windows.
22 #define WIN32_LEAN_AND_MEAN
28 #include <ddk/ntddscsi.h>
31 #define SCSI_DEFAULT_TIMEOUT 300 /* 1 minutes */
32 #define SCSI_MAX_TIMEOUT 108000 /* 30 hours */
34 typedef struct _HANDLE_ENTRY
41 } HANDLE_ENTRY, *PHANDLE_ENTRY;
43 PHANDLE_ENTRY HandleTable = NULL;
46 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
49 TCHAR szDevicePath[256];
54 int port, path, target, lun;
56 for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++)
58 if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
62 if (DeviceIndex >= nEntries)
64 PHANDLE_ENTRY pNewTable;
68 if (HandleTable == NULL)
70 pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY));
74 pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY));
77 if (pNewTable == NULL)
79 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
82 HandleTable = pNewTable;
85 for (index = 0; DeviceName[index] != '\0'; index++)
87 if (DeviceName[index] == ':')
89 else if (DeviceName[index] < '0' || DeviceName[index] > '9')
93 if (DeviceName[index] == '\0' && nColons == 3 &&
94 sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4)
96 HandleTable[DeviceIndex].PortId = (UCHAR)port;
97 HandleTable[DeviceIndex].PathId = (UCHAR)path;
98 HandleTable[DeviceIndex].TargetId = (UCHAR)target;
99 HandleTable[DeviceIndex].Lun = (UCHAR)lun;
101 sprintf(szDevicePath, "\\\\.\\scsi%d:", port);
105 int nPrefixLength = 0;
107 if (DeviceName[0] != '\\') {
108 memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR));
112 HandleTable[DeviceIndex].PortId = 0;
113 HandleTable[DeviceIndex].PathId = 0;
114 HandleTable[DeviceIndex].TargetId = 0;
115 HandleTable[DeviceIndex].Lun = 0;
117 strncpy(&szDevicePath[nPrefixLength],
119 sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1);
121 szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0';
124 HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
126 if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
128 DWORD dwError = GetLastError();
133 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
134 fputs(lpszMessage, stderr);
139 case ERROR_FILE_NOT_FOUND:
140 case ERROR_PATH_NOT_FOUND:
144 case ERROR_TOO_MANY_OPEN_FILES:
149 case ERROR_ACCESS_DENIED:
150 case ERROR_SHARING_VIOLATION:
151 case ERROR_LOCK_VIOLATION:
152 case ERROR_INVALID_NAME:
156 case ERROR_FILE_EXISTS:
160 case ERROR_INVALID_PARAMETER:
165 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
171 static int scsi_timeout = SCSI_DEFAULT_TIMEOUT;
173 void SCSI_Set_Timeout(int secs)
175 if (secs > SCSI_MAX_TIMEOUT)
177 secs = SCSI_MAX_TIMEOUT;
183 void SCSI_Default_Timeout(void)
185 scsi_timeout = SCSI_DEFAULT_TIMEOUT;
188 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
190 if (DeviceFD < nEntries)
192 CloseHandle(HandleTable[DeviceFD].hDevice);
193 HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE;
198 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
203 /* Get the SCSI ID and LUN... */
204 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
208 SCSI_ADDRESS ScsiAddress;
210 DWORD dwBytesReturned;
214 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
215 retval->id = HandleTable[fd].TargetId;
216 retval->lun = HandleTable[fd].Lun;
219 fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
226 FatalError("cannot close SCSI device - %m\n");
229 memset(&ScsiAddress, 0, sizeof(ScsiAddress));
231 ScsiAddress.Length = sizeof(ScsiAddress);
233 bResult = DeviceIoControl( HandleTable[fd].hDevice,
234 IOCTL_SCSI_GET_ADDRESS,
235 &ScsiAddress, sizeof(ScsiAddress),
236 &ScsiAddress, sizeof(ScsiAddress),
245 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
246 retval->id = ScsiAddress.TargetId;
247 retval->lun = ScsiAddress.Lun;
250 fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun);
255 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
256 Direction_T Direction,
260 int DataBufferLength,
261 RequestSense_T *RequestSense)
263 PSCSI_PASS_THROUGH ScsiPassThrough;
265 const DWORD dwDataBufferOffset = sizeof(SCSI_PASS_THROUGH) + (sizeof(RequestSense_T) + 3) / 4 * 4;
266 const DWORD dwBufferSize = dwDataBufferOffset + DataBufferLength;
269 DWORD dwBytesReturned;
271 DWORD dwOutputLength;
273 if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE)
279 ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
281 memset(ScsiPassThrough, 0, dwDataBufferOffset);
283 ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
285 ScsiPassThrough->PathId = HandleTable[DeviceFD].PathId;
286 ScsiPassThrough->TargetId = HandleTable[DeviceFD].TargetId;
287 ScsiPassThrough->Lun = HandleTable[DeviceFD].Lun;
288 ScsiPassThrough->CdbLength = (UCHAR)CDB_Length;
289 ScsiPassThrough->DataIn = Direction == Input;
290 ScsiPassThrough->DataBufferOffset = dwDataBufferOffset;
291 ScsiPassThrough->DataTransferLength = DataBufferLength;
292 ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH);
293 ScsiPassThrough->SenseInfoLength = sizeof(RequestSense_T);
294 ScsiPassThrough->TimeOutValue = scsi_timeout;
296 memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length);
299 if (Direction == Output)
301 memcpy((void *)(((char *)ScsiPassThrough) + dwDataBufferOffset), DataBuffer, DataBufferLength);
302 dwInputLength = dwBufferSize;
303 dwOutputLength = dwDataBufferOffset;
307 dwInputLength = sizeof(SCSI_PASS_THROUGH);
308 dwOutputLength = dwBufferSize;
311 bResult = DeviceIoControl( HandleTable[DeviceFD].hDevice,
312 IOCTL_SCSI_PASS_THROUGH,
313 ScsiPassThrough, dwInputLength,
314 ScsiPassThrough, dwOutputLength,
319 if (ScsiPassThrough->ScsiStatus != 0)
321 memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T));
323 fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus);
324 PrintRequestSense(RequestSense);
330 if (Direction == Input)
333 (void *)(((char *)ScsiPassThrough) + dwDataBufferOffset),
341 DWORD dwError = GetLastError();
344 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
345 fputs(lpszMessage, stderr);
346 LocalFree(lpszMessage);
349 memset(RequestSense, 0, sizeof(RequestSense_T));
352 free(ScsiPassThrough);
354 return bResult ? 0 : -1;