Jump to content

Dietmar

Member
  • Posts

    1,852
  • Joined

  • Last visited

  • Days Won

    10
  • Donations

    0.00 USD 
  • Country

    Germany

Everything posted by Dietmar

  1. Oh..my, sometimes only the dirtiest hack give you success.. I sit like a drunk duck in polling (Windows timer 15.6 ms) for the i219 lan Driver under XP SP3. IRQ registration never succeeded → so RX got serviced only on the timer. So.. I changed the IRQ-registration via this crazy hack 1) Now I try 3 candidate interrupt pairs: - a->IrqVector / a->IrqLevel NdisMQueryAdapterResources, mostly (?!) works but not for me and XP. - a->IrqSysVector / a->IrqSysLevel - a->IrqBusVector / a->IrqBusLevel What this hack is doing: - On modern boards with IOAPIC routing, XP/NDIS can expose interrupt information in multiple.. “views” (resource list, system-translated, bus-related). - If you pick only one pair (the “clean” way), NdisMRegisterInterrupt may fail or the IRQ never fires, and you fall back to timer-driven polling, means a ping of 15 ms. Hack: During MiniportInitialize, take the (Vector,Level) pairs XP already reports, and try registering them in the above order. The first pair that NdisMRegisterInterrupt accepts, becomes the selected IRQ configuration. Only ONE pair is used in the end(!). 2) I normalized BOTH vector and level when XP/IOAPIC gives “translated” values: Here with my values on Asrock z370 k6 board (from my working setup: Vector = 97, Level/IRQ-line = 5) On my compi, the “real” pair is: - vec = 97 decimal = 0x61 - lvl = 5 decimal = 0x05 Now the XP/IOAPIC “translated” case looks like this (same information, just encoded): - raw vec = 0x361 (this is in 0x300..0x3FF) - raw lvl = 0x305 (this is in 0x300..0x3FF) Normalization rule: - if value in 0x300..0x3FF => value = value - 0x300 Do the math (HEX): - vec: 0x361 - 0x300 = 0x061 => 0x61 = 97 decimal - lvl: 0x305 - 0x300 = 0x005 => 0x05 = 5 decimal So after this normalization you end up exactly at your usable XP pair: - vec = 0x61 (97) - lvl = 0x05 (5) If XP already reports normal values (not translated), nothing changes: - raw vec = 0x61 => not in 0x300..0x3FF => keep 0x61 - raw lvl = 0x05 => not in 0x300..0x3FF => keep 0x05 Before, sometimes I had a good vector but a still-translated level, so NdisMRegisterInterrupt failed and I stayed in polling forever, ping always 15 ms, but via IRQ to my router at 192.168.2.1 ping time should be <1 ms. 3) Now I force the XP-safe interrupt mode - shared = TRUE - mode = NdisInterruptLevelSensitive Why this works - This matches how INTx behind IOAPIC behaves in practice on modern chipsets (like crazy). - “Edge” / “not shared” settings are a common reason for missed / never-fired interrupts on XP. Dietmar PS: Because I have no idea, how to test the quality of my driver i219 for XP SP3, I would be very happy, if a user here can do this for me or gives me Tutorial, how to do this by myself. PPS: Here is this my version of the i219 lan driver, running under XP SP3. Now it is the fastest lan, that I ever had. https://files.catbox.moe/rmxl63.zip
  2. Oh..I spend soso many hours to overcome the crazy ULP etc. on this crazy lan chip i219 Dev_15B8. Now for the very first time I come to 100 MB/s, before it was ALWAYS only 10 MB/s because of crazy energy saving.. Here is this driver i219 for XP SP3 Dietmar https://files.catbox.moe/ye06bv.zip Tutorial (MSFN): Getting 100 Mb/s (Fast Ethernet) link on Intel i219 (DEV_15B8) under Windows XP SP3 — the ULP/LPLU “crazy register” fix Problem we hit On i219 (PCH-integrated PHY), Windows XP does not handle Intel’s modern low-power PHY/MAC features correctly. The PHY can stay in (or partially return to) low-power states after reset / link events, which can break auto-negotiation and leave you stuck at 10 Mb/s or with unstable negotiation. What finally made 100 Mb/s work (our “fixed6” build) We had to do two things together: 1) Force a clean exit from ULP/DPG and “sticky” low-power configuration 2) Disable LPLU and restart auto-negotiation with a clean 100FD advertisement ──────────────────────────────────────────────────────────────────────────── 1) ULP / DPG: force the PHY fully “awake” (exit Ultra Low Power) Key idea: ULP settings can be sticky and survive resets. When leaving ULP, hardware may have disabled K1 automatically; you must re-enable it explicitly. Registers involved (names from Linux e1000e): - E1000_H2ME (0x05B50) + bits START_DPG / EXIT_DPG / ULP (Host↔ME handshake) - FWSM flags like ULP_CFG_DONE and EXFWSM_DPG_EXIT_DONE (status/handshake) - PHY reg I218_ULP_CONFIG1 (page 779, reg 16) with bits: STICKY_ULP, INBAND_EXIT, RESET_TO_SMBUS, WOL_HOST, etc. - PHY reg HV_PM_CTRL (page 770, reg 17): HV_PM_CTRL_K1_ENABLE - PHY reg CV_SMB_CTRL (page 769, reg 23): clear FORCE_SMBUS if set - MAC regs: CTRL_EXT (unforce SMBus), FEXTNVM7 (DISABLE_SMB_PERST handling) Minimal “XP-friendly” sequence (conceptual checklist): - Ensure you are allowed to touch PHY regs (lock/semaphore in your driver as needed). - If the platform uses ME/DPG: request DPG exit and/or wait for DPG_EXIT_DONE / ULP_CFG_DONE style indications. - Unforce SMBus mode: - PHY: clear CV_SMB_CTRL_FORCE_SMBUS - MAC: clear CTRL_EXT_FORCE_SMBUS - Re-enable K1 on exit: - PHY: set HV_PM_CTRL_K1_ENABLE - Clear all “ULP enabled configuration” bits in I218_ULP_CONFIG1: - clear at least: IND, STICKY_ULP, RESET_TO_SMBUS, WOL_HOST, INBAND_EXIT, EN_ULP_LANPHYPC, DIS_CLR_STICKY_ON_PERST, DISABLE_SMB_PERST - Commit those PHY changes: - set I218_ULP_CONFIG1_START once after writing - (Optional but recommended for XP testing) ensure DPG is not forced: - set DPGFR to a “not forced” state (typically clearing force bits / leaving default) Why this matters for 100 Mb/s: If the PHY is still partially in ULP / SMBus-forced mode, auto-negotiation can behave “wrong” (bad timing, wrong advertised set, negotiation never completes correctly), especially with XP’s older network stack and power handling. ──────────────────────────────────────────────────────────────────────────── 2) LPLU: disable Low Power Link Up and restart Auto-Negotiation Key idea: LPLU is meant to save power during Dx states. Under XP, it can interfere with negotiation and speed switching. We disabled it and forced a clean auto-neg restart. Registers involved (names from Linux e1000e): - PHY reg HV_OEM_BITS (page 768, reg 25): - HV_OEM_BITS_LPLU (Low Power Link Up) - HV_OEM_BITS_GBE_DIS (Gigabit disable — useful when forcing 10/100 only) - HV_OEM_BITS_RESTART_AN (Restart auto-negotiation) - MAC reg PHY_CTRL (CSR offset 0x00F10) contains LPLU/GBE control bits mirrored into OEM bits on some PCH designs. What we did in practice: - Make sure LPLU is OFF: - clear HV_OEM_BITS_LPLU - clear any LPLU-related bits in PHY_CTRL (PCH-integrated PHY control) - Advertise only what you want (100FD in our case): - Disable/clear 1000Base-T advertisement (and/or set HV_OEM_BITS_GBE_DIS) - Set 10/100 advertisement so that 100 Full Duplex is included (or only 100FD if you want strict) - Restart auto-neg: - set HV_OEM_BITS_RESTART_AN (or trigger autoneg restart via standard PHY control) - Wait for link-up, then read speed/duplex. Practical note (important): Some PCH designs won’t fully apply LPLU changes unless you also do an explicit auto-neg restart. That restart is what finally made the PHY “re-decide” with the corrected (non-low-power) configuration. ──────────────────────────────────────────────────────────────────────────── 3) What to post as the “takeaway” for other XP users If your i219 under XP is stuck at 10 Mb/s or negotiation behaves strangely, try this order: 1) Exit ULP cleanly (clear sticky ULP, unforce SMBus, commit with START, re-enable K1) 2) Disable LPLU 3) Force/limit advertisement (e.g., 10/100 only, or 100FD) 4) Restart auto-neg That combination was the first time we got a stable 100 Mb/s link on DEV_15B8 with XP SP3. ──────────────────────────────────────────────────────────────────────────── Complete Sources (links you can cite on MSFN) 1) Linux kernel e1000e (PCH/i217/i218/i219) — ULP disable flow + K1 re-enable + clearing I218_ULP_CONFIG1: https://codebrowser.dev/linux/linux/drivers/net/ethernet/intel/e1000e/ich8lan.c.html 2) Linux kernel e1000e — ULP/LPLU/ME/DPG related defines (I218_ULP_CONFIG1 bits, HV_OEM_BITS, HV_PM_CTRL_K1_ENABLE, H2ME bits): https://codebrowser.dev/linux/linux/drivers/net/ethernet/intel/e1000e/ich8lan.h.html 3) Linux kernel e1000e — MAC register offsets used here (PHY_CTRL 0x00F10, DPGFR 0x00FAC, CTRL_EXT, FEXTNVM7, etc.): https://codebrowser.dev/linux/linux/drivers/net/ethernet/intel/e1000e/regs.h.html 4) (For historical macro values referenced in some trees) E1000_PHY_CTRL_D0A_LPLU / E1000_PHY_CTRL_NOND0A_LPLU definitions (older e1000 header docs): https://docs.huihoo.com/doxygen/linux/kernel/3.7/e1000_2e1000__hw_8h_source.html
  3. How to switch from Polling mode to legacy IRQ for the i219 lan driver under XP SP3 1) MSI/MSI-X must be OFF on XP → force legacy INTx On PCIe NICs (like Intel i219), the device can deliver interrupts either via MSI/MSI-X (message writes) or via legacy INTx (asserting the interrupt pin). For Windows XP / NDIS 5.1, the safest path is: MSI=OFF, MSI-X=OFF, INTx allowed. If MSI/MSI-X stays enabled, XP may never get a working line-based interrupt even if you “see IRQ resources”. How to do it (PCI configuration space): A) Find MSI / MSI-X capability blocks - Walk the PCI “Capabilities List” (linked list) in config space until you find: - Capability ID 0x05 = MSI - Capability ID 0x11 = MSI-X B) Disable MSI (CapID 0x05) - In the MSI capability structure, clear the “MSI Enable” bit in the MSI Message Control register: - MSI Enable = 0 C) Disable MSI-X (CapID 0x11) - In the MSI-X capability structure, clear the “MSI-X Enable” bit in the MSI-X Message Control register: - MSI-X Enable = 0 D) Ensure INTx is not blocked by PCI Command (offset 0x04) - Set the basic required bits: - Memory Space Enable = 1 (MMIO BAR works) - Bus Master Enable = 1 (DMA works) - And the critical INTx kill-switch must be OFF: - Interrupt Disable (bit 10) = 0 If bit 10 is 1, INTx is blocked even if everything else is correct. Resulting goal state for XP: - MSI Enable = 0 - MSI-X Enable = 0 - PCI Command.IntDisable(bit10) = 0 - PCI Command.MEM=1 and BusMaster=1 2) Fixing NdisMRegisterInterrupt returning STATUS_UNSUCCESSFUL = 0xC0000001 If NdisMRegisterInterrupt(...) returns 0xC0000001 (STATUS_UNSUCCESSFUL), a very common XP/NDIS 5.1 mistake is passing the “wrong kind” of interrupt vector/level. The core rule (this was the real breakthrough): Call NdisMRegisterInterrupt using BUS-relative values from AllocatedResources, NOT translated/system values from TranslatedResources. Why this matters: NDIS does not want you to pre-map vectors. Internally, NdisMRegisterInterrupt performs the mapping itself: - it calls HalGetInterruptVector(...) to translate BUS vector/level → SYSTEM vector/IRQL - then it calls IoConnectInterrupt(...) to connect the ISR So if the miniport passes already-translated numbers (system vector/IRQL), the mapping path can break and you get 0xC0000001. What you must do in the driver (procedure): A) Retrieve both resource lists via NdisMGetDeviceProperty(...) - AllocatedResources → BUS-relative IRQ info (USE THIS for NdisMRegisterInterrupt) - TranslatedResources → SYSTEM-translated IRQ info (LOG/DIAG only) B) In AllocatedResources, locate the descriptor: - Type == CmResourceTypeInterrupt C) Pass exactly these BUS values into NdisMRegisterInterrupt: - InterruptLevel = AllocatedResources.Interrupt.Level - InterruptVector = AllocatedResources.Interrupt.Vector D) Derive “shared” and “mode” from the descriptor: - If ShareDisposition is shared, set: - SharedInterrupt = TRUE - If flags indicate latched vs level-sensitive, pass matching mode: - Latched → NdisInterruptLatched - otherwise → NdisInterruptLevelSensitive Concrete example (typical IOAPIC case, exactly what we saw on i219): - AllocatedResources (BUS): level=16 vector=16 - TranslatedResources (SYSTEM): level=5 vector=865 (and you might see an “XP vector” like 97) Correct behavior was: - NdisMRegisterInterrupt try=BUS lvl=16 vec=16 ... → 0x00000000 Wrong behavior was: - NdisMRegisterInterrupt using translated/system values (e.g. lvl=5 vec=97 or lvl=5 vec=865) → 0xC0000001 Sources - ReactOS NDIS source (shows NdisMRegisterInterrupt using HalGetInterruptVector + IoConnectInterrupt): https://doxygen.reactos.org/dd/d5f/drivers_2network_2ndis_2ndis_2io_8c.html - Microsoft documentation for IoConnectInterrupt: https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-ioconnectinterrupt - PCI basics + capability list (background reference): https://wiki.osdev.org/PCI - PCIe interrupt behavior / INTx vs MSI (background reference): https://docs.amd.com/r/en-US/pg213-pcie4-ultrascale-plus/Generating-Interrupt-Requests
  4. Just now I work still on the lan Intel i219 with Dev_15B8, for to make it better. Here is the version with much lower Ping Dietmar https://files.catbox.moe/0gzcue.zip PS: This i219 lan driver uses only Polling mode, so no IRQ with DMA. And so, it is quite slow. I try to change this to IRQ with DMA, if possible.
  5. @Damnation Hi, what is the exact Dev_ of your lan 2.5 GB from realtek? And which board is it? I have some boards with this chip too so I can make a try for XP SP3 Dietmar
  6. Here is the working driver for lan i219 Dev_15B8 under Windows XP SP3. Please test, good luck Dietmar https://files.catbox.moe/8k5lei.zip
  7. Yesssssssaaaahhhh!!!!! After about 100 hours of crazy work with Windbg I succeed to build a working i219 Dev_15B8 lan driver for Windows XP SP3. I wonder all the time, why already TX works but no RX at all. The fault is the crazy from Intel implemented ULP ultra low power thing. Only when I found code from Linux, how to complete disable ULP, it works. This driver only uses original Ndis 5.1 from XP SP3. No extra function implemented, all done by hand Dietmar
  8. Yesssa.. i219 driver for XP is on the right way Dietmar
  9. @George King Hi, I dont know, how to do this "Can you also please create PR with these changes for everyone to main repo?". My new driver nvme2k.sys is stable for XP SP3, I work now with it on daily use Dietmar
  10. ==================================================== Intel i219 (DEV_15B8) Windows XP SP3 driver from scratch (NDIS 5.1) ==================================================== Hi, I’m working on a Windows XP SP3 LAN driver for my Intel i219, written from scratch as an NDIS 5.1 miniport (i219.sys). I am very happy for any hints about the remaining missing pieces (especially i219 “PCH SPT” specifics). Here is what I already reach, the confirmed hardware facts, register notes, and the current Supported-OID list. ---------------------------------------------------- 1) My used lan adapter on Asrock z370 k6 board ---------------------------------------------------- - NIC: Intel i219 (i219-V2) - PCI Vendor/Device: 8086:15B8 - MMIO: BAR0 mapped at 0xDF400000, length 0x20000 (128 KB) - IRQ: legacy line 5, vector 97 (XP HAL/IOAPIC mapping) - MAC (observed / read from RAL/RAH): 70-85-C2-7E-28-B7 - Current driver build (“v45”) installs and STARTS cleanly in Device Manager and answers basic NDIS OID queries without crashing. ---------------------------------------------------- 2) Why i219 is tricky vs i218 ---------------------------------------------------- - i218 belongs to the older PCH-LPT / LPTLP (Lynx Point, 8-Series) family. - i219 belongs to the newer PCH-SPT (Sunrise Point) and later PCH families. Therefore: “patch only DeviceID” (i218 → i219) is not enough. A working i219 driver must use the correct i219-family MAC/PHY/NVM init logic (different from i218-family). ---------------------------------------------------- 3) Hardware inputs I treat as runtime data (must be read) ---------------------------------------------------- From PCI config space: - Vendor/Device ID (8086 / 15B8) - Command register (Bus Master + Memory Space enable) - BAR0 base + decoded size (here: 0x20000) - Interrupt pin/line (legacy) and optionally MSI capability - Power management capability (D0/D3) - Revision ID, subsystem vendor/device ID (for possible quirks) From MMIO: - Classic Intel GbE register model (“E1000-ish”) ---------------------------------------------------- 4) Minimal register map I’m using (layered bring-up) ---------------------------------------------------- (Full 128 KB MMIO window is huge; I focus on the layers needed for a real driver.) 4.1 Core control / status / PHY/NVM - CTRL 0x00000 (reset / link control) - STATUS 0x00008 (link-up bit etc.) - EECD 0x00010 (EEPROM/flash control) - EERD 0x00014 (EEPROM read) - CTRL_EXT 0x00018 (extended control) - MDIC 0x00020 (MDIO/PHY access) - FEXTNVM 0x00028 (PCH-family helper register) i218 vs i219 note: The register “existence” looks similar, but the correct init sequence and interpretation is family-path dependent (i218=pch_lpt vs i219=pch_spt). 4.2 Interrupts (currently I use polled mode) - ICR 0x000C0 (cause read/ack) - IMS 0x000D0 (mask set) - IMC 0x000D8 (mask clear) - (ITR is optional) 4.3 RX/TX engine registers Receive: - RCTL 0x00100 (RX enable + filters) - RDBAL 0x02800 / RDBAH 0x02804 - RDLEN 0x02808 - RDH 0x02810 / RDT 0x02818 Transmit: - TCTL 0x00400 (TX enable) - TIPG 0x00410 - TDBAL 0x03800 / TDBAH 0x03804 - TDLEN 0x03808 - TDH 0x03810 / TDT 0x03818 4.4 Address filtering tables (important for DHCP/ARP/multicast) - RAL0/RAH0 0x05400 / 0x05404 (RAR0) - MTA 0x05200 (multicast hash table) - VFTA 0x05600 (optional VLAN filter) Important: When Windows sets OID_802_3_MULTICAST_LIST, the driver must program MTA accordingly (or choose a safe fallback strategy). ---------------------------------------------------- 5) Supported OIDs in v45 (current list) ---------------------------------------------------- static const NDIS_OID g_SupportedOids[] = { OID_GEN_SUPPORTED_LIST, OID_GEN_HARDWARE_STATUS, OID_GEN_MEDIA_SUPPORTED, OID_GEN_MEDIA_IN_USE, OID_GEN_MEDIA_CONNECT_STATUS, OID_GEN_MAXIMUM_FRAME_SIZE, OID_GEN_MAXIMUM_TOTAL_SIZE, OID_GEN_LINK_SPEED, OID_GEN_XMIT_OK, OID_GEN_RCV_OK, OID_GEN_XMIT_ERROR, OID_GEN_RCV_ERROR, OID_GEN_RCV_NO_BUFFER, OID_GEN_TRANSMIT_BUFFER_SPACE, OID_GEN_RECEIVE_BUFFER_SPACE, OID_GEN_TRANSMIT_BLOCK_SIZE, OID_GEN_RECEIVE_BLOCK_SIZE, OID_GEN_VENDOR_ID, OID_GEN_VENDOR_DESCRIPTION, OID_GEN_DRIVER_VERSION, OID_GEN_VENDOR_DRIVER_VERSION, OID_GEN_CURRENT_PACKET_FILTER, OID_GEN_CURRENT_LOOKAHEAD, OID_GEN_PROTOCOL_OPTIONS, OID_GEN_MAC_OPTIONS, OID_GEN_MAXIMUM_SEND_PACKETS, OID_GEN_MAXIMUM_LOOKAHEAD, OID_802_3_PERMANENT_ADDRESS, OID_802_3_CURRENT_ADDRESS, OID_802_3_MAXIMUM_LIST_SIZE, OID_802_3_MULTICAST_LIST }; Numeric OID values (standard ntddndis.h definitions): - OID_GEN_SUPPORTED_LIST = 0x00010101 - OID_GEN_HARDWARE_STATUS = 0x00010102 - OID_GEN_MEDIA_SUPPORTED = 0x00010103 - OID_GEN_MEDIA_IN_USE = 0x00010104 - OID_GEN_MAXIMUM_LOOKAHEAD = 0x00010105 - OID_GEN_MAXIMUM_FRAME_SIZE = 0x00010106 - OID_GEN_LINK_SPEED = 0x00010107 - OID_GEN_TRANSMIT_BUFFER_SPACE = 0x00010108 - OID_GEN_RECEIVE_BUFFER_SPACE = 0x00010109 - OID_GEN_TRANSMIT_BLOCK_SIZE = 0x0001010A - OID_GEN_RECEIVE_BLOCK_SIZE = 0x0001010B - OID_GEN_VENDOR_ID = 0x0001010C - OID_GEN_VENDOR_DESCRIPTION = 0x0001010D - OID_GEN_CURRENT_PACKET_FILTER = 0x0001010E - OID_GEN_CURRENT_LOOKAHEAD = 0x0001010F - OID_GEN_DRIVER_VERSION = 0x00010110 - OID_GEN_MAXIMUM_TOTAL_SIZE = 0x00010111 - OID_GEN_PROTOCOL_OPTIONS = 0x00010112 - OID_GEN_MAC_OPTIONS = 0x00010113 - OID_GEN_MEDIA_CONNECT_STATUS = 0x00010114 - OID_GEN_MAXIMUM_SEND_PACKETS = 0x00010115 - OID_GEN_VENDOR_DRIVER_VERSION = 0x00010116 - OID_GEN_XMIT_OK = 0x00020101 - OID_GEN_RCV_OK = 0x00020102 - OID_GEN_XMIT_ERROR = 0x00020103 - OID_GEN_RCV_ERROR = 0x00020104 - OID_GEN_RCV_NO_BUFFER = 0x00020105 - OID_802_3_PERMANENT_ADDRESS = 0x01010101 - OID_802_3_CURRENT_ADDRESS = 0x01010102 - OID_802_3_MULTICAST_LIST = 0x01010103 - OID_802_3_MAXIMUM_LIST_SIZE = 0x01010104 ---------------------------------------------------- 6) Current OID behavior in v45 ---------------------------------------------------- QueryInformation highlights: - OID_GEN_SUPPORTED_LIST: -> returns g_SupportedOids[] - OID_GEN_HARDWARE_STATUS: -> NdisHardwareStatusReady - OID_GEN_MEDIA_SUPPORTED / OID_GEN_MEDIA_IN_USE: -> NdisMedium802_3 - OID_GEN_MEDIA_CONNECT_STATUS: -> cached LinkState (Connected/Disconnected) - OID_GEN_MAXIMUM_FRAME_SIZE: -> 1500 - OID_GEN_MAXIMUM_TOTAL_SIZE: -> 1514 - OID_GEN_LINK_SPEED: -> 10000000 (1 Gbps in 100 bps units) - OID_GEN_VENDOR_ID: -> derived from MAC OUI (first 3 bytes) - OID_GEN_VENDOR_DESCRIPTION: -> "Dietmar i219 XP skeleton v45" - OID_GEN_DRIVER_VERSION: -> 0x0100 - OID_GEN_VENDOR_DRIVER_VERSION: -> 0x00010000 (1.0 encoded as major/minor) - OID_GEN_MAC_OPTIONS: -> COPY_LOOKAHEAD_DATA | TRANSFERS_NOT_PEND (observed as 0x5) - OID_GEN_MAXIMUM_SEND_PACKETS: -> 1 - OID_GEN_MAXIMUM_LOOKAHEAD: -> 1500 - OID_GEN_CURRENT_LOOKAHEAD / OID_GEN_CURRENT_PACKET_FILTER: -> returns cached values (Lookahead / PacketFilter) - Basic stats OIDs: -> currently 0 (no counters yet) - OID_802_3_PERMANENT_ADDRESS / CURRENT_ADDRESS: -> returns 6 bytes MAC - OID_802_3_MAXIMUM_LIST_SIZE: -> 32 SetInformation highlights: - OID_GEN_CURRENT_PACKET_FILTER: -> currently stores PacketFilter only (hardware filter mapping still in progress) - OID_GEN_CURRENT_LOOKAHEAD: -> stores Lookahead (clamped to 1500) - OID_802_3_MULTICAST_LIST: -> stores up to 32 multicast MACs (but MTA programming is still in progress) ---------------------------------------------------- 7) Problems already solved ---------------------------------------------------- - Driver loads/starts (v45): -> Clean start in Device Manager, Initialize runs, MMIO mapping is real. - Reliable MMIO/resource discovery: -> Stable BAR0 mapping confirmed (0xDF400000 / len 0x20000). - Root cause of earlier NDIS crash identified: -> When I previously “faked” some OIDs via WinDbg, I triggered a crash in NDIS OID validation (bad/NULL/incorrect Supported-OID list handling). -> Fix direction implemented: - real SupportedOids[] array - real Query/Set OID engine with correct BUFFER_TOO_SHORT / BytesNeeded / BytesWritten. - XP NDIS signature differences handled: -> Adjusted NdisMMapIoSpace / NdisMUnmapIoSpace usage for XP/NDIS5 compatibility. ---------------------------------------------------- 8) What I still miss ---------------------------------------------------- Even though the driver starts and answers OIDs, I still do NOT have real network traffic working end-to-end: - No DHCP lease / no real RX/TX I can see. What I believe is still needed: 1) Correct i219-family (PCH SPT) PHY + NVM init sequence (this is where i219 differs most from i218). 2) Correct mapping of OID_GEN_CURRENT_PACKET_FILTER into real hardware filtering (RCTL + tables). 3) Correct implementation of OID_802_3_MULTICAST_LIST into MTA programming (or safe fallback). 4) Possibly: switch from polled mode to proper interrupt mode once the basics work. If anyone has experience with i219 on older OSes (XP/2003): - The minimal “must-do” i219 (PCH SPT) PHY/NVM init steps to get stable link + RX/TX. - Any known i219-specific register quirks that differ from i218-family. - Confirmation whether my minimal TX/RX + RCTL strategy is sufficient, or which missing bits are typically required. Dietmar PS: Where the technical details in my i219 XP driver thread come from, and how I verify everything with crazy WinDbg use. ---------------------------------------------------- A) Direct observations from MY system (WinDbg + runtime logging) ---------------------------------------------------- These facts are taken from my own XP test machine and WinDbg sessions: - PCI ID: 8086:15B8 (Intel i219-V2) - BAR0 MMIO mapping: base 0xDF400000, size 0x20000 - IRQ resources (legacy line/vector) - MAC address read/used by the driver (70-85-C2-7E-28-B7) - Which OIDs are queried by NDIS / TCPIP and what my driver returned (seen via breakpoints + stack inspection) - Whether frames are actually TX/RX (currently: driver starts, but traffic still missing) ---------------------------------------------------- B) Extracted from my own driver source code (current v45 skeleton) ---------------------------------------------------- These items are not “guessed”; they come straight from my current i219.c / i219.h: - The exact SupportedOids[] array (the list I return for OID_GEN_SUPPORTED_LIST) - My current OID Query/Set behavior (what I return/store) - Ring sizes / buffer sizes / the delayed bring-up strategy (late TX/RX init after 40s) - Which register offsets I currently touch (RCTL/TCTL/TIPG/RDBAL… etc.) and which bits I set ---------------------------------------------------- C) Public reference sources (open headers/docs) ---------------------------------------------------- I used publicly available sources for “static” definitions, i.e. register offsets, bit masks, and OID semantics: 1) Intel e1000 / e1000e style register offsets + bit definitions - Linux kernel: drivers/net/ethernet/intel/e1000e/ (hw.h, defines.h, etc.) - QEMU’s e1000_hw.h (also includes the classic register layout) 2) NDIS OID numbers (hex values) and structures - ReactOS ntddndis.h (matches Windows OID values and is easy to reference) 3) OID semantics (what Windows expects) - Microsoft documentation for OID_GEN_SUPPORTED_LIST, OID_GEN_CURRENT_PACKET_FILTER, OID_802_3_MULTICAST_LIST, OID_GEN_LINK_SPEED, etc. ---------------------------------------------------- D) Heavy WinDbg use, the extremely hard part ;)) ---------------------------------------------------- My main technique is breakpoint-driven “bisection” (binary search in control flow): - Set a breakpoint at the function I expect to run. - If it is NOT hit, move the breakpoint earlier (caller / dispatcher) until I find the last hit location. - The bug must be between the last-hit BP and the first-not-hit BP. - Only after I have narrowed it down do I inspect registers/stack/buffers. Typical breakpoints I use: 1) OID path: bp i219!I219MiniportQueryInformation bp i219!I219MiniportSetInformation bp NDIS!ndisMDispatchRequest Inside Query/SetInformation on x86 NDIS5, the OID value is the 2nd argument: - OID is at [esp+8] ? poi(@esp+8) I often dump the full stack to see all arguments: dd esp L20 Then continue: g 2) Driver bring-up / resources: bp i219!I219Initialize bp i219!I219LateBringUp bp i219!I219ProgramRxTx bp i219!I219WriteMacToRar0 3) RX/TX progress: bp i219!I219SendPackets bp i219!I219PollRxTx (then watch MMIO reads/writes and descriptor ring head/tail changes) If an OID is queried and packets still don’t flow, I focus on: - OID_GEN_CURRENT_PACKET_FILTER SET → must translate into RCTL + filtering (broadcast/multicast) - OID_802_3_MULTICAST_LIST SET → must program MTA (or enable a safe fallback) - Link state / PHY init (i219 “PCH SPT” path differs from i218 “LPT” path) ---------------------------------------------------- Reference links (for convenience) ---------------------------------------------------- Linux e1000e: - https://github.com/torvalds/linux/tree/master/drivers/net/ethernet/intel/e1000e QEMU e1000 register layout (e1000_hw.h): - https://git.zx2c4.com/qemu/tree/hw/e1000_hw.h ReactOS ntddndis.h (OID hex values): - https://doxygen.reactos.org/dc/d38/ntddndis_8h.html Microsoft OID docs: - https://learn.microsoft.com/en-us/windows-hardware/drivers/network/oid-gen-supported-list - https://learn.microsoft.com/en-us/windows-hardware/drivers/network/oid-gen-current-packet-filter - https://learn.microsoft.com/en-us/windows-hardware/drivers/n
  11. @Damnation I think, it can be done for any Nic, as long as you have Linux, where you can spy. But it is soso crazy hard work. I notice for example, that I always get Bsod D1, which I cannot catch with Windbg, only when you make an offline check of it. It happens, when the lan cable is connected at boottime, but parts of the driver have not loaded to full, so happens this Bsod even everything is "ok". Now I understand, why on many compis there is always a big time delay, before you get connected via lan Dietmar
  12. Hi, I take all data from Linux for i219 for the registers etc. Crazy work, 16 hours a day. Now the driver i219.sys for XP SP3 is nearly ready Dietmar
  13. Hi, I am going to build from scratch a Lan driver for XP SP3 for any i219. I use Ndis5.1 original from XP, not Ndis6 from Vista, win7 etc. Just now, for the very first time, I get this my lan driver startet under XP. Oh crazy..what a hard work with Windbg Dietmar 0: kd> !devnode 8b5e8ee8 DevNode 0x8b5e8ee8 for PDO 0x8b51ccf8 Parent 0x8b5e9998 Sibling 0x8b5e8dc8 Child 0000000000 InstancePath is "PCI\VEN_8086&DEV_15B8&SUBSYS_15B81849&REV_00\3&11583659&0&FE" ServiceName is "i219" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) StateHistory[07] = DeviceNodeEnumerateCompletion (0x30d) StateHistory[06] = DeviceNodeStarted (0x308) StateHistory[05] = DeviceNodeStartPostWork (0x307) StateHistory[04] = DeviceNodeStartCompletion (0x306) StateHistory[03] = DeviceNodeResourcesAssigned (0x304) StateHistory[02] = DeviceNodeDriversAdded (0x303) StateHistory[01] = DeviceNodeInitialized (0x302) StateHistory[00] = DeviceNodeUninitialized (0x301) StateHistory[19] = Unknown State (0x0) StateHistory[18] = Unknown State (0x0) StateHistory[17] = Unknown State (0x0) StateHistory[16] = Unknown State (0x0) StateHistory[15] = Unknown State (0x0) StateHistory[14] = Unknown State (0x0) StateHistory[13] = Unknown State (0x0) StateHistory[12] = Unknown State (0x0) StateHistory[11] = Unknown State (0x0) StateHistory[10] = Unknown State (0x0) StateHistory[09] = Unknown State (0x0) StateHistory[08] = Unknown State (0x0) Flags (0x000000f0) DNF_ENUMERATED, DNF_IDS_QUERIED, DNF_HAS_BOOT_CONFIG, DNF_BOOT_CONFIG_RESERVED CapabilityFlags (0x00002000) WakeFromD3
  14. @Outbreaker Hi Ramsey, I make a mistake in the config files DOSNET.INF HIVESYS.INF TXTSETUP.SIF Here is the corrected version https://files.catbox.moe/duyf52.zip It works for your Windows XP Professional SP3 x86 - Integral Edition 2025.8.19 with settings Customized Option; 1,3,5,8,A,C,E,F Dietmar
  15. Hi, I make a new nvme2k driver for XP SP3 based on scsiport via the idea for this driver from Dominik Behr. The idea for to reach this, I get from Reactos scsi miniport driver. Now it works also for to INSTALL XP SP3 direct to any nvme device. Please test a lot Dietmar https://files.catbox.moe/duyf52.zip Here is the Source Code of the only modded nvme2k.c for to direct install nvme scsi miniport of XP SP3 via nvme2k.sys // // SCSI Miniport Driver for Windows 2000 // #include "nvme2k.h" #include "utils.h" // Poll interval for RequestTimerCall (ScsiPort expects microseconds) #define NVME2K_POLL_USEC 10000 // -------------------------------------------------------------------------- // IRQ robustness for Win2000/XP (SCSIPORT): force legacy INTx by disabling MSI/MSI-X // Many modern NVMe controllers come up with MSI-X enabled; XP SCSIPORT does not // reliably support MSI/MSI-X, resulting in massive timeouts (SpTimeoutSynchronized...). // -------------------------------------------------------------------------- static VOID NvmeForceLegacyIntx(IN PHW_DEVICE_EXTENSION DevExt) { // PCI conventional header offsets const UCHAR PCI_STATUS_OFFSET_LOCAL = 0x06; // USHORT const UCHAR PCI_CAP_PTR_OFFSET_LOCAL = 0x34; // UCHAR const USHORT PCI_STATUS_CAP_LIST = 0x0010; const UCHAR PCI_CAP_ID_MSI = 0x05; const UCHAR PCI_CAP_ID_MSIX = 0x11; USHORT status; UCHAR capPtr; UCHAR capId; UCHAR next; ULONG guard; status = ReadPciConfigWord(DevExt, PCI_STATUS_OFFSET_LOCAL); if (!(status & PCI_STATUS_CAP_LIST)) { return; } capPtr = ReadPciConfigByte(DevExt, PCI_CAP_PTR_OFFSET_LOCAL); capPtr = (UCHAR)(capPtr & (UCHAR)~0x03); // DWORD alignment guard = 0; while (guard < 32 && capPtr >= 0x40 && capPtr < 0x100) { capId = ReadPciConfigByte(DevExt, capPtr); next = ReadPciConfigByte(DevExt, (UCHAR)(capPtr + 1)); next = (UCHAR)(next & (UCHAR)~0x03); if (capId == PCI_CAP_ID_MSI) { // MSI Message Control is a WORD at cap+2; bit0 = MSI Enable USHORT msiCtrl; USHORT newCtrl; msiCtrl = ReadPciConfigWord(DevExt, (UCHAR)(capPtr + 2)); if (msiCtrl & 0x0001) { newCtrl = (USHORT)(msiCtrl & (USHORT)~0x0001); WritePciConfigWord(DevExt, (UCHAR)(capPtr + 2), newCtrl); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: NvmeForceLegacyIntx - MSI disabled (cap=%02X ctrl %04X->%04X)\n", capPtr, msiCtrl, newCtrl); #endif } } else if (capId == PCI_CAP_ID_MSIX) { // MSI-X Message Control is a WORD at cap+2; bit15 = MSI-X Enable, bit14 = Function Mask USHORT msixCtrl; USHORT newCtrl; msixCtrl = ReadPciConfigWord(DevExt, (UCHAR)(capPtr + 2)); newCtrl = msixCtrl; // Mask vectors and disable MSI-X newCtrl = (USHORT)(newCtrl | 0x4000); // Function Mask newCtrl = (USHORT)(newCtrl & (USHORT)~0x8000); // MSI-X Enable if (newCtrl != msixCtrl) { WritePciConfigWord(DevExt, (UCHAR)(capPtr + 2), newCtrl); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: NvmeForceLegacyIntx - MSI-X disabled (cap=%02X ctrl %04X->%04X)\n", capPtr, msixCtrl, newCtrl); #endif } } if (next == 0 || next == capPtr) { break; } capPtr = next; guard++; } } // // DriverEntry - Main entry point // ULONG DriverEntry(IN PVOID DriverObject, IN PVOID Argument2) { HW_INITIALIZATION_DATA hwInitData; ULONG status; #if (_WIN32_WINNT < 0x500) ULONG HwContext[2]; #endif // Break into debugger if attached #ifdef NVME2K_DBG //__asm { int 3 } ScsiDebugPrint(0, "nvme2k: DriverEntry called\n"); #endif // Zero out the initialization data structure memset(&hwInitData, 0, sizeof(HW_INITIALIZATION_DATA)); // Set size of structure hwInitData.HwInitializationDataSize = sizeof(HW_INITIALIZATION_DATA); // Set entry points hwInitData.HwInitialize = HwInitialize; hwInitData.HwStartIo = HwStartIo; hwInitData.HwInterrupt = HwInterrupt; hwInitData.HwFindAdapter = HwFindAdapter; hwInitData.HwResetBus = HwResetBus; #if (_WIN32_WINNT >= 0x500) hwInitData.HwAdapterControl = HwAdapterControl; #else hwInitData.HwAdapterState = HwAdapterState; #endif // Set driver-specific parameters hwInitData.AdapterInterfaceType = PCIBus; // Change as needed hwInitData.DeviceExtensionSize = sizeof(HW_DEVICE_EXTENSION); hwInitData.SpecificLuExtensionSize = 0; hwInitData.SrbExtensionSize = sizeof(NVME_SRB_EXTENSION); // Required for PRP list tracking hwInitData.NumberOfAccessRanges = 1; hwInitData.MapBuffers = TRUE; hwInitData.NeedPhysicalAddresses = TRUE; hwInitData.TaggedQueuing = TRUE; hwInitData.AutoRequestSense = TRUE; hwInitData.MultipleRequestPerLu = TRUE; // Vendor/Device IDs (for PCI devices) hwInitData.VendorIdLength = 0; hwInitData.VendorId = NULL; hwInitData.DeviceIdLength = 0; hwInitData.DeviceId = NULL; #if (_WIN32_WINNT < 0x500) HwContext[0] = 0; HwContext[1] = 0; #endif // Call port driver status = ScsiPortInitialize(DriverObject, Argument2, &hwInitData, #if (_WIN32_WINNT >= 0x500) NULL #else HwContext #endif ); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: DriverEntry exiting with status 0x%08X\n", status); #endif return status; } ULONG HwFoundAdapter( IN PHW_DEVICE_EXTENSION DevExt, IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, IN PUCHAR pciBuffer) { PACCESS_RANGE accessRange; SCSI_PHYSICAL_ADDRESS bar0; ULONG bar0tmp; ULONG barSize; ULONG tempSize; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - found NVMe device VID=%04X DID=%04X at bus %d slot %d\n", DevExt->VendorId, DevExt->DeviceId, DevExt->BusNumber, DevExt->SlotNumber); #endif // Read subsystem IDs using helper function DevExt->SubsystemVendorId = ReadPciConfigWord(DevExt, PCI_SUBSYSTEM_VENDOR_ID_OFFSET); DevExt->SubsystemId = ReadPciConfigWord(DevExt, PCI_SUBSYSTEM_ID_OFFSET); // Enable PCI device decoding and bus mastering. // Do NOT leave PCI_INTERRUPT_DISABLE set here: on Win2000/XP ScsiPort setups frequently rely on legacy INTx. // (MSI/MSI-X is not guaranteed/available with ScsiPort.) { USHORT cmdReg = ReadPciConfigWord(DevExt, PCI_COMMAND_OFFSET); cmdReg |= (PCI_ENABLE_BUS_MASTER | PCI_ENABLE_MEMORY_SPACE); cmdReg = (USHORT)(cmdReg & ~PCI_INTERRUPT_DISABLE); // ensure INTx not disabled WritePciConfigWord(DevExt, PCI_COMMAND_OFFSET, cmdReg); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - PCI Command Register = %04X (IntDis=%d)\n", cmdReg, !!(cmdReg & PCI_INTERRUPT_DISABLE)); #endif } // Force legacy INTx on XP/2000 to avoid MSI/MSI-X related timeouts NvmeForceLegacyIntx(DevExt); // Read interrupt configuration from PCI config space // This is probably redundant on Win2K and can be ifdefed out { UCHAR interruptLine = ReadPciConfigByte(DevExt, PCI_INTERRUPT_LINE_OFFSET); UCHAR interruptPin = ReadPciConfigByte(DevExt, PCI_INTERRUPT_PIN_OFFSET); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - PCI Interrupt Line=%d Pin=%d\n", interruptLine, interruptPin); ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - ConfigInfo BEFORE: BusInterruptLevel=%d Vector=%d Mode=%d\n", ConfigInfo->BusInterruptLevel, ConfigInfo->BusInterruptVector, ConfigInfo->InterruptMode); #endif #if (_WIN32_WINNT < 0x500) // CRITICAL FOR NT4: When manually setting SystemIoBusNumber/SlotNumber, // SCSI port doesn't automatically query interrupt configuration from HAL. // We MUST set valid interrupt parameters or we'll get STATUS_INVALID_PARAMETER. // For PCI: BusInterruptLevel = interrupt line, mode = LevelSensitive if (interruptPin != 0 && interruptLine != 0 && interruptLine != 0xFF) { ConfigInfo->BusInterruptLevel = interruptLine; ConfigInfo->BusInterruptVector = interruptLine; ConfigInfo->InterruptMode = LevelSensitive; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - Set interrupt from PCI config: Level=%d\n", interruptLine); #endif } else { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - WARNING: No valid PCI interrupt configured\n"); #endif // If no valid interrupt, still need to set something valid for NT4. // Use polling mode - but this might not work on NT4! ConfigInfo->BusInterruptLevel = 0; ConfigInfo->BusInterruptVector = 0; } #else // Win2000/XP: leave interrupt routing to ScsiPort/HAL; do not override ConfigInfo here. #endif } // Set the number of access ranges we're using (1 for BAR0) // NT4 may require this to be explicitly set for resource translation ConfigInfo->NumberOfAccessRanges = 1; ConfigInfo->MaximumTransferLength = 32u << NVME_PAGE_SHIFT; // safe default ConfigInfo->NumberOfBuses = 1; ConfigInfo->ScatterGather = TRUE; ConfigInfo->Master = TRUE; ConfigInfo->CachesData = FALSE; ConfigInfo->AdapterScansDown = FALSE; ConfigInfo->Dma32BitAddresses = TRUE; #if (_WIN32_WINNT >= 0x500) ConfigInfo->Dma64BitAddresses = TRUE; // NVMe supports 64-bit addressing #endif ConfigInfo->MaximumNumberOfTargets = 2; // Support TargetId 0 and 1 ConfigInfo->NumberOfPhysicalBreaks = 511; // PRP1 + PRP list (512 entries) ConfigInfo->AlignmentMask = 0x3; // DWORD alignment ConfigInfo->NeedPhysicalAddresses = TRUE; // Required for ScsiPortGetPhysicalAddress to work ConfigInfo->TaggedQueuing = TRUE; // Support tagged command queuing ConfigInfo->MultipleRequestPerLu = TRUE; // Allow multiple outstanding commands per LUN ConfigInfo->AutoRequestSense = TRUE; // Automatically provide sense data on errors // Note: SrbExtensionSize must be set in HW_INITIALIZATION_DATA, not here #ifdef NVME2K_DBG_EXTRA { ULONG a; accessRange = &((*(ConfigInfo->AccessRanges))[0]); for (a = 0; a < ConfigInfo->NumberOfAccessRanges; a++) { ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - range:%u start:%08X, length:%08X, inMemory:%d\n", a, (ULONG)(accessRange->RangeStart.QuadPart), accessRange->RangeLength, accessRange->RangeInMemory); accessRange++; } } #endif // Determine BAR0 / controller register range. // On Win2000/XP PnP paths, ScsiPort usually provides a translated AccessRange already. // Only fall back to PCI BAR probing ("BAR sizing dance") if the AccessRange is not populated. accessRange = &((*(ConfigInfo->AccessRanges))[0]); if (accessRange->RangeLength != 0 && accessRange->RangeStart.QuadPart != 0) { // PnP path: trust the provided resource assignment. accessRange->RangeInMemory = TRUE; // NVMe register space is MMIO DevExt->ControllerRegistersLength = accessRange->RangeLength; } else { // Non-PnP / textmode scan path: read BAR0 from PCI config and size it. bar0tmp = ReadPciConfigDword(DevExt, PCI_BASE_ADDRESS_0); bar0.HighPart = 0; bar0.LowPart = bar0tmp & 0xFFFFFFF0; if ((bar0tmp & 0x6) == 0x6) { bar0.HighPart = ReadPciConfigDword(DevExt, PCI_BASE_ADDRESS_1); if (bar0.HighPart) { ScsiDebugPrint(0, "nvme2k: BAR0 base=0x%08X%08X beyond 4GB, it may not end well on 32bit kernel\n", bar0.HighPart, bar0.LowPart); } } #if (_WIN32_WINNT >= 0x500 && !defined(ALPHA)) accessRange->RangeStart = ScsiPortConvertUlongToPhysicalAddress(ScsiPortConvertPhysicalAddressToULongPtr(bar0)); #else accessRange->RangeStart = ScsiPortConvertUlongToPhysicalAddress(bar0.LowPart); #endif if (bar0tmp & 0x1) { return SP_RETURN_ERROR; } accessRange->RangeInMemory = TRUE; // Size BAR0 only if we had to probe it ourselves. WritePciConfigDword(DevExt, PCI_BASE_ADDRESS_0, 0xFFFFFFFF); // Read back the modified value barSize = ReadPciConfigDword(DevExt, PCI_BASE_ADDRESS_0); // Restore original BAR value WritePciConfigDword(DevExt, PCI_BASE_ADDRESS_0, bar0tmp); accessRange->RangeLength = ~(barSize & 0xFFFFFFF0) + 1; DevExt->ControllerRegistersLength = accessRange->RangeLength; } #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - BAR0 base=0x%08X size=0x%08X\n", (ULONG)accessRange->RangeStart.QuadPart, accessRange->RangeLength); #endif // Validate the access range (required for NT4, optional for Win2K+) // This checks if the range is available and doesn't conflict with other devices if (!ScsiPortValidateRange( (PVOID)DevExt, ConfigInfo->AdapterInterfaceType, ConfigInfo->SystemIoBusNumber, accessRange->RangeStart, accessRange->RangeLength, (BOOLEAN)!accessRange->RangeInMemory)) { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - ScsiPortValidateRange failed for BAR0\n"); #endif return SP_RETURN_ERROR; } // Map the controller registers DevExt->ControllerRegisters = ScsiPortGetDeviceBase( (PVOID)DevExt, ConfigInfo->AdapterInterfaceType, ConfigInfo->SystemIoBusNumber, accessRange->RangeStart, accessRange->RangeLength, (BOOLEAN)!accessRange->RangeInMemory); if (DevExt->ControllerRegisters == NULL) { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - failed to map controller registers\n"); #endif return SP_RETURN_ERROR; } #if 0 // can be reported in newer OSes // Read controller capabilities to determine max queue size // This must be done here so we can set ConfigInfo->NumberOfRequests { ULONGLONG cap; USHORT mqes, maxQueueSize; cap = NvmeReadReg64(DevExt, NVME_REG_CAP); mqes = (USHORT)(cap & NVME_CAP_MQES_MASK); maxQueueSize = mqes + 1; // MQES is 0-based // Limit to our maximum (what fits in one page) if (maxQueueSize > NVME_MAX_QUEUE_SIZE) { maxQueueSize = NVME_MAX_QUEUE_SIZE; } // Tell SCSI port driver how many outstanding requests we can handle // This prevents the OS from sending more requests than we can queue ConfigInfo->NumberOfRequests = maxQueueSize; ScsiDebugPrint(0, "nvme2k: HwFindAdapter - MQES=%u, setting NumberOfRequests=%u\n", mqes, maxQueueSize); } #endif // // Uncached memory size calculation: // - Admin SQ: 4096 bytes (4KB aligned) // - I/O SQ: 4096 bytes (4KB aligned) // - Utility buffer / PRP list pool: (SgListPages pages * 4KB, page-aligned) // - Admin CQ: 4096 bytes (4KB aligned) // - I/O CQ: 4096 bytes (4KB aligned) // Total: ~60KB with alignment // // Allocate uncached memory block DevExt->SgListPages = 32; DevExt->UncachedExtensionSize = (NVME_PAGE_SIZE * (DevExt->SgListPages + 4 + 1)); DevExt->UncachedExtensionBase = ScsiPortGetUncachedExtension( (PVOID)DevExt, ConfigInfo, DevExt->UncachedExtensionSize); if (DevExt->UncachedExtensionBase == NULL) { DevExt->SgListPages = 16; DevExt->UncachedExtensionSize = (NVME_PAGE_SIZE * (DevExt->SgListPages + 4 + 1)); DevExt->UncachedExtensionBase = ScsiPortGetUncachedExtension( (PVOID)DevExt, ConfigInfo, DevExt->UncachedExtensionSize); if (DevExt->UncachedExtensionBase == NULL) { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - failed to allocate uncached memory\n"); #endif return SP_RETURN_ERROR; } } // Get physical address of the entire uncached block tempSize = DevExt->UncachedExtensionSize; DevExt->UncachedExtensionPhys = ScsiPortGetPhysicalAddress( (PVOID)DevExt, NULL, DevExt->UncachedExtensionBase, &tempSize); // Zero out the entire uncached memory memset(DevExt->UncachedExtensionBase, 0, DevExt->UncachedExtensionSize); // Initialize allocator DevExt->UncachedExtensionOffset = 0; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - allocated %u bytes of uncached memory at virt=%p phys=%08X%08X\n", DevExt->UncachedExtensionSize, DevExt->UncachedExtensionBase, (ULONG)(DevExt->UncachedExtensionPhys.QuadPart >> 32), (ULONG)(DevExt->UncachedExtensionPhys.QuadPart & 0xFFFFFFFF)); #endif #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - success, returning SP_RETURN_FOUND\n"); #endif if (!NvmeSanitizeController(DevExt)) { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwInHwFoundAdapteritialize - NvmeSanitizeController failed\n"); #endif return SP_RETURN_ERROR; } if (!NvmeInitializeController(DevExt)) { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFoundAdapter - NvmeInitializeController failed\n"); #endif return SP_RETURN_ERROR; } // We need to update some of the config info now from the data we got from the controller. ConfigInfo->MaximumTransferLength = DevExt->MaxTransferSizeBytes; if (((ConfigInfo->MaximumTransferLength >> NVME_PAGE_SHIFT) - 1) < ConfigInfo->NumberOfPhysicalBreaks) ConfigInfo->NumberOfPhysicalBreaks = (ConfigInfo->MaximumTransferLength >> NVME_PAGE_SHIFT) - 1; return SP_RETURN_FOUND; } // // HwFindAdapter - Locate and configure the adapter // ULONG HwFindAdapter( IN PVOID DeviceExtension, IN PVOID HwContext, IN PVOID BusInformation, IN PCHAR ArgumentString, IN OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo, OUT PBOOLEAN Again) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; UCHAR pciBuffer[256]; ULONG slotNumber; ULONG busNumber; UCHAR baseClass, subClass, progIf; ULONG bytesRead; BOOLEAN PNP = ConfigInfo->NumberOfAccessRanges != 0; // Defaults: keep polling fallback enabled until we prove legacy INTx is reliable. DevExt->FallbackTimerNeeded = 1; DevExt->InterruptCount = 0; if (HwContext) { busNumber = ((PULONG)HwContext)[0]; slotNumber = ((PULONG)HwContext)[1]; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFindAdapter:%p called with HwContext - Bus=%d Slot=%d\n", DeviceExtension, busNumber, slotNumber); #endif } else { // Win2k, PnP gives us this directly busNumber = ConfigInfo->SystemIoBusNumber; slotNumber = ConfigInfo->SlotNumber; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFindAdapter:%p called w/o HwContext - Bus=%d Slot=%d PNP=%d\n", DeviceExtension, busNumber, slotNumber, PNP); #endif } // PnP path (Win2000/XP): ScsiPort gives us the exact bus/slot to probe. // Do NOT scan other slots here, or you may confuse enumeration and waste time in textmode. if (!HwContext && PNP) { bytesRead = ScsiPortGetBusData( DeviceExtension, PCIConfiguration, busNumber, slotNumber, pciBuffer, 256); if (bytesRead == 0) { *Again = FALSE; return SP_RETURN_NOT_FOUND; } DevExt->VendorId = *(USHORT*)&pciBuffer[PCI_VENDOR_ID_OFFSET]; DevExt->DeviceId = *(USHORT*)&pciBuffer[PCI_DEVICE_ID_OFFSET]; if (DevExt->VendorId == 0xFFFF || DevExt->VendorId == 0x0000) { *Again = FALSE; return SP_RETURN_NOT_FOUND; } DevExt->RevisionId = pciBuffer[PCI_REVISION_ID_OFFSET]; progIf = pciBuffer[PCI_CLASS_CODE_OFFSET]; subClass = pciBuffer[PCI_CLASS_CODE_OFFSET + 1]; baseClass = pciBuffer[PCI_CLASS_CODE_OFFSET + 2]; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFindAdapter (PnP) - bus %d slot %d: VID=%04X DID=%04X Class=%02X%02X%02X\n", busNumber, slotNumber, DevExt->VendorId, DevExt->DeviceId, baseClass, subClass, progIf); #endif if (!IsNvmeDevice(baseClass, subClass, progIf)) { *Again = FALSE; return SP_RETURN_NOT_FOUND; } DevExt->BusNumber = busNumber; DevExt->SlotNumber = slotNumber; *Again = FALSE; // Ensure ConfigInfo matches the adapter we found (needed for non-PnP/textmode/NT4 scan paths) ConfigInfo->AdapterInterfaceType = PCIBus; ConfigInfo->SystemIoBusNumber = busNumber; ConfigInfo->SlotNumber = slotNumber; return HwFoundAdapter(DevExt, ConfigInfo, pciBuffer); } scanloop: // Read PCI configuration space for THIS slot only bytesRead = ScsiPortGetBusData( DeviceExtension, PCIConfiguration, busNumber, slotNumber, pciBuffer, 256); if (bytesRead == 0) { // No device in this slot - tell SCSI port to keep scanning other slots goto scannext; } // Extract Vendor ID and Device ID DevExt->VendorId = *(USHORT*)&pciBuffer[PCI_VENDOR_ID_OFFSET]; DevExt->DeviceId = *(USHORT*)&pciBuffer[PCI_DEVICE_ID_OFFSET]; // Check for invalid vendor ID if (DevExt->VendorId == 0xFFFF || DevExt->VendorId == 0x0000) { // No valid device in this slot - tell SCSI port to keep scanning other slots goto scannext; } // Extract class code information DevExt->RevisionId = pciBuffer[PCI_REVISION_ID_OFFSET]; progIf = pciBuffer[PCI_CLASS_CODE_OFFSET]; subClass = pciBuffer[PCI_CLASS_CODE_OFFSET + 1]; baseClass = pciBuffer[PCI_CLASS_CODE_OFFSET + 2]; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFindAdapter - bus %d slot %d: VID=%04X DID=%04X Class=%02X%02X%02X\n", busNumber, slotNumber, DevExt->VendorId, DevExt->DeviceId, baseClass, subClass, progIf); #endif // Check if this is an NVMe device if (IsNvmeDevice(baseClass, subClass, progIf)) { // Found an NVMe device at the slot SCSI port asked us to check! DevExt->BusNumber = busNumber; DevExt->SlotNumber = slotNumber; // Ensure ConfigInfo matches the adapter we found (needed for non-PnP/textmode/NT4 scan paths) ConfigInfo->AdapterInterfaceType = PCIBus; ConfigInfo->SystemIoBusNumber = busNumber; ConfigInfo->SlotNumber = slotNumber; // Store next slot/bus so we can resume scanning on next call if (HwContext) { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFindAdapter - NT4: store HwContext to resume scanning\n"); #endif ((PULONG)HwContext)[0] = DevExt->BusNumber; ((PULONG)HwContext)[1] = DevExt->SlotNumber + 1; if (((PULONG)HwContext)[1] >= (PCI_MAX_DEVICES*PCI_MAX_FUNCTION)) { ((PULONG)HwContext)[1] = 0; ((PULONG)HwContext)[0]++; } *Again = TRUE; } else { *Again = FALSE; } #ifdef NVME2K_DBG if (!HwContext) { ScsiDebugPrint(0, "nvme2k: HwFindAdapter - uh oh no HwContext! are we going to scan whole thing again?\n"); } #endif return HwFoundAdapter(DevExt, ConfigInfo, pciBuffer); } #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwFindAdapter - not an NVMe device\n"); #endif scannext: // NT4 or install time: Continue scanning the bus slotNumber++; if (slotNumber == (PCI_MAX_DEVICES*PCI_MAX_FUNCTION)) { busNumber++; slotNumber = 0; if (busNumber == 16) { // theoretically 256 but we arent going to waste cycles *Again = FALSE; return SP_RETURN_NOT_FOUND; } } goto scanloop; } // // HwInitialize - Initialize the adapter // BOOLEAN HwInitialize(IN PVOID DeviceExtension) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwInitialize called\n"); #endif // Ensure legacy INTx is not disabled at PCI command level. // Some ScsiPort environments (especially textmode) may not use MSI/MSI-X reliably. { USHORT cmdReg = ReadPciConfigWord(DevExt, PCI_COMMAND_OFFSET); if (cmdReg & PCI_INTERRUPT_DISABLE) { cmdReg = (USHORT)(cmdReg & ~PCI_INTERRUPT_DISABLE); WritePciConfigWord(DevExt, PCI_COMMAND_OFFSET, cmdReg); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwInitialize - cleared PCI_INTERRUPT_DISABLE (Cmd=%04X)\n", cmdReg); #endif } } // Step 3: Enable interrupts // This is done after initialization is complete but before HwInitialize returns, // so ScsiPort knows we're interrupt-capable NvmeEnableInterrupts(DevExt); #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwInitialize finished successfully\n"); #endif return TRUE; } // // HwStartIo - Process SCSI request // BOOLEAN HwStartIo(IN PVOID DeviceExtension, IN PSCSI_REQUEST_BLOCK Srb) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; NVME_COMMAND nvmeCmd; USHORT commandId; #ifdef NVME2K_DBG_EXTRA ScsiDebugPrint(0, "nvme2k: HwStartIo called - Function=%02X Path=%d Target=%d Lun=%d\n", Srb->Function, Srb->PathId, Srb->TargetId, Srb->Lun); #endif // If interrupts are flaky/missing (common on modern PCIe with XP textmode), // arm a lightweight fallback timer that polls NVMe completions. // HwInterrupt() will cancel the timer whenever real interrupts fire. if (DevExt->InitComplete && DevExt->FallbackTimerNeeded) { ScsiPortNotification(RequestTimerCall, DeviceExtension, FallbackTimer, NVME2K_POLL_USEC); } #if 1 // Poll completion queues as a backup in case interrupts are delayed // This helps performance on busy systems if (DevExt->InitComplete) { if (DevExt->CurrentQueueDepth > 0 || DevExt->NonTaggedInFlight) { NvmeProcessAdminCompletion(DevExt); NvmeProcessIoCompletion(DevExt); } } #endif // Check if the request is for our device (PathId=0, TargetId=0, Lun=0) if (Srb->PathId != 0 || Srb->TargetId != 0 || Srb->Lun != 0) { // Not our device - distinguish between invalid target and invalid LUN if (Srb->Function == SRB_FUNCTION_EXECUTE_SCSI) { // Check if this is an invalid LUN on our target (Path=0, Target=0, but Lun != 0) if (Srb->PathId == 0 && Srb->TargetId == 0 && Srb->Lun != 0) { // Invalid LUN on our target - return error with sense data PSENSE_DATA senseBuffer; Srb->SrbStatus = SRB_STATUS_ERROR; Srb->ScsiStatus = 0x02; // CHECK_CONDITION // Fill in sense data if AutoRequestSense is enabled and buffer is available if (Srb->SenseInfoBuffer != NULL && Srb->SenseInfoBufferLength >= sizeof(SENSE_DATA)) { senseBuffer = (PSENSE_DATA)Srb->SenseInfoBuffer; memset(senseBuffer, 0, sizeof(SENSE_DATA)); senseBuffer->ErrorCode = 0x70; // Current error, fixed format senseBuffer->Valid = 0; senseBuffer->SenseKey = SCSI_SENSE_ILLEGAL_REQUEST; senseBuffer->AdditionalSenseLength = sizeof(SENSE_DATA) - 8; senseBuffer->AdditionalSenseCode = SCSI_ADSENSE_INVALID_LUN; senseBuffer->AdditionalSenseCodeQualifier = 0x00; Srb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID; } } else { // Invalid target or path - selection timeout Srb->SrbStatus = SRB_STATUS_SELECTION_TIMEOUT; } } else { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; } ScsiPortNotification(RequestComplete, DeviceExtension, Srb); ScsiPortNotification(NextRequest, DeviceExtension, NULL); return TRUE; } // Process the SRB based on its function switch (Srb->Function) { case SRB_FUNCTION_EXECUTE_SCSI: #ifdef NVME2K_DBG_EXTRA ScsiDebugPrint(0, "nvme2k: processing op=%02X\n", Srb->Cdb[0]); // Log tagged queuing usage if (Srb->SrbFlags & SRB_FLAGS_QUEUE_ACTION_ENABLE) { const char* queueType = "Unknown"; switch (Srb->QueueAction) { case SRB_SIMPLE_TAG_REQUEST: queueType = "SIMPLE"; break; case SRB_HEAD_OF_QUEUE_TAG_REQUEST: queueType = "HEAD_OF_QUEUE"; break; case SRB_ORDERED_QUEUE_TAG_REQUEST: queueType = "ORDERED"; break; } ScsiDebugPrint(0, "nvme2k: Tagged queuing enabled - QueueAction=%s (0x%02X) Tag:%02X\n", queueType, Srb->QueueAction, Srb->QueueTag); } #endif // Process SCSI CDB switch (Srb->Cdb[0]) { case SCSIOP_READ6: case SCSIOP_READ: case SCSIOP_READ16: case SCSIOP_WRITE6: case SCSIOP_WRITE: case SCSIOP_WRITE16: return ScsiHandleReadWrite(DevExt, Srb); case SCSIOP_TEST_UNIT_READY: if (DevExt->InitComplete) Srb->SrbStatus = SRB_STATUS_SUCCESS; else Srb->SrbStatus = SRB_STATUS_BUSY; break; case SCSIOP_VERIFY6: case SCSIOP_VERIFY: Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case SCSIOP_INQUIRY: return ScsiHandleInquiry(DevExt, Srb); case SCSIOP_READ_CAPACITY: return ScsiHandleReadCapacity(DevExt, Srb); case SCSIOP_READ_CAPACITY16: return ScsiHandleReadCapacity16(DevExt, Srb); case SCSIOP_LOG_SENSE: return ScsiHandleLogSense(DevExt, Srb); case SCSIOP_MODE_SENSE: case SCSIOP_MODE_SENSE10: return ScsiHandleModeSense(DevExt, Srb); case SCSIOP_START_STOP_UNIT: // Accept but do nothing Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case SCSIOP_SYNCHRONIZE_CACHE: return ScsiHandleFlush(DevExt, Srb); case SCSIOP_ATA_PASSTHROUGH16: case SCSIOP_ATA_PASSTHROUGH12: // SAT (SCSI/ATA Translation) ATA PASS-THROUGH commands return ScsiHandleSatPassthrough(DevExt, Srb); case SCSIOP_READ_DEFECT_DATA10: return ScsiHandleReadDefectData10(DevExt, Srb); default: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo - unimplemented SCSI opcode 0x%02X\n", Srb->Cdb[0]); #endif Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; break; } break; case SRB_FUNCTION_FLUSH: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo SRB_FUNCTION_FLUSH\n"); #endif return ScsiHandleFlush(DevExt, Srb); case SRB_FUNCTION_FLUSH_QUEUE: // No internal queue to flush - requests go directly to hardware Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_SHUTDOWN: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo - SRB_FUNCTION_SHUTDOWN - flushing cache\n"); #endif // Flush all cached writes before shutdown return ScsiHandleFlush(DevExt, Srb); case SRB_FUNCTION_ABORT_COMMAND: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo SRB_FUNCTION_ABORT_COMMAND\n"); #endif Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_RESET_BUS: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo SRB_FUNCTION_RESET_BUS\n"); #endif Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_RESET_DEVICE: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo SRB_FUNCTION_RESET_DEVICE\n"); #endif Srb->SrbStatus = SRB_STATUS_SUCCESS; break; case SRB_FUNCTION_IO_CONTROL: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo - SRB_FUNCTION_IO_CONTROL\n"); #endif if (Srb->DataTransferLength >= sizeof(SRB_IO_CONTROL)) { PSRB_IO_CONTROL srbControl = (PSRB_IO_CONTROL)Srb->DataBuffer; if (memcmp(srbControl->Signature, "NVME2KDB", 8) == 0) { if (HandleIO_NVME2KDB(DevExt, Srb)) { if (Srb->SrbStatus != SRB_STATUS_PENDING) { Srb->SrbStatus = SRB_STATUS_SUCCESS; } } else { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; } } else if (memcmp(srbControl->Signature, "NvmeMini", 8) == 0) { if (HandleIO_NvmeMini(DevExt, Srb)) { if (Srb->SrbStatus != SRB_STATUS_PENDING) { Srb->SrbStatus = SRB_STATUS_SUCCESS; } } else { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; } } else if (memcmp(srbControl->Signature, "SCSIDISK", 8) == 0) { if (HandleIO_SCSIDISK(DevExt, Srb)) { // If HandleIO_SCSIDISK returns TRUE, it may have set the status // to PENDING for async operations. if (Srb->SrbStatus != SRB_STATUS_PENDING) { Srb->SrbStatus = SRB_STATUS_SUCCESS; } } else { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; } } else { Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; } } else { #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo - SRB_FUNCTION_IO_CONTROL invalid transfer length - DataTransferLength=%u\n", Srb->DataTransferLength); #endif Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; return FALSE; } break; default: #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwStartIo - unimplemented SRB function 0x%02X\n", Srb->Function); #endif Srb->SrbStatus = SRB_STATUS_INVALID_REQUEST; break; } // Complete the request if not pending if (Srb->SrbStatus != SRB_STATUS_PENDING) { ScsiPortNotification(RequestComplete, DeviceExtension, Srb); ScsiPortNotification(NextRequest, DeviceExtension, NULL); } return TRUE; } VOID FallbackTimer(IN PVOID DeviceExtension) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; DevExt->FallbackTimerNeeded++; if (!DevExt->FallbackTimerNeeded) // wraparound DevExt->FallbackTimerNeeded = 2; // because 1 means fallbacktime didnt fire NvmeProcessAdminCompletion(DevExt); NvmeProcessIoCompletion(DevExt); // Rearm polling while requests are still in flight and fallback is enabled. // If real interrupts fire, HwInterrupt() cancels the timer. if (DevExt->InitComplete && DevExt->FallbackTimerNeeded) { if (DevExt->CurrentQueueDepth > 0 || DevExt->NonTaggedInFlight) { ScsiPortNotification(RequestTimerCall, DeviceExtension, FallbackTimer, NVME2K_POLL_USEC); } } } // // HwInterrupt - ISR for adapter // BOOLEAN HwInterrupt(IN PVOID DeviceExtension) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; BOOLEAN interruptHandled = FALSE; // Process Admin Queue completions first if (NvmeProcessAdminCompletion(DevExt)) { interruptHandled = TRUE; } // Process I/O Queue completions if (NvmeProcessIoCompletion(DevExt)) { interruptHandled = TRUE; } // Only treat this as a "real" interrupt if we actually consumed NVMe completions. // This avoids disabling the polling fallback on shared/spurious IRQs. if (interruptHandled) { DevExt->InterruptCount++; if (DevExt->FallbackTimerNeeded) { // cancel any pending fallback timer ScsiPortNotification(RequestTimerCall, DeviceExtension, FallbackTimer, 0); // interrupts worked a million times, and callback didn't fire -> probably don't need a fallback if (DevExt->InterruptCount >= 1000000 && DevExt->FallbackTimerNeeded == 1) { DevExt->FallbackTimerNeeded = 0; } } } return interruptHandled; } // // HwResetBus - Reset the SCSI bus // BOOLEAN HwResetBus(IN PVOID DeviceExtension, IN ULONG PathId) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; // TODO: Reset the SCSI bus // Perform hardware reset // Complete all outstanding requests ScsiPortCompleteRequest(DeviceExtension, (UCHAR)PathId, SP_UNTAGGED, SP_UNTAGGED, SRB_STATUS_BUS_RESET); return TRUE; } #if (_WIN32_WINNT >= 0x500) // // HwAdapterControl - Handle adapter power and PnP events (Windows 2000+) // SCSI_ADAPTER_CONTROL_STATUS HwAdapterControl( IN PVOID DeviceExtension, IN SCSI_ADAPTER_CONTROL_TYPE ControlType, IN PVOID Parameters) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; SCSI_ADAPTER_CONTROL_STATUS status = ScsiAdapterControlSuccess; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwAdapterControl called - ControlType=%d\n", ControlType); #endif switch (ControlType) { case ScsiQuerySupportedControlTypes: { PSCSI_SUPPORTED_CONTROL_TYPE_LIST list = (PSCSI_SUPPORTED_CONTROL_TYPE_LIST)Parameters; // Indicate which control types we support list->SupportedTypeList[ScsiStopAdapter] = TRUE; list->SupportedTypeList[ScsiRestartAdapter] = TRUE; } break; case ScsiStopAdapter: // Stop the adapter - perform clean shutdown #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: ScsiStopAdapter - performing shutdown\n"); #endif NvmeShutdownController(DevExt); break; case ScsiRestartAdapter: // Restart the adapter - reinitialize controller #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: ScsiRestartAdapter - reinitializing\n"); #endif // Controller was reset, need to reinitialize if (HwInitialize(DevExt)) { status = ScsiAdapterControlSuccess; } else { status = ScsiAdapterControlUnsuccessful; } break; default: status = ScsiAdapterControlUnsuccessful; break; } return status; } #else // // HwAdapterState - Handle adapter state changes (Windows NT 4) // BOOLEAN HwAdapterState( IN PVOID DeviceExtension, IN PVOID Context, IN BOOLEAN SaveState) { PHW_DEVICE_EXTENSION DevExt = (PHW_DEVICE_EXTENSION)DeviceExtension; #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwAdapterState called - SaveState=%d\n", SaveState); #endif if (SaveState) { // Save adapter state - prepare for power down or hibernation #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwAdapterState - saving state and shutting down\n"); #endif // Perform clean shutdown of the NVMe controller NvmeShutdownController(DevExt); } else { // Restore adapter state - reinitialize after power up #ifdef NVME2K_DBG ScsiDebugPrint(0, "nvme2k: HwAdapterState - restoring state\n"); #endif // Reinitialize the controller return HwInitialize(DevExt); } return TRUE; } #endif
  16. Hi, I try to make a XP SP3 boot CD with the scsciport nvme driver nvme2k for to boot via it from nvme disk. When I put this driver via its nvme2k.inf to an already existing XP SP3 installation, I can boot from this nvme device. But "no disk" recogniced via real boot CD from XP SP3. May be, only a single entry I miss for a scsiport driver but I have no other idea Dietmar Here are the original and the modded files for the boot CD to enable nvme boot https://files.catbox.moe/igbiep.7z
  17. Hi, this could be a really interesting nvme driver for XP SP3 also, https://github.com/techomancer/nvme2k because it works with scsiport.sys and not storport.sys. Long time ago I thought about the same idea. And may be, with this nvme driver there is no need for any "nvme" in Bios, means old boards can have ALL nvme boot, because ONLY scsiport drivers can use ntbootdd.sys, build as this nvme driver. I wrote an own working ntbootdd.sys in 2004 driver for to do ramboot of XP Dietmar
  18. Hi, I just make a nice hack. I get a lot of Arduino nano for 67 Cent from China. They work under Win10 but not under XP SP3, "Unknown USB device". I use the Arduino IDE ver. 1.8.9 portable, means no installation. It has the exotic USB serial VID_0843&PID_5740. So, I take the win7 driver STM32_vcp_driver.zip from STMicroelectronics which has funny VID_0483&PID_5740. There I edit just the stmcdc.inf file only at this part ;------------------------------------------------------------------------------ ; VID/PID Settings ;------------------------------------------------------------------------------ [DeviceList.NT] %DESCRIPTION%=DriverInstall,USB\VID_0843&PID_5740 [DeviceList.NTamd64] %DESCRIPTION%=DriverInstall,USB\VID_0843&PID_5740 Right click on this modded stmcdc.inf "install", and voila, this Arduino nano clone from China works perfect under XP SP3 Dietmar
  19. @UsefulAGKHelper Here I put W2003_tools_update.7z good luck Dietmar https://files.catbox.moe/7wrcnc.7z
  20. @reboot12 Make some tests with disable and enable the Microsoft UAA drivers in System Devices. I remember, that I had the same problem and the admin @Dave-H here also with Baytrail Flex 10 and XP and sound Dietmar
  21. @reboot12 This can be a problem with a driver, that appears double. Make a try to disable really all. And then install your wished sound card and look what happens. With csmwrap I had the problem, that some parts of memory are occupied twice Dietmar
  22. @reboot12 Here it is, good luck Dietmar https://www.sendspace.com/file/2kr246
  23. @reboot12 Hi, I extracted your Bios but I dont know, where to upload it Dietmar
  24. @reboot12 I still do not understand, why now you get the latest Source files from csmwrap.efi . Is it, because you connect now to another server via git clone https://github.com/FlyGoat/CSMWrap.git --recursive Dietmar
×
×
  • Create New...