Patch by Hartmut Birr: protect IrpFlags with spinlock.
[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.22 2002/09/20 05:40:28 ei 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 <ddk/srb.h>
32 #include <ddk/scsi.h>
33 #include <ddk/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 typedef enum _SCSI_PORT_TIMER_STATES
46 {
47 IDETimerIdle,
48 IDETimerCmdWait,
49 IDETimerResetWaitForBusyNegate,
50 IDETimerResetWaitForDrdyAssert
51 } SCSI_PORT_TIMER_STATES;
52
53
54 /*
55 * SCSI_PORT_DEVICE_EXTENSION
56 *
57 * DESCRIPTION
58 * First part of the port objects device extension. The second
59 * part is the miniport-specific device extension.
60 */
61
62 typedef struct _SCSI_PORT_DEVICE_EXTENSION
63 {
64 ULONG Length;
65 ULONG MiniPortExtensionSize;
66 PORT_CONFIGURATION_INFORMATION PortConfig;
67 ULONG PortNumber;
68
69 KSPIN_LOCK IrpLock;
70 KSPIN_LOCK SpinLock;
71 PKINTERRUPT Interrupt;
72 PIRP CurrentIrp;
73 ULONG IrpFlags;
74
75 SCSI_PORT_TIMER_STATES TimerState;
76 LONG TimerCount;
77
78 BOOLEAN Initializing;
79
80 ULONG PortBusInfoSize;
81 PSCSI_ADAPTER_BUS_INFO PortBusInfo;
82
83 PIO_SCSI_CAPABILITIES PortCapabilities;
84
85 PDEVICE_OBJECT DeviceObject;
86 PCONTROLLER_OBJECT ControllerObject;
87
88 PHW_STARTIO HwStartIo;
89 PHW_INTERRUPT HwInterrupt;
90
91 PSCSI_REQUEST_BLOCK OriginalSrb;
92 SCSI_REQUEST_BLOCK InternalSrb;
93 SENSE_DATA InternalSenseData;
94
95 UCHAR MiniPortDeviceExtension[1]; /* must be the last entry */
96 } SCSI_PORT_DEVICE_EXTENSION, *PSCSI_PORT_DEVICE_EXTENSION;
97
98
99 /*
100 * SCSI_PORT_TIMER_STATES
101 *
102 * DESCRIPTION
103 * An enumeration containing the states in the timer DFA
104 */
105
106
107
108 #define IRP_FLAG_COMPLETE 0x00000001
109 #define IRP_FLAG_NEXT 0x00000002
110
111
112 /* GLOBALS *******************************************************************/
113
114 static NTSTATUS STDCALL
115 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
116 IN PIRP Irp);
117
118 static NTSTATUS STDCALL
119 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
120 IN PIRP Irp);
121
122 static NTSTATUS STDCALL
123 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
124 IN PIRP Irp);
125
126 static VOID STDCALL
127 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
128 IN PIRP Irp);
129
130 static IO_ALLOCATION_ACTION STDCALL
131 ScsiPortAllocateController(IN PDEVICE_OBJECT DeviceObject,
132 IN PIRP Irp,
133 IN PVOID MapRegisterBase,
134 IN PVOID Context);
135
136 static BOOLEAN STDCALL
137 ScsiPortStartPacket(IN OUT PVOID Context);
138
139 static NTSTATUS
140 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
141 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
142 IN ULONG PortCount);
143
144 static VOID
145 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension);
146
147 static BOOLEAN STDCALL
148 ScsiPortIsr(IN PKINTERRUPT Interrupt,
149 IN PVOID ServiceContext);
150
151 static VOID STDCALL
152 ScsiPortDpcForIsr(IN PKDPC Dpc,
153 IN PDEVICE_OBJECT DpcDeviceObject,
154 IN PIRP DpcIrp,
155 IN PVOID DpcContext);
156
157 static VOID STDCALL
158 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
159 PVOID Context);
160
161 static PSCSI_REQUEST_BLOCK
162 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
163 PSCSI_REQUEST_BLOCK OriginalSrb);
164
165 /* FUNCTIONS *****************************************************************/
166
167 /**********************************************************************
168 * NAME EXPORTED
169 * DriverEntry
170 *
171 * DESCRIPTION
172 * This function initializes the driver.
173 *
174 * RUN LEVEL
175 * PASSIVE_LEVEL
176 *
177 * ARGUMENTS
178 * DriverObject
179 * System allocated Driver Object for this driver.
180 *
181 * RegistryPath
182 * Name of registry driver service key.
183 *
184 * RETURN VALUE
185 * Status.
186 */
187
188 NTSTATUS STDCALL
189 DriverEntry(IN PDRIVER_OBJECT DriverObject,
190 IN PUNICODE_STRING RegistryPath)
191 {
192 DPRINT("ScsiPort Driver %s\n", VERSION);
193 return(STATUS_SUCCESS);
194 }
195
196
197 /**********************************************************************
198 * NAME EXPORTED
199 * ScsiDebugPrint
200 *
201 * DESCRIPTION
202 * Prints debugging messages.
203 *
204 * RUN LEVEL
205 * PASSIVE_LEVEL
206 *
207 * ARGUMENTS
208 * DebugPrintLevel
209 * Debug level of the given message.
210 *
211 * DebugMessage
212 * Pointer to printf()-compatible format string.
213 *
214 * ...
215 Additional output data (see printf()).
216 *
217 * RETURN VALUE
218 * None.
219 */
220
221 VOID
222 ScsiDebugPrint(IN ULONG DebugPrintLevel,
223 IN PCHAR DebugMessage,
224 ...)
225 {
226 char Buffer[256];
227 va_list ap;
228
229 #if 0
230 if (DebugPrintLevel > InternalDebugLevel)
231 return;
232 #endif
233
234 va_start(ap, DebugMessage);
235 vsprintf(Buffer, DebugMessage, ap);
236 va_end(ap);
237
238 DbgPrint(Buffer);
239 }
240
241
242 VOID STDCALL
243 ScsiPortCompleteRequest(IN PVOID HwDeviceExtension,
244 IN UCHAR PathId,
245 IN UCHAR TargetId,
246 IN UCHAR Lun,
247 IN UCHAR SrbStatus)
248 {
249 UNIMPLEMENTED;
250 }
251
252
253 ULONG STDCALL
254 ScsiPortConvertPhysicalAddressToUlong(IN SCSI_PHYSICAL_ADDRESS Address)
255 {
256 return(Address.u.LowPart);
257 }
258
259
260 VOID STDCALL
261 ScsiPortFlushDma(IN PVOID HwDeviceExtension)
262 {
263 UNIMPLEMENTED;
264 }
265
266
267 VOID STDCALL
268 ScsiPortFreeDeviceBase(IN PVOID HwDeviceExtension,
269 IN PVOID MappedAddress)
270 {
271 UNIMPLEMENTED;
272 }
273
274
275 ULONG STDCALL
276 ScsiPortGetBusData(IN PVOID DeviceExtension,
277 IN ULONG BusDataType,
278 IN ULONG SystemIoBusNumber,
279 IN ULONG SlotNumber,
280 IN PVOID Buffer,
281 IN ULONG Length)
282 {
283 return(HalGetBusData(BusDataType,
284 SystemIoBusNumber,
285 SlotNumber,
286 Buffer,
287 Length));
288 }
289
290
291 PVOID STDCALL
292 ScsiPortGetDeviceBase(IN PVOID HwDeviceExtension,
293 IN INTERFACE_TYPE BusType,
294 IN ULONG SystemIoBusNumber,
295 IN SCSI_PHYSICAL_ADDRESS IoAddress,
296 IN ULONG NumberOfBytes,
297 IN BOOLEAN InIoSpace)
298 {
299 ULONG AddressSpace;
300 PHYSICAL_ADDRESS TranslatedAddress;
301 PVOID VirtualAddress;
302 PVOID Buffer;
303 BOOLEAN rc;
304
305 AddressSpace = (ULONG)InIoSpace;
306
307 if (!HalTranslateBusAddress(BusType,
308 SystemIoBusNumber,
309 IoAddress,
310 &AddressSpace,
311 &TranslatedAddress))
312 return NULL;
313
314 /* i/o space */
315 if (AddressSpace != 0)
316 return (PVOID)TranslatedAddress.u.LowPart;
317
318 VirtualAddress = MmMapIoSpace(TranslatedAddress,
319 NumberOfBytes,
320 FALSE);
321
322 Buffer = ExAllocatePool(NonPagedPool,0x20);
323 if (Buffer == NULL)
324 return VirtualAddress;
325
326 return NULL; /* ?? */
327 }
328
329
330 PVOID STDCALL
331 ScsiPortGetLogicalUnit(IN PVOID HwDeviceExtension,
332 IN UCHAR PathId,
333 IN UCHAR TargetId,
334 IN UCHAR Lun)
335 {
336 UNIMPLEMENTED;
337 }
338
339
340 SCSI_PHYSICAL_ADDRESS STDCALL
341 ScsiPortGetPhysicalAddress(IN PVOID HwDeviceExtension,
342 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
343 IN PVOID VirtualAddress,
344 OUT ULONG *Length)
345 {
346 UNIMPLEMENTED;
347 }
348
349
350 PSCSI_REQUEST_BLOCK STDCALL
351 ScsiPortGetSrb(IN PVOID DeviceExtension,
352 IN UCHAR PathId,
353 IN UCHAR TargetId,
354 IN UCHAR Lun,
355 IN LONG QueueTag)
356 {
357 UNIMPLEMENTED;
358 }
359
360
361 PVOID STDCALL
362 ScsiPortGetUncachedExtension(IN PVOID HwDeviceExtension,
363 IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
364 IN ULONG NumberOfBytes)
365 {
366 UNIMPLEMENTED;
367 }
368
369
370 PVOID STDCALL
371 ScsiPortGetVirtualAddress(IN PVOID HwDeviceExtension,
372 IN SCSI_PHYSICAL_ADDRESS PhysicalAddress)
373 {
374 UNIMPLEMENTED;
375 }
376
377
378 /**********************************************************************
379 * NAME EXPORTED
380 * ScsiPortInitialize
381 *
382 * DESCRIPTION
383 * Initializes SCSI port driver specific data.
384 *
385 * RUN LEVEL
386 * PASSIVE_LEVEL
387 *
388 * ARGUMENTS
389 * Argument1
390 * Pointer to the miniport driver's driver object.
391 *
392 * Argument2
393 * Pointer to the miniport driver's registry path.
394 *
395 * HwInitializationData
396 * Pointer to port driver specific configuration data.
397 *
398 * HwContext
399 Miniport driver specific context.
400 *
401 * RETURN VALUE
402 * Status.
403 */
404
405 ULONG STDCALL
406 ScsiPortInitialize(IN PVOID Argument1,
407 IN PVOID Argument2,
408 IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
409 IN PVOID HwContext)
410 {
411 PDRIVER_OBJECT DriverObject = (PDRIVER_OBJECT)Argument1;
412 PUNICODE_STRING RegistryPath = (PUNICODE_STRING)Argument2;
413 PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension;
414 PCONFIGURATION_INFORMATION SystemConfig;
415 PPORT_CONFIGURATION_INFORMATION PortConfig;
416 BOOLEAN Again;
417 ULONG i;
418 ULONG Result;
419 NTSTATUS Status;
420 ULONG MaxBus;
421 PACCESS_RANGE AccessRanges;
422 ULONG ExtensionSize;
423
424 DPRINT("ScsiPortInitialize() called!\n");
425
426 if ((HwInitializationData->HwInitialize == NULL) ||
427 (HwInitializationData->HwStartIo == NULL) ||
428 (HwInitializationData->HwInterrupt == NULL) ||
429 (HwInitializationData->HwFindAdapter == NULL) ||
430 (HwInitializationData->HwResetBus == NULL))
431 return(STATUS_INVALID_PARAMETER);
432
433 DriverObject->DriverStartIo = ScsiPortStartIo;
434 DriverObject->MajorFunction[IRP_MJ_CREATE] = ScsiPortCreateClose;
435 DriverObject->MajorFunction[IRP_MJ_CLOSE] = ScsiPortCreateClose;
436 DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = ScsiPortDeviceControl;
437 DriverObject->MajorFunction[IRP_MJ_SCSI] = ScsiPortDispatchScsi;
438
439
440 SystemConfig = IoGetConfigurationInformation();
441
442 ExtensionSize = sizeof(SCSI_PORT_DEVICE_EXTENSION) +
443 HwInitializationData->DeviceExtensionSize;
444 PseudoDeviceExtension = ExAllocatePool(PagedPool,
445 ExtensionSize);
446 RtlZeroMemory(PseudoDeviceExtension,
447 ExtensionSize);
448 PseudoDeviceExtension->Length = ExtensionSize;
449 PseudoDeviceExtension->MiniPortExtensionSize = HwInitializationData->DeviceExtensionSize;
450 PseudoDeviceExtension->HwStartIo = HwInitializationData->HwStartIo;
451 PseudoDeviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
452
453 PortConfig = &PseudoDeviceExtension->PortConfig;
454
455 PortConfig->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
456 PortConfig->AdapterInterfaceType = HwInitializationData->AdapterInterfaceType;
457 PortConfig->InterruptMode =
458 (PortConfig->AdapterInterfaceType == PCIBus) ? LevelSensitive : Latched;
459 PortConfig->AtdiskPrimaryClaimed = SystemConfig->AtDiskPrimaryAddressClaimed;
460 PortConfig->AtdiskSecondaryClaimed = SystemConfig->AtDiskSecondaryAddressClaimed;
461 PortConfig->NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
462
463 PortConfig->AccessRanges =
464 ExAllocatePool(PagedPool,
465 sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
466
467
468 PortConfig->SystemIoBusNumber = 0;
469 PortConfig->SlotNumber = 0;
470
471 MaxBus = (PortConfig->AdapterInterfaceType == PCIBus) ? 8 : 1;
472
473 DPRINT("MaxBus: %lu\n", MaxBus);
474
475 while (TRUE)
476 {
477 DPRINT("Calling HwFindAdapter() for Bus %lu\n", PortConfig->SystemIoBusNumber);
478
479 // RtlZeroMemory(AccessRanges,
480 // sizeof(ACCESS_RANGE) * PortConfig->NumberOfAccessRanges);
481
482 RtlZeroMemory(PseudoDeviceExtension->MiniPortDeviceExtension,
483 PseudoDeviceExtension->MiniPortExtensionSize);
484
485 /* Note: HwFindAdapter is called once for each bus */
486 Result = (HwInitializationData->HwFindAdapter)(&PseudoDeviceExtension->MiniPortDeviceExtension,
487 HwContext,
488 NULL, /* BusInformation */
489 NULL, /* ArgumentString */
490 &PseudoDeviceExtension->PortConfig,
491 &Again);
492 DPRINT("HwFindAdapter() result: %lu\n", Result);
493
494 if (Result == SP_RETURN_FOUND)
495 {
496 DPRINT("ScsiPortInitialize(): Found HBA!\n");
497
498 Status = ScsiPortCreatePortDevice(DriverObject,
499 PseudoDeviceExtension,
500 SystemConfig->ScsiPortCount);
501
502 if (!NT_SUCCESS(Status))
503 {
504 DbgPrint("ScsiPortCreatePortDevice() failed! (Status 0x%lX)\n", Status);
505
506 ExFreePool(PortConfig->AccessRanges);
507 ExFreePool(PseudoDeviceExtension);
508
509 return(Status);
510 }
511
512 /* Update the configuration info */
513 SystemConfig->AtDiskPrimaryAddressClaimed = PortConfig->AtdiskPrimaryClaimed;
514 SystemConfig->AtDiskSecondaryAddressClaimed = PortConfig->AtdiskSecondaryClaimed;
515 SystemConfig->ScsiPortCount++;
516 }
517
518 if (Again == FALSE)
519 {
520 PortConfig->SystemIoBusNumber++;
521 PortConfig->SlotNumber = 0;
522 }
523
524 DPRINT("Bus: %lu MaxBus: %lu\n", PortConfig->SystemIoBusNumber, MaxBus);
525 if (PortConfig->SystemIoBusNumber >= MaxBus)
526 {
527 DPRINT("Scanned all buses!\n");
528 break;
529 }
530 }
531
532 ExFreePool(PortConfig->AccessRanges);
533 ExFreePool(PseudoDeviceExtension);
534
535 DPRINT("ScsiPortInitialize() done!\n");
536
537 return(STATUS_SUCCESS);
538 }
539
540
541 VOID STDCALL
542 ScsiPortIoMapTransfer(IN PVOID HwDeviceExtension,
543 IN PSCSI_REQUEST_BLOCK Srb,
544 IN ULONG LogicalAddress,
545 IN ULONG Length)
546 {
547 UNIMPLEMENTED;
548 }
549
550
551 VOID STDCALL
552 ScsiPortLogError(IN PVOID HwDeviceExtension,
553 IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
554 IN UCHAR PathId,
555 IN UCHAR TargetId,
556 IN UCHAR Lun,
557 IN ULONG ErrorCode,
558 IN ULONG UniqueId)
559 {
560 UNIMPLEMENTED;
561 }
562
563
564 VOID STDCALL
565 ScsiPortMoveMemory(OUT PVOID Destination,
566 IN PVOID Source,
567 IN ULONG Length)
568 {
569 RtlMoveMemory(Destination,
570 Source,
571 Length);
572 }
573
574
575 VOID
576 ScsiPortNotification(IN SCSI_NOTIFICATION_TYPE NotificationType,
577 IN PVOID HwDeviceExtension,
578 ...)
579 {
580 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
581
582 DPRINT("ScsiPortNotification() called\n");
583
584 DeviceExtension = CONTAINING_RECORD(HwDeviceExtension,
585 SCSI_PORT_DEVICE_EXTENSION,
586 MiniPortDeviceExtension);
587
588 DPRINT("DeviceExtension %p\n", DeviceExtension);
589
590 DPRINT("Initializing = %s\n", (DeviceExtension->Initializing)?"TRUE":"FALSE");
591
592 if (DeviceExtension->Initializing == TRUE)
593 return;
594
595 switch (NotificationType)
596 {
597 case RequestComplete:
598 DPRINT("Notify: RequestComplete\n");
599 DeviceExtension->IrpFlags |= IRP_FLAG_COMPLETE;
600 break;
601
602 case NextRequest:
603 DPRINT("Notify: NextRequest\n");
604 DeviceExtension->IrpFlags |= IRP_FLAG_NEXT;
605 break;
606
607 default:
608 break;
609 }
610 }
611
612
613 ULONG STDCALL
614 ScsiPortSetBusDataByOffset(IN PVOID DeviceExtension,
615 IN ULONG BusDataType,
616 IN ULONG SystemIoBusNumber,
617 IN ULONG SlotNumber,
618 IN PVOID Buffer,
619 IN ULONG Offset,
620 IN ULONG Length)
621 {
622 return(HalSetBusDataByOffset(BusDataType,
623 SystemIoBusNumber,
624 SlotNumber,
625 Buffer,
626 Offset,
627 Length));
628 }
629
630
631 BOOLEAN STDCALL
632 ScsiPortValidateRange(IN PVOID HwDeviceExtension,
633 IN INTERFACE_TYPE BusType,
634 IN ULONG SystemIoBusNumber,
635 IN SCSI_PHYSICAL_ADDRESS IoAddress,
636 IN ULONG NumberOfBytes,
637 IN BOOLEAN InIoSpace)
638 {
639 return(TRUE);
640 }
641
642
643 /* INTERNAL FUNCTIONS ********************************************************/
644
645 /**********************************************************************
646 * NAME INTERNAL
647 * ScsiPortCreateClose
648 *
649 * DESCRIPTION
650 * Answer requests for Create/Close calls: a null operation.
651 *
652 * RUN LEVEL
653 * PASSIVE_LEVEL
654 *
655 * ARGUMENTS
656 * DeviceObject
657 * Pointer to a device object.
658 *
659 * Irp
660 * Pointer to an IRP.
661 *
662 * ...
663 Additional output data (see printf()).
664 *
665 * RETURN VALUE
666 * Status.
667 */
668
669 static NTSTATUS STDCALL
670 ScsiPortCreateClose(IN PDEVICE_OBJECT DeviceObject,
671 IN PIRP Irp)
672 {
673 DPRINT("ScsiPortCreateClose()\n");
674
675 Irp->IoStatus.Status = STATUS_SUCCESS;
676 Irp->IoStatus.Information = FILE_OPENED;
677
678 IoCompleteRequest(Irp, IO_NO_INCREMENT);
679
680 return(STATUS_SUCCESS);
681 }
682
683
684 /**********************************************************************
685 * NAME INTERNAL
686 * ScsiPortDispatchScsi
687 *
688 * DESCRIPTION
689 * Answer requests for SCSI calls
690 *
691 * RUN LEVEL
692 * PASSIVE_LEVEL
693 *
694 * ARGUMENTS
695 * Standard dispatch arguments
696 *
697 * RETURNS
698 * NTSTATUS
699 */
700
701 static NTSTATUS STDCALL
702 ScsiPortDispatchScsi(IN PDEVICE_OBJECT DeviceObject,
703 IN PIRP Irp)
704 {
705 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
706 PIO_STACK_LOCATION Stack;
707 PSCSI_REQUEST_BLOCK Srb;
708 NTSTATUS Status = STATUS_SUCCESS;
709 ULONG DataSize = 0;
710
711 DPRINT("ScsiPortDispatchScsi(DeviceObject %p Irp %p)\n",
712 DeviceObject, Irp);
713
714 DeviceExtension = DeviceObject->DeviceExtension;
715 Stack = IoGetCurrentIrpStackLocation(Irp);
716
717 Srb = Stack->Parameters.Scsi.Srb;
718 if (Srb == NULL)
719 {
720 Status = STATUS_UNSUCCESSFUL;
721
722 Irp->IoStatus.Status = Status;
723 Irp->IoStatus.Information = 0;
724
725 IoCompleteRequest(Irp, IO_NO_INCREMENT);
726
727 return(Status);
728 }
729
730 DPRINT("Srb: %p\n", Srb);
731 DPRINT("Srb->Function: %lu\n", Srb->Function);
732 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
733
734 switch (Srb->Function)
735 {
736 case SRB_FUNCTION_EXECUTE_SCSI:
737 IoStartPacket(DeviceObject, Irp, NULL, NULL);
738 return(STATUS_PENDING);
739
740 case SRB_FUNCTION_SHUTDOWN:
741 case SRB_FUNCTION_FLUSH:
742 if (DeviceExtension->PortConfig.CachesData == TRUE)
743 {
744 IoStartPacket(DeviceObject, Irp, NULL, NULL);
745 return(STATUS_PENDING);
746 }
747 break;
748
749 case SRB_FUNCTION_CLAIM_DEVICE:
750 {
751 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
752 PSCSI_INQUIRY_DATA UnitInfo;
753 PINQUIRYDATA InquiryData;
754
755 DPRINT(" SRB_FUNCTION_CLAIM_DEVICE\n");
756 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
757
758 Srb->DataBuffer = NULL;
759
760 if (DeviceExtension->PortBusInfo != NULL)
761 {
762 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
763
764 if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
765 break;
766
767 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
768 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
769
770 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
771 {
772 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
773
774 if ((UnitInfo->TargetId == Srb->TargetId) &&
775 (UnitInfo->Lun == Srb->Lun) &&
776 (UnitInfo->DeviceClaimed == FALSE))
777 {
778 UnitInfo->DeviceClaimed = TRUE;
779 DPRINT("Claimed device!\n");
780
781 /* FIXME: Hack!!!!! */
782 Srb->DataBuffer = DeviceObject;
783
784 break;
785 }
786
787 if (UnitInfo->NextInquiryDataOffset == 0)
788 break;
789
790 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
791 }
792 }
793 }
794 break;
795
796 case SRB_FUNCTION_RELEASE_DEVICE:
797 {
798 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
799 PSCSI_INQUIRY_DATA UnitInfo;
800 PINQUIRYDATA InquiryData;
801
802 DPRINT(" SRB_FUNCTION_RELEASE_DEVICE\n");
803 DPRINT("PathId: %lu TargetId: %lu Lun: %lu\n", Srb->PathId, Srb->TargetId, Srb->Lun);
804
805 if (DeviceExtension->PortBusInfo != NULL)
806 {
807 AdapterInfo = (PSCSI_ADAPTER_BUS_INFO)DeviceExtension->PortBusInfo;
808
809 if (AdapterInfo->BusData[Srb->PathId].NumberOfLogicalUnits == 0)
810 break;
811
812 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo +
813 AdapterInfo->BusData[Srb->PathId].InquiryDataOffset);
814
815 while (AdapterInfo->BusData[Srb->PathId].InquiryDataOffset)
816 {
817 InquiryData = (PINQUIRYDATA)UnitInfo->InquiryData;
818
819 if ((UnitInfo->TargetId == Srb->TargetId) &&
820 (UnitInfo->Lun == Srb->Lun) &&
821 (UnitInfo->DeviceClaimed == TRUE))
822 {
823 UnitInfo->DeviceClaimed = FALSE;
824 DPRINT("Released device!\n");
825 break;
826 }
827
828 if (UnitInfo->NextInquiryDataOffset == 0)
829 break;
830
831 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)AdapterInfo + UnitInfo->NextInquiryDataOffset);
832 }
833 }
834 }
835 break;
836
837 default:
838 DPRINT1("SRB function not implemented (Function %lu)\n", Srb->Function);
839 Status = STATUS_NOT_IMPLEMENTED;
840 break;
841 }
842
843 Irp->IoStatus.Status = Status;
844 Irp->IoStatus.Information = DataSize;
845
846 IoCompleteRequest(Irp, IO_NO_INCREMENT);
847
848 return(Status);
849 }
850
851
852 /**********************************************************************
853 * NAME INTERNAL
854 * ScsiPortDeviceControl
855 *
856 * DESCRIPTION
857 * Answer requests for device control calls
858 *
859 * RUN LEVEL
860 * PASSIVE_LEVEL
861 *
862 * ARGUMENTS
863 * Standard dispatch arguments
864 *
865 * RETURNS
866 * NTSTATUS
867 */
868
869 static NTSTATUS STDCALL
870 ScsiPortDeviceControl(IN PDEVICE_OBJECT DeviceObject,
871 IN PIRP Irp)
872 {
873 PIO_STACK_LOCATION Stack;
874 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
875
876 DPRINT("ScsiPortDeviceControl()\n");
877
878 Irp->IoStatus.Status = STATUS_SUCCESS;
879 Irp->IoStatus.Information = 0;
880
881
882 Stack = IoGetCurrentIrpStackLocation(Irp);
883 DeviceExtension = DeviceObject->DeviceExtension;
884
885 switch (Stack->Parameters.DeviceIoControl.IoControlCode)
886 {
887
888 case IOCTL_SCSI_GET_CAPABILITIES:
889 {
890 DPRINT(" IOCTL_SCSI_GET_CAPABILITIES\n");
891
892 *((PIO_SCSI_CAPABILITIES *)Irp->AssociatedIrp.SystemBuffer) =
893 DeviceExtension->PortCapabilities;
894
895 Irp->IoStatus.Information = sizeof(PIO_SCSI_CAPABILITIES);
896 }
897 break;
898
899 case IOCTL_SCSI_GET_INQUIRY_DATA:
900 {
901 DPRINT(" IOCTL_SCSI_GET_INQUIRY_DATA\n");
902
903 /* Copy inquiry data to the port device extension */
904 memcpy(Irp->AssociatedIrp.SystemBuffer,
905 DeviceExtension->PortBusInfo,
906 DeviceExtension->PortBusInfoSize);
907
908 DPRINT("BufferSize: %lu\n", DeviceExtension->PortBusInfoSize);
909 Irp->IoStatus.Information = DeviceExtension->PortBusInfoSize;
910 }
911 break;
912
913 default:
914 DPRINT1(" unknown ioctl code: 0x%lX\n",
915 Stack->Parameters.DeviceIoControl.IoControlCode);
916 break;
917 }
918
919 IoCompleteRequest(Irp, IO_NO_INCREMENT);
920
921 return(STATUS_SUCCESS);
922 }
923
924
925 static VOID STDCALL
926 ScsiPortStartIo(IN PDEVICE_OBJECT DeviceObject,
927 IN PIRP Irp)
928 {
929 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
930 PIO_STACK_LOCATION IrpStack;
931 KIRQL OldIrql;
932
933 DPRINT("ScsiPortStartIo() called!\n");
934
935 DeviceExtension = DeviceObject->DeviceExtension;
936 IrpStack = IoGetCurrentIrpStackLocation(Irp);
937
938 // FIXME: implement the supported functions
939
940 switch (IrpStack->MajorFunction)
941 {
942 case IRP_MJ_SCSI:
943 {
944 BOOLEAN Result;
945 PSCSI_REQUEST_BLOCK Srb;
946 KIRQL oldIrql;
947
948 DPRINT("IRP_MJ_SCSI\n");
949
950 Srb = IrpStack->Parameters.Scsi.Srb;
951
952 DPRINT("DeviceExtension %p\n", DeviceExtension);
953
954 Irp->IoStatus.Status = STATUS_SUCCESS;
955 Irp->IoStatus.Information = Srb->DataTransferLength;
956
957 DeviceExtension->CurrentIrp = Irp;
958
959 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
960 ScsiPortStartPacket,
961 DeviceExtension))
962 {
963 DPRINT("Synchronization failed!\n");
964
965 Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
966 Irp->IoStatus.Information = 0;
967 IoCompleteRequest(Irp,
968 IO_NO_INCREMENT);
969 IoStartNextPacket(DeviceObject,
970 FALSE);
971 }
972 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
973 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
974 {
975 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
976 IoCompleteRequest(Irp,
977 IO_NO_INCREMENT);
978 }
979
980 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
981 {
982 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
983 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
984 IoStartNextPacket(DeviceObject,
985 FALSE);
986 }
987 else
988 {
989 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
990 }
991 }
992 break;
993
994 default:
995 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
996 Irp->IoStatus.Information = 0;
997 IoCompleteRequest(Irp,
998 IO_NO_INCREMENT);
999 IoStartNextPacket(DeviceObject,
1000 FALSE);
1001 break;
1002 }
1003 DPRINT("ScsiPortStartIo() done\n");
1004 }
1005
1006
1007 static BOOLEAN STDCALL
1008 ScsiPortStartPacket(IN OUT PVOID Context)
1009 {
1010 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1011 PIO_STACK_LOCATION IrpStack;
1012 PSCSI_REQUEST_BLOCK Srb;
1013
1014 DPRINT("ScsiPortStartPacket() called\n");
1015
1016 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)Context;
1017
1018 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1019 Srb = IrpStack->Parameters.Scsi.Srb;
1020
1021 return(DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1022 Srb));
1023 }
1024
1025
1026 /**********************************************************************
1027 * NAME INTERNAL
1028 * ScsiPortCreatePortDevice
1029 *
1030 * DESCRIPTION
1031 * Creates and initializes a SCSI port device object.
1032 *
1033 * RUN LEVEL
1034 * PASSIVE_LEVEL
1035 *
1036 * ARGUMENTS
1037 * DriverObject
1038 * ...
1039 *
1040 * PseudoDeviceExtension
1041 * ...
1042 *
1043 * PortNumber
1044 * ...
1045 *
1046 * RETURNS
1047 * NTSTATUS
1048 */
1049
1050 static NTSTATUS
1051 ScsiPortCreatePortDevice(IN PDRIVER_OBJECT DriverObject,
1052 IN PSCSI_PORT_DEVICE_EXTENSION PseudoDeviceExtension,
1053 IN ULONG PortNumber)
1054 {
1055 PSCSI_PORT_DEVICE_EXTENSION PortDeviceExtension;
1056 PIO_SCSI_CAPABILITIES PortCapabilities;
1057 PDEVICE_OBJECT PortDeviceObject;
1058 WCHAR NameBuffer[80];
1059 UNICODE_STRING DeviceName;
1060 WCHAR DosNameBuffer[80];
1061 UNICODE_STRING DosDeviceName;
1062 NTSTATUS Status;
1063 ULONG AccessRangeSize;
1064
1065 #if 0
1066 ULONG MappedIrq;
1067 KIRQL Dirql;
1068 KAFFINITY Affinity;
1069 #endif
1070
1071 DPRINT("ScsiPortCreatePortDevice() called\n");
1072
1073 #if 0
1074 MappedIrq = HalGetInterruptVector(PseudoDeviceExtension->PortConfig.AdapterInterfaceType,
1075 PseudoDeviceExtension->PortConfig.SystemIoBusNumber,
1076 0,
1077 PseudoDeviceExtension->PortConfig.BusInterruptLevel,
1078 &Dirql,
1079 &Affinity);
1080 #endif
1081
1082 /* Create a unicode device name */
1083 swprintf(NameBuffer,
1084 L"\\Device\\ScsiPort%lu",
1085 PortNumber);
1086 RtlInitUnicodeString(&DeviceName,
1087 NameBuffer);
1088
1089 DPRINT("Creating device: %wZ\n", &DeviceName);
1090
1091 /* Create the port device */
1092 Status = IoCreateDevice(DriverObject,
1093 PseudoDeviceExtension->Length,
1094 &DeviceName,
1095 FILE_DEVICE_CONTROLLER,
1096 0,
1097 FALSE,
1098 &PortDeviceObject);
1099 if (!NT_SUCCESS(Status))
1100 {
1101 DbgPrint("IoCreateDevice call failed! (Status 0x%lX)\n", Status);
1102 return(Status);
1103 }
1104
1105 DPRINT("Created device: %wZ\n", &DeviceName);
1106
1107 /* Set the buffering strategy here... */
1108 PortDeviceObject->Flags |= DO_DIRECT_IO;
1109 PortDeviceObject->AlignmentRequirement = FILE_WORD_ALIGNMENT;
1110
1111 PortDeviceExtension = PortDeviceObject->DeviceExtension;
1112
1113 /* Copy pseudo device extension into the real device extension */
1114 memcpy(PortDeviceExtension,
1115 PseudoDeviceExtension,
1116 PseudoDeviceExtension->Length);
1117
1118 /* Copy access ranges */
1119 AccessRangeSize =
1120 sizeof(ACCESS_RANGE) * PseudoDeviceExtension->PortConfig.NumberOfAccessRanges;
1121 PortDeviceExtension->PortConfig.AccessRanges = ExAllocatePool(NonPagedPool,
1122 AccessRangeSize);
1123 memcpy(PortDeviceExtension->PortConfig.AccessRanges,
1124 PseudoDeviceExtension->PortConfig.AccessRanges,
1125 AccessRangeSize);
1126
1127 PortDeviceExtension->DeviceObject = PortDeviceObject;
1128 PortDeviceExtension->PortNumber = PortNumber;
1129
1130 /* Initialize the spin lock in the controller extension */
1131 KeInitializeSpinLock(&PortDeviceExtension->IrpLock);
1132 KeInitializeSpinLock(&PortDeviceExtension->SpinLock);
1133
1134 /* Register an interrupt handler for this device */
1135 Status = IoConnectInterrupt(&PortDeviceExtension->Interrupt,
1136 ScsiPortIsr,
1137 PortDeviceExtension,
1138 &PortDeviceExtension->SpinLock,
1139 PortDeviceExtension->PortConfig.BusInterruptVector, // MappedIrq,
1140 PortDeviceExtension->PortConfig.BusInterruptLevel, // Dirql,
1141 15, //Dirql,
1142 PortDeviceExtension->PortConfig.InterruptMode,
1143 FALSE,
1144 0xFFFF, //Affinity,
1145 FALSE);
1146 if (!NT_SUCCESS(Status))
1147 {
1148 DbgPrint("Could not Connect Interrupt %d\n",
1149 PortDeviceExtension->PortConfig.BusInterruptVector);
1150 return(Status);
1151 }
1152
1153 /* Initialize the DPC object */
1154 IoInitializeDpcRequest(PortDeviceExtension->DeviceObject,
1155 ScsiPortDpcForIsr);
1156
1157 /* Initialize the device timer */
1158 PortDeviceExtension->TimerState = IDETimerIdle;
1159 PortDeviceExtension->TimerCount = 0;
1160 IoInitializeTimer(PortDeviceExtension->DeviceObject,
1161 ScsiPortIoTimer,
1162 PortDeviceExtension);
1163
1164 /* Initialize port capabilities */
1165 PortCapabilities = ExAllocatePool(NonPagedPool,
1166 sizeof(IO_SCSI_CAPABILITIES));
1167 PortDeviceExtension->PortCapabilities = PortCapabilities;
1168 PortCapabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
1169 PortCapabilities->MaximumTransferLength =
1170 PortDeviceExtension->PortConfig.MaximumTransferLength;
1171 PortCapabilities->MaximumPhysicalPages =
1172 PortCapabilities->MaximumTransferLength / PAGESIZE;
1173 PortCapabilities->SupportedAsynchronousEvents = 0; /* FIXME */
1174 PortCapabilities->AlignmentMask =
1175 PortDeviceExtension->PortConfig.AlignmentMask;
1176 PortCapabilities->TaggedQueuing =
1177 PortDeviceExtension->PortConfig.TaggedQueuing;
1178 PortCapabilities->AdapterScansDown =
1179 PortDeviceExtension->PortConfig.AdapterScansDown;
1180 PortCapabilities->AdapterUsesPio = TRUE; /* FIXME */
1181
1182 /* Initialize inquiry data */
1183 PortDeviceExtension->PortBusInfoSize = 0;
1184 PortDeviceExtension->PortBusInfo = NULL;
1185
1186 DPRINT("DeviceExtension %p\n", PortDeviceExtension);
1187 ScsiPortInquire(PortDeviceExtension);
1188
1189
1190 /* FIXME: Copy more configuration data? */
1191
1192 /* Create the dos device link */
1193 swprintf(DosNameBuffer,
1194 L"\\??\\Scsi%lu:",
1195 PortNumber);
1196 RtlInitUnicodeString(&DosDeviceName,
1197 DosNameBuffer);
1198
1199 IoCreateSymbolicLink(&DosDeviceName,
1200 &DeviceName);
1201
1202 DPRINT("ScsiPortCreatePortDevice() done\n");
1203
1204 return(STATUS_SUCCESS);
1205 }
1206
1207
1208 static VOID
1209 ScsiPortInquire(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1210 {
1211 PSCSI_ADAPTER_BUS_INFO AdapterInfo;
1212 PSCSI_INQUIRY_DATA UnitInfo, PrevUnit;
1213 SCSI_REQUEST_BLOCK Srb;
1214 ULONG Bus;
1215 ULONG Target;
1216 ULONG UnitCount;
1217 ULONG DataSize;
1218 BOOLEAN Result;
1219
1220 DPRINT("ScsiPortInquire() called\n");
1221
1222 DeviceExtension->Initializing = TRUE;
1223
1224 /* Copy inquiry data to the port device extension */
1225 AdapterInfo =(PSCSI_ADAPTER_BUS_INFO)ExAllocatePool(NonPagedPool, 4096);
1226 RtlZeroMemory(AdapterInfo, 4096);
1227 AdapterInfo->NumberOfBuses = DeviceExtension->PortConfig.NumberOfBuses;
1228
1229 UnitInfo = (PSCSI_INQUIRY_DATA)
1230 ((PUCHAR)AdapterInfo + sizeof(SCSI_ADAPTER_BUS_INFO) +
1231 (sizeof(SCSI_BUS_DATA) * (AdapterInfo->NumberOfBuses - 1)));
1232
1233 RtlZeroMemory(&Srb,
1234 sizeof(SCSI_REQUEST_BLOCK));
1235 Srb.DataBuffer = ExAllocatePool(NonPagedPool, 256);
1236 Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
1237 Srb.DataTransferLength = 256;
1238 Srb.Cdb[0] = SCSIOP_INQUIRY;
1239
1240 for (Bus = 0; Bus < AdapterInfo->NumberOfBuses; Bus++)
1241 {
1242 Srb.PathId = Bus;
1243
1244 AdapterInfo->BusData[Bus].InitiatorBusId = 0; /* ? */
1245 AdapterInfo->BusData[Bus].InquiryDataOffset =
1246 (ULONG)((PUCHAR)UnitInfo - (PUCHAR)AdapterInfo);
1247
1248 PrevUnit = NULL;
1249 UnitCount = 0;
1250
1251 for (Target = 0; Target < DeviceExtension->PortConfig.MaximumNumberOfTargets; Target++)
1252 {
1253 Srb.TargetId = Target;
1254 Srb.Lun = 0;
1255 Srb.SrbStatus = SRB_STATUS_SUCCESS;
1256
1257 Result = DeviceExtension->HwStartIo(&DeviceExtension->MiniPortDeviceExtension,
1258 &Srb);
1259 DPRINT("Result: %s Srb.SrbStatus %lx\n", (Result)?"True":"False", Srb.SrbStatus);
1260
1261 if (Result == TRUE && Srb.SrbStatus == SRB_STATUS_SUCCESS)
1262 {
1263 UnitInfo->PathId = Bus;
1264 UnitInfo->TargetId = Target;
1265 UnitInfo->Lun = 0;
1266 UnitInfo->InquiryDataLength = INQUIRYDATABUFFERSIZE;
1267 memcpy(&UnitInfo->InquiryData,
1268 Srb.DataBuffer,
1269 INQUIRYDATABUFFERSIZE);
1270 if (PrevUnit != NULL)
1271 PrevUnit->NextInquiryDataOffset = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1272 PrevUnit = UnitInfo;
1273 UnitInfo = (PSCSI_INQUIRY_DATA)((PUCHAR)UnitInfo + sizeof(SCSI_INQUIRY_DATA)+INQUIRYDATABUFFERSIZE-1);
1274 UnitCount++;
1275 }
1276 }
1277 DPRINT("UnitCount: %lu\n", UnitCount);
1278 AdapterInfo->BusData[Bus].NumberOfLogicalUnits = UnitCount;
1279 if (UnitCount == 0)
1280 AdapterInfo->BusData[Bus].InquiryDataOffset = 0;
1281 }
1282 DataSize = (ULONG)((PUCHAR)UnitInfo-(PUCHAR)AdapterInfo);
1283
1284 ExFreePool(Srb.DataBuffer);
1285
1286 DeviceExtension->Initializing = FALSE;
1287
1288 /* copy inquiry data to the port driver's device extension */
1289 DeviceExtension->PortBusInfoSize = DataSize;
1290 DeviceExtension->PortBusInfo = ExAllocatePool(NonPagedPool,
1291 DataSize);
1292 RtlCopyMemory(DeviceExtension->PortBusInfo,
1293 AdapterInfo,
1294 DataSize);
1295
1296 ExFreePool(AdapterInfo);
1297
1298 DPRINT("ScsiPortInquire() done\n");
1299 }
1300
1301
1302 static BOOLEAN STDCALL
1303 ScsiPortIsr(IN PKINTERRUPT Interrupt,
1304 IN PVOID ServiceContext)
1305 {
1306 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1307 BOOLEAN Result;
1308
1309 DPRINT("ScsiPortIsr() called!\n");
1310
1311 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)ServiceContext;
1312
1313 Result = DeviceExtension->HwInterrupt(&DeviceExtension->MiniPortDeviceExtension);
1314 if (Result == FALSE)
1315 {
1316 return(FALSE);
1317 }
1318
1319 if (DeviceExtension->IrpFlags)
1320 {
1321 IoRequestDpc(DeviceExtension->DeviceObject,
1322 DeviceExtension->CurrentIrp,
1323 DeviceExtension);
1324 }
1325
1326 return(TRUE);
1327 }
1328
1329
1330 // ScsiPortDpcForIsr
1331 // DESCRIPTION:
1332 //
1333 // RUN LEVEL:
1334 //
1335 // ARGUMENTS:
1336 // IN PKDPC Dpc
1337 // IN PDEVICE_OBJECT DpcDeviceObject
1338 // IN PIRP DpcIrp
1339 // IN PVOID DpcContext
1340 //
1341 static VOID STDCALL
1342 ScsiPortDpcForIsr(IN PKDPC Dpc,
1343 IN PDEVICE_OBJECT DpcDeviceObject,
1344 IN PIRP DpcIrp,
1345 IN PVOID DpcContext)
1346 {
1347 PSCSI_PORT_DEVICE_EXTENSION DeviceExtension;
1348 PIO_STACK_LOCATION IrpStack;
1349 PSCSI_REQUEST_BLOCK Srb;
1350 KIRQL oldIrql;
1351
1352 DPRINT("ScsiPortDpcForIsr(Dpc %p DpcDeviceObject %p DpcIrp %p DpcContext %p)\n",
1353 Dpc, DpcDeviceObject, DpcIrp, DpcContext);
1354
1355 DeviceExtension = (PSCSI_PORT_DEVICE_EXTENSION)DpcContext;
1356
1357 KeAcquireSpinLock(&DeviceExtension->IrpLock, &oldIrql);
1358 if (DeviceExtension->IrpFlags)
1359 {
1360 IrpStack = IoGetCurrentIrpStackLocation(DeviceExtension->CurrentIrp);
1361 Srb = IrpStack->Parameters.Scsi.Srb;
1362
1363 if (DeviceExtension->OriginalSrb != NULL)
1364 {
1365 DPRINT("Got sense data!\n");
1366
1367 DPRINT("Valid: %x\n", DeviceExtension->InternalSenseData.Valid);
1368 DPRINT("ErrorCode: %x\n", DeviceExtension->InternalSenseData.ErrorCode);
1369 DPRINT("SenseKey: %x\n", DeviceExtension->InternalSenseData.SenseKey);
1370 DPRINT("SenseCode: %x\n", DeviceExtension->InternalSenseData.AdditionalSenseCode);
1371
1372 /* Copy sense data */
1373 if (DeviceExtension->OriginalSrb->SenseInfoBufferLength != 0)
1374 {
1375 RtlCopyMemory(DeviceExtension->OriginalSrb->SenseInfoBuffer,
1376 &DeviceExtension->InternalSenseData,
1377 sizeof(SENSE_DATA));
1378 DeviceExtension->OriginalSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
1379 }
1380
1381 /* Clear current sense data */
1382 RtlZeroMemory(&DeviceExtension->InternalSenseData, sizeof(SENSE_DATA));
1383
1384 IrpStack->Parameters.Scsi.Srb = DeviceExtension->OriginalSrb;
1385 DeviceExtension->OriginalSrb = NULL;
1386 }
1387 else if ((SRB_STATUS(Srb->SrbStatus) != SRB_STATUS_SUCCESS) &&
1388 (Srb->ScsiStatus == SCSISTAT_CHECK_CONDITION))
1389 {
1390 DPRINT("SCSIOP_REQUEST_SENSE required!\n");
1391
1392 DeviceExtension->OriginalSrb = Srb;
1393 IrpStack->Parameters.Scsi.Srb = ScsiPortInitSenseRequestSrb(DeviceExtension,
1394 Srb);
1395 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1396 if (!KeSynchronizeExecution(DeviceExtension->Interrupt,
1397 ScsiPortStartPacket,
1398 DeviceExtension))
1399 {
1400 DPRINT("Synchronization failed!\n");
1401
1402 DpcIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
1403 DpcIrp->IoStatus.Information = 0;
1404 IoCompleteRequest(DpcIrp,
1405 IO_NO_INCREMENT);
1406 IoStartNextPacket(DpcDeviceObject,
1407 FALSE);
1408 }
1409
1410 return;
1411 }
1412
1413 DeviceExtension->CurrentIrp = NULL;
1414
1415
1416 // DpcIrp->IoStatus.Information = 0;
1417 // DpcIrp->IoStatus.Status = STATUS_SUCCESS;
1418
1419 if (DeviceExtension->IrpFlags & IRP_FLAG_COMPLETE)
1420 {
1421 DeviceExtension->IrpFlags &= ~IRP_FLAG_COMPLETE;
1422 IoCompleteRequest(DpcIrp, IO_NO_INCREMENT);
1423 }
1424
1425 if (DeviceExtension->IrpFlags & IRP_FLAG_NEXT)
1426 {
1427 DeviceExtension->IrpFlags &= ~IRP_FLAG_NEXT;
1428 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1429 IoStartNextPacket(DpcDeviceObject, FALSE);
1430 }
1431 else
1432 {
1433 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1434 }
1435 }
1436 else
1437 {
1438 KeReleaseSpinLock(&DeviceExtension->IrpLock, oldIrql);
1439 }
1440 DPRINT("ScsiPortDpcForIsr() done\n");
1441 }
1442
1443
1444 // ScsiPortIoTimer
1445 // DESCRIPTION:
1446 // This function handles timeouts and other time delayed processing
1447 //
1448 // RUN LEVEL:
1449 //
1450 // ARGUMENTS:
1451 // IN PDEVICE_OBJECT DeviceObject Device object registered with timer
1452 // IN PVOID Context the Controller extension for the
1453 // controller the device is on
1454 //
1455 static VOID STDCALL
1456 ScsiPortIoTimer(PDEVICE_OBJECT DeviceObject,
1457 PVOID Context)
1458 {
1459 DPRINT1("ScsiPortIoTimer()\n");
1460 }
1461
1462
1463 static PSCSI_REQUEST_BLOCK
1464 ScsiPortInitSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension,
1465 PSCSI_REQUEST_BLOCK OriginalSrb)
1466 {
1467 PSCSI_REQUEST_BLOCK Srb;
1468 PCDB Cdb;
1469
1470 Srb = &DeviceExtension->InternalSrb;
1471
1472 RtlZeroMemory(Srb,
1473 sizeof(SCSI_REQUEST_BLOCK));
1474
1475 Srb->PathId = OriginalSrb->PathId;
1476 Srb->TargetId = OriginalSrb->TargetId;
1477 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
1478 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
1479 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER;
1480
1481 Srb->TimeOutValue = 4;
1482
1483 Srb->CdbLength = 6;
1484 Srb->DataBuffer = &DeviceExtension->InternalSenseData;
1485 Srb->DataTransferLength = sizeof(SENSE_DATA);
1486
1487 Cdb = (PCDB)Srb->Cdb;
1488 Cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
1489 Cdb->CDB6INQUIRY.AllocationLength = sizeof(SENSE_DATA);
1490
1491 return(Srb);
1492 }
1493
1494
1495 static VOID
1496 ScsiPortFreeSenseRequestSrb(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1497 {
1498 DeviceExtension->OriginalSrb = NULL;
1499 }
1500
1501
1502 #if 0
1503 static NTSTATUS
1504 ScsiPortBuildDeviceMap(PSCSI_PORT_DEVICE_EXTENSION DeviceExtension)
1505 {
1506 OBJECT_ATTRIBUTES ObjectAttributes;
1507 UNICODE_STRING KeyName;
1508 WCHAR NameBuffer[32];
1509 ULONG Disposition;
1510 HANDLE ScsiKey;
1511 HANDLE ScsiPortKey;
1512 HANDLE ScsiBusKey;
1513 HANDLE ScsiTargetKey;
1514 HANDLE ScsiUnitKey;
1515 ULONG BusNumber;
1516 NTSTATUS Status;
1517
1518 /* Open or create the 'Scsi' subkey */
1519 RtlInitUnicodeStringFromLiteral(&KeyName,
1520 L"\\Registry\\Machine\\Hardware\\DeviceMap\\Scsi");
1521 InitializeObjectAttributes(&ObjectAttributes,
1522 &KeyName,
1523 OBJ_OPENIF,
1524 0,
1525 NULL);
1526 Status = NtCreateKey(&ScsiKey,
1527 KEY_ALL_ACCESS,
1528 &ObjectAttributes,
1529 0,
1530 NULL,
1531 REG_OPTION_VOLATILE,
1532 &Disposition);
1533 if (!NT_SUCCESS(Status))
1534 return(Status);
1535
1536 /* Create new 'Scsi Port X' subkey */
1537 swprintf(NameBuffer,
1538 L"Scsi Port %lu",
1539 DeviceExtension->PortNumber);
1540 RtlInitUnicodeString(&KeyName,
1541 NameBuffer);
1542 InitializeObjectAttributes(&ObjectAttributes,
1543 &KeyName,
1544 0,
1545 ScsiKey,
1546 NULL);
1547 Status = NtCreateKey(&ScsiPortKey,
1548 KEY_ALL_ACCESS,
1549 &ObjectAttributes,
1550 0,
1551 NULL,
1552 REG_OPTION_VOLATILE,
1553 &Disposition);
1554 if (!NT_SUCCESS(Status))
1555 {
1556 NtClose(ScsiKey);
1557 return(Status);
1558 }
1559
1560 /* Add port-specific values */
1561
1562 /* 'DMA Enabled' (REG_DWORD) */
1563 DPRINT1("DMA Enabled = %s\n",
1564 (DeviceExtension->PortCapabilities->AdapterUsesPio)?"TRUE":"FALSE");
1565
1566 /* 'Driver' (REG_SZ) */
1567
1568 /* 'Interrupt' (REG_DWORD) (NT4 only) */
1569 DPRINT1("Interrupt = %lx\n", DeviceExtension->PortConfig.BusInterruptLevel);
1570
1571 /* 'IOAddress' (REG_DWORD) (NT4 only) */
1572 DPRINT1("IOAddress = %lx\n",
1573 ScsiPortConvertPhysicalAddressToUlong(DeviceExtension->PortConfig.AccessRanges[0].RangeStart));
1574
1575
1576 /* Create 'Scsi Bus X' keys */
1577 for (BusNumber = 0; BusNumber < DeviceExtension->PortConfig.NumberOfBuses; BusNumber++)
1578 {
1579 swprintf(NameBuffer,
1580 L"Scsi Bus %lu",
1581 DeviceExtension->PortNumber);
1582 RtlInitUnicodeString(&KeyName,
1583 NameBuffer);
1584 InitializeObjectAttributes(&ObjectAttributes,
1585 &KeyName,
1586 0,
1587 ScsiPortKey,
1588 NULL);
1589 Status = NtCreateKey(&ScsiBusKey,
1590 KEY_ALL_ACCESS,
1591 &ObjectAttributes,
1592 0,
1593 NULL,
1594 REG_OPTION_VOLATILE,
1595 &Disposition);
1596 if (!NT_SUCCESS(Status))
1597 {
1598 NtClose(ScsiPortKey);
1599 NtClose(ScsiKey);
1600 return(Status);
1601 }
1602
1603 /* Create target keys */
1604
1605
1606 NtClose(ScsiBusKey);
1607 }
1608
1609 NtClose(ScsiPortKey);
1610 NtClose(ScsiKey);
1611
1612 return(Status);
1613 }
1614 #endif
1615
1616 /* EOF */