Basic work on disk driver stack (still incomplete).
[reactos.git] / reactos / drivers / storage / scsiport / scsiport.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 2001, 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id: scsiport.c,v 1.3 2002/01/27 01:25:49 ekohl Exp $
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * FILE: services/storage/scsiport/scsiport.c
24 * PURPOSE: SCSI port driver
25 * PROGRAMMER: Eric Kohl (ekohl@rz-online.de)
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ddk/ntddk.h>
31 #include "../include/srb.h"
32 #include "../include/scsi.h"
33 #include "../include/ntddscsi.h"
34
35 #define NDEBUG
36 #include <debug.h>
37
38
39 #define VERSION "0.0.1"
40
41
42 /* TYPES *********************************************************************/
43
44 /*
45 * SCSI_PORT_DEVICE_EXTENSION
46 *
47 * DESCRIPTION
48 * First part of the port objects device extension. The second
49 * part is the miniport-specific device extension.
50 */
51
52 typedef struct _SCSI_PORT_DEVICE_EXTENSION
53 {
54 ULONG Length;
55 ULONG MiniPortExtensionSize;
56 PORT_CONFIGURATION_INFORMATION PortConfig;
57
58 PHW_STARTIO HwStartIo;
59
60 UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
61 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
62
63
64 /*
65 * SCSI_PORT_TIMER_STATES
66 *
67 * DESCRIPTION
68 * An enumeration containing the states in the timer DFA
69 */
70
71 typedef enum _SCSI_PORT_TIMER_STATES
72 {
73 IDETimerIdle,
74 IDETimerCmdWait,
75 IDETimerResetWaitForBusyNegate,
76 IDETimerResetWaitForDrdyAssert
77 } SCSI_PORT_TIMER_STATES;
78
79
80 /*
81 * SCSI_PORT_CONTROLLER_EXTENSION
82 *
83 * DESCRIPTION
84 * Driver-defined structure used to hold miscellaneous controller information.
85 *
86 * ACCESS
87 * Allocated from NON-PAGED POOL
88 * Available at any IRQL
89 */
90
91 typedef struct _SCSI_PORT_CONTROLLER_EXTENSION
92 {
93 KSPIN_LOCK SpinLock;
94 ULONG Number;
95 ULONG Vector;
96 BOOLEAN DMASupported;
97 BOOLEAN ControllerInterruptBug;
98 PKINTERRUPT Interrupt;
99
100 BOOLEAN OperationInProgress;
101 UCHAR DeviceStatus;
102 PSCSI_PORT_DEVICE_EXTENSION DeviceForOperation;
103 PIRP CurrentIrp;
104 ULONG Retries;
105
106 SCSI_PORT_TIMER_STATES TimerState;
107 LONG TimerCount;
108
109 PDEVICE_OBJECT PortDeviceObject;
110
111 } SCSI_PORT_CONTROLLER_EXTENSION, *PSCSI_PORT_CONTROLLER_EXTENSION;
112
113
114 /* GLOBALS *******************************************************************/
115
116
117 static NTSTATUS STDCALL
118 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
119 IN PIRP Irp);
120
121 static NTSTATUS STDCALL
122 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
123 IN PIRP Irp);
124
125 static NTSTATUS STDCALL
126 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
127 IN PIRP Irp);
128
129 static VOID STDCALL
130 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
131 IN PIRP Irp);
132
133 static NTSTATUS
134 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
135 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
136 IN ULONG PortCount);
137
138 static BOOLEAN STDCALL
139 ScsiPortIsr(IN PKINTERRUPT Interrupt,
140 IN PVOID ServiceContext);
141
142 static VOID
143 ScsiPortDpcForIsr(IN PKDPC Dpc,
144 IN PDEVICE_OBJECT DpcDeviceObject,
145 IN PIRP DpcIrp,
146 IN PVOID DpcContext);
147
148 static VOID STDCALL
149 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
150 PVOID Context);
151
152
153 /* FUNCTIONS *****************************************************************/
154
155 /**********************************************************************
156 * NAME EXPORTED
157 * DriverEntry
158 *
159 * DESCRIPTION
160 * This function initializes the driver.
161 *
162 * RUN LEVEL
163 * PASSIVE_LEVEL
164 *
165 * ARGUMENTS
166 * DriverObject
167 * System allocated Driver Object for this driver.
168 *
169 * RegistryPath
170 * Name of registry driver service key.
171 *
172 * RETURN VALUE
173 * Status.
174 */
175
176 NTSTATUS STDCALL
177 DriverEntry(IN PDRIVER_OBJECT DriverObject,
178 IN PUNICODE_STRING RegistryPath)
179 {
180 DbgPrint("ScsiPort Driver %s\n", VERSION);
181 return(STATUS_SUCCESS);
182 }
183
184
185 /**********************************************************************
186 * NAME EXPORTED
187 * ScsiDebugPrint
188 *
189 * DESCRIPTION
190 * Prints debugging messages.
191 *
192 * RUN LEVEL
193 * PASSIVE_LEVEL
194 *
195 * ARGUMENTS
196 * DebugPrintLevel
197 * Debug level of the given message.
198 *
199 * DebugMessage
200 * Pointer to printf()-compatible format string.
201 *
202 * ...
203 Additional output data (see printf()).
204 *
205 * RETURN VALUE
206 * None.
207 */
208
209 VOID
210 ScsiDebugPrint(IN ULONG DebugPrintLevel,
211 IN PCHAR DebugMessage,
212 ...)
213 {
214 char Buffer[256];
215 va_list ap;
216
217 #if 0
218 if (DebugPrintLevel > InternalDebugLevel)
219 return;
220 #endif
221
222 va_start(ap, DebugMessage);
223 vsprintf(Buffer, DebugMessage, ap);
224 va_end(ap);
225
226 DbgPrint(Buffer);
227 }
228
229
230 VOID STDCALL
231 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
232 IN UCHAR PathId,
233 IN UCHAR TargetId,
234 IN UCHAR Lun,
235 IN UCHAR SrbStatus)
236 {
237 UNIMPLEMENTED;
238 }
239
240
241 ULONG STDCALL
242 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
243 {
244 return Address.u.LowPart;
245 }
246
247
248 VOID STDCALL
249 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
250 {
251 UNIMPLEMENTED;
252 }
253
254
255 VOID STDCALL
256 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
257 IN PVOID MappedAddress)
258 {
259 UNIMPLEMENTED;
260 }
261
262
263 ULONG STDCALL
264 ScsiPortGetBusData(IN PVOID DeviceExtension,
265 IN ULONG BusDataType,
266 IN ULONG SystemIoBusNumber,
267 IN ULONG SlotNumber,
268 IN PVOID Buffer,
269 IN ULONG Length)
270 {
271 return(HalGetBusData(BusDataType,
272 SystemIoBusNumber,
273 SlotNumber,
274 Buffer,
275 Length));
276 }
277
278
279 PVOID STDCALL
280 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
281 IN INTERFACE_TYPE BusType,
282 IN ULONG SystemIoBusNumber,
283 IN SCSI_PHYSICAL_ADDRESS IoAddress,
284 IN ULONG NumberOfBytes,
285 IN BOOLEAN InIoSpace)
286 {
287 ULONG AddressSpace;
288 PHYSICAL_ADDRESS TranslatedAddress;
289 PVOID VirtualAddress;
290 PVOID Buffer;
291 BOOLEAN rc;
292
293 AddressSpace = (ULONG)InIoSpace;
294
295 if (!HalTranslateBusAddress(BusType,
296 SystemIoBusNumber,
297 IoAddress,
298 &AddressSpace,
299 &TranslatedAddress))
300 return NULL;
301
302 /* i/o space */
303 if (AddressSpace != 0)
304 return (PVOID)TranslatedAddress.u.LowPart;
305
306 VirtualAddress = MmMapIoSpace(TranslatedAddress,
307 NumberOfBytes,
308 FALSE);
309
310 Buffer = ExAllocatePool(NonPagedPool,0x20);
311 if (Buffer == NULL)
312 return VirtualAddress;
313
314 return NULL; /* ?? */
315 }
316
317
318 PVOID STDCALL
319 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
320 IN UCHAR PathId,
321 IN UCHAR TargetId,
322 IN UCHAR Lun)
323 {
324 UNIMPLEMENTED;
325 }
326
327
328 SCSI_PHYSICAL_ADDRESS STDCALL
329 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
330 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
331 IN PVOID VirtualAddress,
332 OUT ULONG *Length)
333 {
334 UNIMPLEMENTED;
335 }
336
337
338 PSCSI_REQUEST_BLOCK STDCALL
339 ScsiPortGetSrb(IN PVOID DeviceExtension,
340 IN UCHAR PathId,
341 IN UCHAR TargetId,
342 IN UCHAR Lun,
343 IN LONG QueueTag)
344 {
345 UNIMPLEMENTED;
346 }
347
348
349 PVOID STDCALL
350 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
351 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
352 IN ULONG NumberOfBytes)
353 {
354 UNIMPLEMENTED;
355 }
356
357
358 PVOID STDCALL
359 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
360 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
361 {
362 UNIMPLEMENTED;
363 }
364
365
366 ULONG STDCALL
367 ScsiPortInitialize(IN PVOID Argument1,
368 IN PVOID Argument2,
369 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
370 IN PVOID HwContext)
371 {
372 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
373 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
374 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
375 PCONFIGURATION_INFORMATION SystemConfig;
376 PPORT_CONFIGURATION_INFORMATION PortConfig;
377 BOOLEAN Again;
378 ULONG i;
379 ULONG Result;
380 NTSTATUS Status;
381 ULONG MaxBus;
382 PACCESS_RANGE AccessRanges;
383 ULONG ExtensionSize;
384
385 DPRINT1("ScsiPortInitialize() called!\n");
386
387 if ((HwInitializationData->HwInitialize == NULL) ||
388 (HwInitializationData->HwStartIo == NULL) ||
389 (HwInitializationData->HwInterrupt == NULL) ||
390 (HwInitializationData->HwFindAdapter == NULL) ||
391 (HwInitializationData->HwResetBus == NULL))
392 return(STATUS_INVALID_PARAMETER);
393
394 DriverObject->DriverStartIo = ScsiPortStartIo;
395 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
396 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
397 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
398 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
399
400 // DriverObject->MajorFunction[IRP_MJ_READ] = IDEDispatchReadWrite;
401 // DriverObject->MajorFunction[IRP_MJ_WRITE] = IDEDispatchReadWrite;
402 // DriverObject->MajorFunction[IRP_MJ_QUERY_INFORMATION] = IDEDispatchQueryInformation;
403 // DriverObject->MajorFunction[IRP_MJ_SET_INFORMATION] = IDEDispatchSetInformation;
404
405
406
407
408 SystemConfig = IoGetConfigurationInformation();
409
410 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
411 HwInitializationData->DeviceExtensionSize;
412 PseudoDeviceExtension = ExAllocatePool(PagedPool,
413 ExtensionSize);
414 RtlZeroMemory(PseudoDeviceExtension,
415 ExtensionSize);
416 PseudoDeviceExtension->Length = ExtensionSize;
417 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
418 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
419
420 PortConfig = &PseudoDeviceExtension->PortConfig;
421
422 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
423 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
424 PortConfig->InterruptMode =
425 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
426 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
427 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
428 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
429
430 PortConfig->AccessRanges =
431 ExAllocatePool(PagedPool,
432 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
433
434
435 PortConfig->SystemIoBusNumber = 0;
436 PortConfig->SlotNumber = 0;
437
438 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
439
440 DPRINT("MaxBus: %lu\n", MaxBus);
441
442 while (TRUE)
443 {
444 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
445
446 // RtlZeroMemory(AccessRanges,
447 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
448
449 /* Note: HwFindAdapter is called once for each bus */
450 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
451 HwContext,
452 NULL, /* BusInformation */
453 NULL, /* ArgumentString */
454 &PseudoDeviceExtension->PortConfig,
455 &Again);
456 DPRINT("HwFindAdapter() result: %lu\n", Result);
457
458 if (Result == SP_RETURN_FOUND)
459 {
460 DPRINT("ScsiPortInitialize(): Found HBA!\n");
461
462 Status = ScsiPortCreatePortDevice(DriverObject,
463 PseudoDeviceExtension,
464 SystemConfig->ScsiPortCount);
465
466 if (!NT_SUCCESS(Status))
467 {
468 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
469
470 ExFreePool(PortConfig->AccessRanges);
471 ExFreePool(PseudoDeviceExtension);
472
473 return(Status);
474 }
475
476 /* Update the configuration info */
477 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
478 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
479 SystemConfig->ScsiPortCount++;
480 }
481
482 if (Again == FALSE)
483 {
484 PortConfig->SystemIoBusNumber++;
485 PortConfig->SlotNumber = 0;
486 }
487
488 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
489 if (PortConfig->SystemIoBusNumber >= MaxBus)
490 {
491 DPRINT1("Scanned all buses!\n");
492 break;
493 }
494 }
495
496 ExFreePool(PortConfig->AccessRanges);
497 ExFreePool(PseudoDeviceExtension);
498
499 DPRINT1("ScsiPortInitialize() done!\n");
500
501 return(STATUS_SUCCESS);
502 }
503
504
505 VOID STDCALL
506 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
507 IN PSCSI_REQUEST_BLOCK Srb,
508 IN ULONG LogicalAddress,
509 IN ULONG Length)
510 {
511 UNIMPLEMENTED;
512 }
513
514
515 VOID STDCALL
516 ScsiPortLogError(IN PVOID HwDeviceExtension,
517 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
518 IN UCHAR PathId,
519 IN UCHAR TargetId,
520 IN UCHAR Lun,
521 IN ULONG ErrorCode,
522 IN ULONG UniqueId)
523 {
524 UNIMPLEMENTED;
525 }
526
527
528 VOID STDCALL
529 ScsiPortMoveMemory(OUT PVOID Destination,
530 IN PVOID Source,
531 IN ULONG Length)
532 {
533 RtlMoveMemory(Destination,
534 Source,
535 Length);
536 }
537
538
539 VOID
540 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
541 IN PVOID HwDeviceExtension,
542 ...)
543 {
544 UNIMPLEMENTED;
545 }
546
547
548 ULONG STDCALL
549 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
550 IN ULONG BusDataType,
551 IN ULONG SystemIoBusNumber,
552 IN ULONG SlotNumber,
553 IN PVOID Buffer,
554 IN ULONG Offset,
555 IN ULONG Length)
556 {
557 return(HalSetBusDataByOffset(BusDataType,
558 SystemIoBusNumber,
559 SlotNumber,
560 Buffer,
561 Offset,
562 Length));
563 }
564
565
566 BOOLEAN STDCALL
567 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
568 IN INTERFACE_TYPE BusType,
569 IN ULONG SystemIoBusNumber,
570 IN SCSI_PHYSICAL_ADDRESS IoAddress,
571 IN ULONG NumberOfBytes,
572 IN BOOLEAN InIoSpace)
573 {
574 return(TRUE);
575 }
576
577
578 /* INTERNAL FUNCTIONS ********************************************************/
579
580 /**********************************************************************
581 * NAME INTERNAL
582 * ScsiPortCreateClose
583 *
584 * DESCRIPTION
585 * Answer requests for Create/Close calls: a null operation.
586 *
587 * RUN LEVEL
588 * PASSIVE_LEVEL
589 *
590 * ARGUMENTS
591 * DeviceObject
592 * Pointer to a device object.
593 *
594 * Irp
595 * Pointer to an IRP.
596 *
597 * ...
598 Additional output data (see printf()).
599 *
600 * RETURN VALUE
601 * Status.
602 */
603
604 static NTSTATUS STDCALL
605 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
606 IN PIRP Irp)
607 {
608 DPRINT("ScsiPortCreateClose()\n");
609
610 Irp->IoStatus.Status = STATUS_SUCCESS;
611 Irp->IoStatus.Information = FILE_OPENED;
612
613 IoCompleteRequest(Irp, IO_NO_INCREMENT);
614
615 return(STATUS_SUCCESS);
616 }
617
618
619 // ScsiPortDispatchScsi
620 //
621 // DESCRIPTION:
622 // Answer requests for SCSI calls
623 //
624 // RUN LEVEL:
625 // PASSIVE_LEVEL
626 //
627 // ARGUMENTS:
628 // Standard dispatch arguments
629 //
630 // RETURNS:
631 // NTSTATUS
632 //
633
634 static NTSTATUS STDCALL
635 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
636 IN PIRP Irp)
637 {
638 DPRINT("ScsiPortDispatchScsi()\n");
639
640 Irp->IoStatus.Status = STATUS_SUCCESS;
641 Irp->IoStatus.Information = 0;
642
643 IoCompleteRequest(Irp, IO_NO_INCREMENT);
644
645 return(STATUS_SUCCESS);
646 }
647
648
649 // ScsiPortDeviceControl
650 //
651 // DESCRIPTION:
652 // Answer requests for device control calls
653 //
654 // RUN LEVEL:
655 // PASSIVE_LEVEL
656 //
657 // ARGUMENTS:
658 // Standard dispatch arguments
659 //
660 // RETURNS:
661 // NTSTATUS
662 //
663
664 static NTSTATUS STDCALL
665 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
666 IN PIRP Irp)
667 {
668 PIO_STACK_LOCATION Stack;
669 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
670
671 DPRINT("ScsiPortDeviceControl()\n");
672
673 Irp->IoStatus.Status = STATUS_SUCCESS;
674 Irp->IoStatus.Information = 0;
675
676
677 Stack = IoGetCurrentIrpStackLocation(Irp);
678 DeviceExtension = DeviceObject->DeviceExtension;
679
680 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
681 {
682 case IOCTL_SCSI_EXECUTE_IN:
683 {
684 DPRINT1(" IOCTL_SCSI_EXECUTE_IN\n");
685 }
686 break;
687
688 case IOCTL_SCSI_EXECUTE_OUT:
689 {
690 DPRINT1(" IOCTL_SCSI_EXECUTE_OUT\n");
691 }
692 break;
693
694 case IOCTL_SCSI_EXECUTE_NONE:
695 {
696 DPRINT1(" IOCTL_SCSI_EXECUTE_NONE\n");
697 }
698 break;
699
700 case IOCTL_SCSI_GET_CAPABILITIES:
701 {
702 PIO_SCSI_CAPABILITIES Capabilities;
703
704 DPRINT1(" IOCTL_SCSI_GET_CAPABILITIES\n");
705
706 Capabilities = (PIO_SCSI_CAPABILITIES)Irp->AssociatedIrp.SystemBuffer;
707 Capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
708 Capabilities->MaximumTransferLength =
709 DeviceExtension->PortConfig.MaximumTransferLength;
710 Capabilities->MaximumPhysicalPages = 1;
711 Capabilities->SupportedAsynchronousEvents = 0;
712 Capabilities->AlignmentMask =
713 DeviceExtension->PortConfig.AlignmentMask;
714 Capabilities->TaggedQueuing =
715 DeviceExtension->PortConfig.TaggedQueuing;
716 Capabilities->AdapterScansDown =
717 DeviceExtension->PortConfig.AdapterScansDown;
718 Capabilities->AdapterUsesPio = TRUE;
719
720 Irp->IoStatus.Information = sizeof(IO_SCSI_CAPABILITIES);
721 }
722 break;
723
724 case IOCTL_SCSI_GET_INQUIRY_DATA:
725 {
726 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
727 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
728 SCSI_REQUEST_BLOCK Srb;
729 ULONG Bus;
730 ULONG Target;
731 ULONG UnitCount;
732 BOOLEAN Result;
733
734 DPRINT1(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
735
736 AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)Irp->AssociatedIrp.SystemBuffer;
737 AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
738
739 UnitInfo = (PSCSI_INQUIRY_DATA)
740 ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
741 (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
742
743 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
744 RtlZeroMemory(&Srb,
745 sizeof(SCSI_REQUEST_BLOCK));
746 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
747 Srb.DataTransferLength = 256;
748 Srb.Cdb[0] = SCSIOP_INQUIRY;
749
750 for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
751 {
752 Srb.PathId = Bus;
753
754 AdapterInfo->BusData[Bus].InitiatorBusId = 0; /* ? */
755 AdapterInfo->BusData[Bus].InquiryDataOffset =
756 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
757
758 PrevUnit = NULL;
759 UnitCount = 0;
760
761 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
762 {
763 Srb.TargetId = Target;
764 Srb.Lun = 0;
765
766 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
767 &Srb);
768 if (Result == TRUE)
769 {
770 UnitInfo->PathId = Bus;
771 UnitInfo->TargetId = Target;
772 UnitInfo->Lun = 0;
773 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
774 memcpy(&UnitInfo->InquiryData,
775 Srb.DataBuffer,
776 INQUIRYDATABUFFERSIZE);
777 if (PrevUnit != NULL)
778 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
779 PrevUnit = UnitInfo;
780 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
781 UnitCount++;
782 }
783 }
784 AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
785 }
786
787 ExFreePool(Srb.DataBuffer);
788 DPRINT1("BufferSize: %lu\n",(ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo));
789 Irp->IoStatus.Information = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
790 }
791 break;
792
793 default:
794 DPRINT1(" unknown ioctl code: 0x%lX\n",
795 Stack->Parameters.DeviceIoControl.IoControlCode);
796 break;
797 }
798
799 IoCompleteRequest(Irp, IO_NO_INCREMENT);
800
801 return(STATUS_SUCCESS);
802 }
803
804
805 static VOID STDCALL
806 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
807 IN PIRP Irp)
808 {
809 PIO_STACK_LOCATION IrpStack;
810
811 DPRINT("ScsiPortStartIo() called!\n");
812
813 IrpStack = IoGetCurrentIrpStackLocation(Irp);
814 // DeviceExtension = (PIDE_DEVICE_EXTENSION) DeviceObject->DeviceExtension;
815
816 // FIXME: implement the supported functions
817
818 switch (IrpStack->MajorFunction)
819 {
820
821 default:
822 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
823 Irp->IoStatus.Information = 0;
824 // KeBugCheck((ULONG)Irp);
825 IoCompleteRequest(Irp,
826 IO_NO_INCREMENT);
827 IoStartNextPacket(DeviceObject,
828 FALSE);
829 break;
830 }
831 DPRINT("ScsiPortStartIo() finished!\n");
832 }
833
834
835 static NTSTATUS
836 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
837 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
838 IN ULONG PortNumber)
839 {
840 PSCSI_PORT_CONTROLLER_EXTENSION ControllerExtension;
841 PCONTROLLER_OBJECT ControllerObject;
842 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
843 PDEVICE_OBJECT PortDeviceObject;
844 WCHAR NameBuffer[80];
845 UNICODE_STRING DeviceName;
846 WCHAR DosNameBuffer[80];
847 UNICODE_STRING DosDeviceName;
848 NTSTATUS Status;
849 ULONG AccessRangeSize;
850
851 ULONG MappedIrq;
852 KIRQL Dirql;
853 KAFFINITY Affinity;
854
855 DPRINT("ScsiPortCreatePortDevice() called\n");
856
857 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
858 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
859 0,
860 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
861 &Dirql,
862 &Affinity);
863
864 ControllerObject = IoCreateController(sizeof(SCSI_PORT_CONTROLLER_EXTENSION));
865 if (ControllerObject == NULL)
866 {
867 DbgPrint("Could not create controller object for port %d\n",
868 PortNumber);
869 return(STATUS_NO_SUCH_DEVICE);
870 }
871
872 /* Fill out Controller extension data */
873 ControllerExtension = (PSCSI_PORT_CONTROLLER_EXTENSION)
874 ControllerObject->ControllerExtension;
875 ControllerExtension->Number = PortNumber;
876 ControllerExtension->Vector = PseudoDeviceExtension->PortConfig.BusInterruptVector;
877 ControllerExtension->DMASupported = FALSE;
878 ControllerExtension->ControllerInterruptBug = FALSE;
879 ControllerExtension->OperationInProgress = FALSE;
880
881 /* Initialize the spin lock in the controller extension */
882 KeInitializeSpinLock(&ControllerExtension->SpinLock);
883
884 /* Register an interrupt handler for this controller */
885 Status = IoConnectInterrupt(&ControllerExtension->Interrupt,
886 ScsiPortIsr,
887 ControllerExtension,
888 &ControllerExtension->SpinLock,
889 MappedIrq,
890 Dirql,
891 Dirql,
892 PseudoDeviceExtension->PortConfig.InterruptMode,
893 FALSE,
894 Affinity,
895 FALSE);
896 if (!NT_SUCCESS(Status))
897 {
898 DbgPrint("Could not Connect Interrupt %d\n",
899 ControllerExtension->Vector);
900 IoDeleteController (ControllerObject);
901 return(Status);
902 }
903
904 /* Create a unicode device name */
905 swprintf(NameBuffer,
906 L"\\Device\\ScsiPort%lu",
907 PortNumber);
908 RtlInitUnicodeString(&DeviceName,
909 NameBuffer);
910
911 DPRINT("Creating device: %wZ\n", &DeviceName);
912
913 /* Create the port device */
914 Status = IoCreateDevice(DriverObject,
915 PseudoDeviceExtension->Length,
916 &DeviceName,
917 FILE_DEVICE_CONTROLLER,
918 0,
919 FALSE,
920 &PortDeviceObject);
921 if (!NT_SUCCESS(Status))
922 {
923 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
924 IoDisconnectInterrupt(ControllerExtension->Interrupt);
925 IoDeleteController(ControllerObject);
926 return(Status);
927 }
928
929 DPRINT("Created device: %wZ\n", &DeviceName);
930
931 /* Set the buffering strategy here... */
932 PortDeviceObject->Flags |= DO_DIRECT_IO;
933 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
934
935 PortDeviceExtension = PortDeviceObject->DeviceExtension;
936
937 ControllerExtension->PortDeviceObject = PortDeviceObject;
938
939 /* Initialize the DPC object here */
940 IoInitializeDpcRequest(ControllerExtension->PortDeviceObject,
941 ScsiPortDpcForIsr);
942
943 /*
944 * Initialize the controller timer here
945 * (since it has to be tied to a device)
946 */
947 ControllerExtension->TimerState = IDETimerIdle;
948 ControllerExtension->TimerCount = 0;
949 IoInitializeTimer(ControllerExtension->PortDeviceObject,
950 ScsiPortIoTimer,
951 ControllerExtension);
952
953 /* Copy port configuration in device extension */
954 memcpy(PortDeviceExtension,
955 PseudoDeviceExtension,
956 PseudoDeviceExtension->Length);
957
958 /* Copy access ranges */
959 AccessRangeSize =
960 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
961 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
962 AccessRangeSize);
963 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
964 PseudoDeviceExtension->PortConfig.AccessRanges,
965 AccessRangeSize);
966
967 /* FIXME: Copy or configure any more? */
968
969 /* Create the dos device */
970 swprintf(DosNameBuffer,
971 L"\\??\\Scsi%lu:",
972 PortNumber);
973 RtlInitUnicodeString(&DosDeviceName,
974 DosNameBuffer);
975
976 IoCreateSymbolicLink(&DosDeviceName,
977 &DeviceName);
978
979 return(STATUS_SUCCESS);
980 }
981
982
983
984 static BOOLEAN STDCALL
985 ScsiPortIsr(IN PKINTERRUPT Interrupt,
986 IN PVOID ServiceContext)
987 {
988 DPRINT1("ScsiPortIsr() called!\n");
989
990 return(TRUE);
991 }
992
993
994 // ScsiPortDpcForIsr
995 // DESCRIPTION:
996 //
997 // RUN LEVEL:
998 //
999 // ARGUMENTS:
1000 // IN PKDPC Dpc
1001 // IN PDEVICE_OBJECT DpcDeviceObject
1002 // IN PIRP DpcIrp
1003 // IN PVOID DpcContext
1004 //
1005 static VOID
1006 ScsiPortDpcForIsr(IN PKDPC Dpc,
1007 IN PDEVICE_OBJECT DpcDeviceObject,
1008 IN PIRP DpcIrp,
1009 IN PVOID DpcContext)
1010 {
1011 DPRINT("ScsiPortDpcForIsr()\n");
1012 // IDEFinishOperation((PIDE_CONTROLLER_EXTENSION) DpcContext);
1013 }
1014
1015
1016 // ScsiPortIoTimer
1017 // DESCRIPTION:
1018 // This function handles timeouts and other time delayed processing
1019 //
1020 // RUN LEVEL:
1021 //
1022 // ARGUMENTS:
1023 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1024 // IN PVOID Context the Controller extension for the
1025 // controller the device is on
1026 //
1027 static VOID STDCALL
1028 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1029 PVOID Context)
1030 {
1031 DPRINT("ScsiPortIoTimer()\n");
1032 }
1033
1034 /* EOF */