fix lintian issues
[debian/mtx] / scsi_win32.c
1 /* Copyright 2006-2008 Robert Nelson <robertn@the-nelsons.org>
2
3 $Date: 2008-08-19 03:03:38 -0700 (Tue, 19 Aug 2008) $
4 $Revision: 193 $
5
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.
9
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
13   for complete details.
14
15 */
16
17 /*
18  * This is the SCSI commands for Windows.
19  */
20
21 #include <stdio.h>
22 #define WIN32_LEAN_AND_MEAN
23 #include <windows.h>
24
25 #ifdef _MSC_VER
26 #include <ntddscsi.h>
27 #else
28 #include <ddk/ntddscsi.h>
29 #endif
30
31 #define SCSI_DEFAULT_TIMEOUT    300             /* 1 minutes */
32 #define SCSI_MAX_TIMEOUT                108000  /* 30 hours */
33
34 typedef struct  _HANDLE_ENTRY
35 {
36         HANDLE  hDevice;
37         UCHAR   PortId;
38         UCHAR   PathId;
39         UCHAR   TargetId;
40         UCHAR   Lun;
41 } HANDLE_ENTRY, *PHANDLE_ENTRY;
42
43 PHANDLE_ENTRY   HandleTable = NULL;
44 int                             nEntries = 0;
45
46 DEVICE_TYPE SCSI_OpenDevice(char *DeviceName)
47 {
48         int             DeviceIndex;
49         TCHAR   szDevicePath[256];
50
51         int             nColons = 0;
52         int             index;
53
54         int             port, path, target, lun;
55
56         for (DeviceIndex = 0; DeviceIndex < nEntries; DeviceIndex++)
57         {
58                 if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
59                         break;
60         }
61
62         if (DeviceIndex >= nEntries)
63         {
64                 PHANDLE_ENTRY pNewTable;
65
66                 nEntries += 4;
67
68                 if (HandleTable == NULL)
69                 {
70                         pNewTable = (PHANDLE_ENTRY)malloc(nEntries * sizeof(HANDLE_ENTRY));
71                 }
72                 else
73                 {
74                         pNewTable = (PHANDLE_ENTRY)realloc(HandleTable, nEntries * sizeof(HANDLE_ENTRY));
75                 }
76
77                 if (pNewTable == NULL)
78                 {
79                         FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
80                 }
81
82                 HandleTable = pNewTable;
83         }
84
85         for (index = 0; DeviceName[index] != '\0'; index++)
86         {
87                 if (DeviceName[index] == ':')
88                         nColons++;
89                 else if (DeviceName[index] < '0' || DeviceName[index] > '9')
90                         break;
91         }
92
93         if (DeviceName[index] == '\0' && nColons == 3 && 
94                 sscanf(DeviceName, "%d:%d:%d:%d", &port, &path, &target, &lun) == 4)
95         {
96                 HandleTable[DeviceIndex].PortId = (UCHAR)port;
97                 HandleTable[DeviceIndex].PathId = (UCHAR)path;
98                 HandleTable[DeviceIndex].TargetId = (UCHAR)target;
99                 HandleTable[DeviceIndex].Lun = (UCHAR)lun;
100
101                 sprintf(szDevicePath, "\\\\.\\scsi%d:", port);
102         }
103         else 
104         {
105                 int nPrefixLength = 0;
106
107                 if (DeviceName[0] != '\\') {
108                         memcpy(szDevicePath, "\\\\.\\", 4 * sizeof(TCHAR));
109                         nPrefixLength = 4;
110                 }
111
112                 HandleTable[DeviceIndex].PortId = 0;
113                 HandleTable[DeviceIndex].PathId = 0;
114                 HandleTable[DeviceIndex].TargetId = 0;
115                 HandleTable[DeviceIndex].Lun = 0;
116
117                 strncpy(&szDevicePath[nPrefixLength], 
118                                 DeviceName, 
119                                 sizeof(szDevicePath) / sizeof(TCHAR) - nPrefixLength - 1);
120
121                 szDevicePath[sizeof(szDevicePath) / sizeof(TCHAR) - 1] = '\0';
122         }
123
124         HandleTable[DeviceIndex].hDevice = CreateFile(szDevicePath, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
125
126         if (HandleTable[DeviceIndex].hDevice == INVALID_HANDLE_VALUE)
127         {
128                 DWORD dwError = GetLastError();
129
130 #if DEBUG
131                 LPSTR lpszMessage;
132
133                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
134                 fputs(lpszMessage, stderr);
135 #endif
136
137                 switch (dwError)
138                 {
139                 case ERROR_FILE_NOT_FOUND:
140                 case ERROR_PATH_NOT_FOUND:
141                         errno = ENOENT;
142                         break;
143
144                 case ERROR_TOO_MANY_OPEN_FILES:
145                         errno =  EMFILE;
146                         break;
147
148                 default:
149                 case ERROR_ACCESS_DENIED:
150                 case ERROR_SHARING_VIOLATION:
151                 case ERROR_LOCK_VIOLATION:
152                 case ERROR_INVALID_NAME:
153                         errno = EACCES;
154                         break;
155
156                 case ERROR_FILE_EXISTS:
157                         errno = EEXIST;
158                         break;
159
160                 case ERROR_INVALID_PARAMETER:
161                         errno = EINVAL;
162                         break;
163                 }
164
165                 FatalError("cannot open SCSI device '%s' - %m\n", DeviceName);
166         }
167
168         return DeviceIndex;
169 }
170
171 static int scsi_timeout = SCSI_DEFAULT_TIMEOUT;
172
173 void SCSI_Set_Timeout(int secs)
174 {
175         if (secs > SCSI_MAX_TIMEOUT)
176         {
177                 secs = SCSI_MAX_TIMEOUT;
178         }
179
180         scsi_timeout = secs;
181 }
182  
183 void SCSI_Default_Timeout(void)
184 {
185         scsi_timeout = SCSI_DEFAULT_TIMEOUT;
186 }
187
188 void SCSI_CloseDevice(char *DeviceName, DEVICE_TYPE DeviceFD)
189 {
190         if (DeviceFD < nEntries)
191         {
192                 CloseHandle(HandleTable[DeviceFD].hDevice);
193                 HandleTable[DeviceFD].hDevice = INVALID_HANDLE_VALUE;
194         }
195         else
196         {
197                 errno = EBADF;
198                 FatalError("cannot close SCSI device '%s' - %m\n", DeviceName);
199         }
200 }
201
202
203 /* Get the SCSI ID and LUN... */
204 scsi_id_t *SCSI_GetIDLun(DEVICE_TYPE fd)
205 {
206         scsi_id_t *             retval;
207
208         SCSI_ADDRESS    ScsiAddress;
209         BOOL                    bResult;
210         DWORD                   dwBytesReturned;
211
212         if (fd < nEntries)
213         {
214                 retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
215                 retval->id = HandleTable[fd].TargetId;
216                 retval->lun = HandleTable[fd].Lun;
217
218 #ifdef DEBUG
219                 fprintf(stderr,"SCSI:ID=%d LUN=%d\n", retval->id, retval->lun);
220 #endif
221                 return retval;
222         }
223         else
224         {
225                 errno = EBADF;
226                 FatalError("cannot close SCSI device - %m\n");
227         }
228
229         memset(&ScsiAddress, 0, sizeof(ScsiAddress));
230
231         ScsiAddress.Length = sizeof(ScsiAddress);
232
233         bResult = DeviceIoControl(      HandleTable[fd].hDevice, 
234                                                                 IOCTL_SCSI_GET_ADDRESS, 
235                                                                 &ScsiAddress, sizeof(ScsiAddress), 
236                                                                 &ScsiAddress, sizeof(ScsiAddress), 
237                                                                 &dwBytesReturned, 
238                                                                 NULL);
239
240         if (!bResult)
241         {
242                 return NULL;
243         }
244
245         retval = (scsi_id_t *)xmalloc(sizeof(scsi_id_t));
246         retval->id = ScsiAddress.TargetId;
247         retval->lun = ScsiAddress.Lun;
248
249 #ifdef DEBUG
250         fprintf(stderr,"SCSI:ID=%d LUN=%d\n",retval->id,retval->lun);
251 #endif
252         return retval;
253 }
254
255 int SCSI_ExecuteCommand(DEVICE_TYPE DeviceFD,
256                                                 Direction_T Direction,
257                                                 CDB_T *CDB,
258                                                 int CDB_Length,
259                                                 void *DataBuffer,
260                                                 int DataBufferLength,
261                                                 RequestSense_T *RequestSense)
262 {
263         PSCSI_PASS_THROUGH ScsiPassThrough;
264
265         const DWORD     dwDataBufferOffset = sizeof(SCSI_PASS_THROUGH) + (sizeof(RequestSense_T) + 3) / 4 * 4;
266         const DWORD     dwBufferSize = dwDataBufferOffset + DataBufferLength;
267
268         BOOL            bResult;
269         DWORD           dwBytesReturned;
270         DWORD           dwInputLength;
271         DWORD           dwOutputLength;
272
273         if (DeviceFD >= nEntries || HandleTable[DeviceFD].hDevice == INVALID_HANDLE_VALUE)
274         {
275                 errno = EBADF;
276                 return -1;
277         }
278
279         ScsiPassThrough = (PSCSI_PASS_THROUGH)malloc(dwBufferSize);
280
281         memset(ScsiPassThrough, 0, dwDataBufferOffset);
282
283         ScsiPassThrough->Length = sizeof(SCSI_PASS_THROUGH);
284
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;
295
296         memcpy(ScsiPassThrough->Cdb, CDB, CDB_Length);
297         dwBytesReturned = 0;
298
299         if (Direction == Output)
300         {
301                 memcpy((void *)(((char *)ScsiPassThrough) + dwDataBufferOffset), DataBuffer, DataBufferLength);
302                 dwInputLength = dwBufferSize;
303                 dwOutputLength = dwDataBufferOffset;
304         }
305         else
306         {
307                 dwInputLength = sizeof(SCSI_PASS_THROUGH);
308                 dwOutputLength = dwBufferSize;
309         }
310
311         bResult = DeviceIoControl(      HandleTable[DeviceFD].hDevice, 
312                                                                 IOCTL_SCSI_PASS_THROUGH, 
313                                                                 ScsiPassThrough, dwInputLength, 
314                                                                 ScsiPassThrough, dwOutputLength, 
315                                                                 &dwBytesReturned, 
316                                                                 NULL);
317         if (bResult)
318         {
319                 if (ScsiPassThrough->ScsiStatus != 0)
320                 {
321                         memcpy(RequestSense, &ScsiPassThrough[1], sizeof(RequestSense_T));
322 #if DEBUG
323                         fprintf(stderr, "Command failed - ScsiStatus = %d\n", ScsiPassThrough->ScsiStatus);
324                         PrintRequestSense(RequestSense);
325 #endif
326                         bResult = false;
327                 }
328                 else
329                 {
330                         if (Direction == Input)
331                         {
332                                 memcpy( DataBuffer, 
333                                                 (void *)(((char *)ScsiPassThrough) + dwDataBufferOffset),
334                                                 DataBufferLength);
335                         }
336                 }
337         }
338         else
339         {
340 #if DEBUG
341                 DWORD   dwError = GetLastError();
342                 LPSTR   lpszMessage;
343
344                 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwError, 0, (LPSTR)&lpszMessage, 0, NULL);
345                 fputs(lpszMessage, stderr);
346                 LocalFree(lpszMessage);
347 #endif
348
349                 memset(RequestSense, 0, sizeof(RequestSense_T));
350         }
351
352         free(ScsiPassThrough);
353
354         return bResult ? 0 : -1;
355 }