1 /* Copyright 2006 Robert Nelson <robertn@the-nelsons.org>
3 $Date: 2007-03-24 18:14:01 -0700 (Sat, 24 Mar 2007) $
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.
27 #include <ddk/ntddscsi.h>
30 #define SCSI_DEFAULT_TIMEOUT 300 /* 1 minutes */
31 #define SCSI_MAX_TIMEOUT 108000 /* 30 hours */
33 typedef struct _HANDLE_ENTRY
40 } HANDLE_ENTRY, *PHANDLE_ENTRY;
42 PHANDLE_ENTRY HandleTable = NULL;
45 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
48 TCHAR szDevicePath[256];
53 int port, path, target, lun;
55 for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++)
57 if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
61 if (DeviceIndex >= nEntries)
63 PHANDLE_ENTRY pNewTable;
67 if (HandleTable == NULL)
69 pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY));
73 pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY));
76 if (pNewTable == NULL)
78 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
81 HandleTable = pNewTable;
84 for (index = 0; DeviceName[index] != '\0'; index++)
86 if (DeviceName[index] == ':')
88 else if (DeviceName[index] < '0' || DeviceName[index] > '9')
92 if (DeviceName[index] == '\0' && nColons == 3 &&
93 sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4)
95 HandleTable[DeviceIndex].PortId = (UCHAR)port;
96 HandleTable[DeviceIndex].PathId = (UCHAR)path;
97 HandleTable[DeviceIndex].TargetId = (UCHAR)target;
98 HandleTable[DeviceIndex].Lun = (UCHAR)lun;
100 sprintf(szDevicePath, "\\\\.\\scsi%d:", port);
104 int nPrefixLength = 0;
106 if (DeviceName[0] != '\\') {
107 memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR));
111 HandleTable[DeviceIndex].PortId = 0;
112 HandleTable[DeviceIndex].PathId = 0;
113 HandleTable[DeviceIndex].TargetId = 0;
114 HandleTable[DeviceIndex].Lun = 0;
116 strncpy(&szDevicePath[nPrefixLength],
118 sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1);
120 szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0';
123 HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
125 if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
127 DWORD dwError = GetLastError();
132 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
133 fputs(lpszMessage, stderr);
138 case ERROR_FILE_NOT_FOUND:
139 case ERROR_PATH_NOT_FOUND:
143 case ERROR_TOO_MANY_OPEN_FILES:
148 case ERROR_ACCESS_DENIED:
149 case ERROR_SHARING_VIOLATION:
150 case ERROR_LOCK_VIOLATION:
151 case ERROR_INVALID_NAME:
155 case ERROR_FILE_EXISTS:
159 case ERROR_INVALID_PARAMETER:
164 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
170 static int scsi_timeout = SCSI_DEFAULT_TIMEOUT;
172 void SCSI_Set_Timeout(int secs)
174 if (secs > SCSI_MAX_TIMEOUT)
176 secs = SCSI_MAX_TIMEOUT;
182 void SCSI_Default_Timeout(void)
184 scsi_timeout = SCSI_DEFAULT_TIMEOUT;
187 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
189 if (DeviceFD < nEntries)
191 CloseHandle(HandleTable[DeviceFD].hDevice);
192 HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE;
197 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
202 /* Get the SCSI ID and LUN... */
203 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
207 SCSI_ADDRESS ScsiAddress;
209 DWORD dwBytesReturned;
213 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
214 retval->id = HandleTable[fd].TargetId;
215 retval->lun = HandleTable[fd].Lun;
218 fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
225 FatalError("cannot close SCSI device - %m\n");
228 memset(&ScsiAddress, 0, sizeof(ScsiAddress));
230 ScsiAddress.Length = sizeof(ScsiAddress);
232 bResult = DeviceIoControl( HandleTable[fd].hDevice,
233 IOCTL_SCSI_GET_ADDRESS,
234 &ScsiAddress, sizeof(ScsiAddress),
235 &ScsiAddress, sizeof(ScsiAddress),
244 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
245 retval->id = ScsiAddress.TargetId;
246 retval->lun = ScsiAddress.Lun;
249 fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun);
254 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
255 Direction_T Direction,
259 int DataBufferLength,
260 RequestSense_T *RequestSense)
262 PSCSI_PASS_THROUGH ScsiPassThrough;
264 const DWORD dwDataBufferOffset = sizeof(SCSI_PASS_THROUGH) + (sizeof(RequestSense_T) + 3) / 4 * 4;
265 const DWORD dwBufferSize = dwDataBufferOffset + DataBufferLength;
268 DWORD dwBytesReturned;
270 DWORD dwOutputLength;
272 if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE)
278 ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
280 memset(ScsiPassThrough, 0, dwDataBufferOffset);
282 ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
284 ScsiPassThrough->PathId = HandleTable[DeviceFD].PathId;
285 ScsiPassThrough->TargetId = HandleTable[DeviceFD].TargetId;
286 ScsiPassThrough->Lun = HandleTable[DeviceFD].Lun;
287 ScsiPassThrough->CdbLength = (UCHAR)CDB_Length;
288 ScsiPassThrough->DataIn = Direction == Input;
289 ScsiPassThrough->DataBufferOffset = dwDataBufferOffset;
290 ScsiPassThrough->DataTransferLength = DataBufferLength;
291 ScsiPassThrough->SenseInfoOffset = sizeof(SCSI_PASS_THROUGH);
292 ScsiPassThrough->SenseInfoLength = sizeof(RequestSense_T);
293 ScsiPassThrough->TimeOutValue = scsi_timeout;
295 memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length);
298 if (Direction == Output)
300 memcpy((void *)(((char *)ScsiPassThrough) + dwDataBufferOffset), DataBuffer, DataBufferLength);
301 dwInputLength = dwBufferSize;
302 dwOutputLength = dwDataBufferOffset;
306 dwInputLength = sizeof(SCSI_PASS_THROUGH);
307 dwOutputLength = dwBufferSize;
310 bResult = DeviceIoControl( HandleTable[DeviceFD].hDevice,
311 IOCTL_SCSI_PASS_THROUGH,
312 ScsiPassThrough, dwInputLength,
313 ScsiPassThrough, dwOutputLength,
318 if (ScsiPassThrough->ScsiStatus != 0)
320 memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T));
322 fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus);
323 PrintRequestSense(RequestSense);
329 if (Direction == Input)
332 (void *)(((char *)ScsiPassThrough) + dwDataBufferOffset),
340 DWORD dwError = GetLastError();
343 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
344 fputs(lpszMessage, stderr);
345 LocalFree(lpszMessage);
348 memset(RequestSense, 0, sizeof(RequestSense_T));
351 free(ScsiPassThrough);
353 return bResult ? 0 : -1;