```cpp // Condensed IOUserSCSIParallelInterfaceController: virtual disk, no hardware, no DMA. // All data moves by CPU copy via UserGetDataBuffer; fBufferIOVMAddr is never used. constexpr uint64_t kXferBytes = 16384; // == SegmentByteCount == maxTransferSize constexpr uint64_t kPageBytes = 16384; // Apple-Silicon page constexpr uint32_t kBlockLen = 4096; kern_return_t IMPL(MyController, UserInitializeController) { // ... allocate backing store, queues, etc. ... // The seven required constraint keys. OSDictionary * c = OSDictionary::withCapacity(8); putU64(c, kIOMaximumSegmentCountReadKey, 1); putU64(c, kIOMaximumSegmentCountWriteKey, 1); putU64(c, kIOMaximumSegmentByteCountReadKey, kXferBytes); putU64(c, kIOMaximumSegmentByteCountWriteKey, kXferBytes); putU64(c, kIOMinimumSegmentAlignmentByteCountKey, kPageBytes); putU64(c, kIOMaximumSegmentAddressableBitCountKey, 64); putU64(c, kIOMinimumHBADataAlignmentMaskKey, 0xFFFFFFFFFFFFFFFFULL); kern_return_t ret = UserReportHBAConstraints(c); OSSafeReleaseNULL(c); if (ret != kIOReturnSuccess) return ret; // FB21256805: the deblocking layer reads its limits from NODE properties, // not from UserReportHBAConstraints — republish the same values there. OSDictionary * p = OSDictionary::withCapacity(8); putU64(p, kIOMaximumByteCountReadKey, kXferBytes); putU64(p, kIOMaximumByteCountWriteKey, kXferBytes); putU64(p, kIOMaximumSegmentCountReadKey, 1); putU64(p, kIOMaximumSegmentCountWriteKey, 1); putU64(p, kIOMaximumSegmentByteCountReadKey, kXferBytes); putU64(p, kIOMaximumSegmentByteCountWriteKey, kXferBytes); putU64(p, kIOMinimumSegmentAlignmentByteCountKey, kPageBytes); SetProperties(p); OSSafeReleaseNULL(p); return kIOReturnSuccess; } kern_return_t IMPL(MyController, UserGetDMASpecification) { *maxTransferSize = kXferBytes; // == 1 segment × kIOMaximumSegmentByteCount *alignment = 1; // 16384 triggers the double-buffer read clobber (question 3) *numAddressBits = 64; // 32 breaks enumeration (INQUIRY buffers rejected) *segmentType = kDMAOutputSegmentHost64; return kIOReturnSuccess; } kern_return_t IMPL(MyController, UserReportMaximumTaskCount) { *count = 512; return kIOReturnSuccess; } kern_return_t IMPL(MyController, UserMapHBAData) { static uint32_t next = 0; *uniqueTaskID = ++next; return kIOReturnSuccess; } // ReportHBASpecificTaskDataSize returns 0 — no per-task HBA data. void IMPL(MyController, UserProcessParallelTask) // never reached for straddling tasks { const uint8_t op = parallelTask.fCommandDescriptorBlock[0]; const uint64_t len = parallelTask.fRequestedByteCountOfTransfer; SCSIUserParallelResponse r = {}; r.fControllerTaskIdentifier = parallelTask.fControllerTaskIdentifier; r.fTargetID = parallelTask.fTargetID; r.fServiceResponse = kSCSIServiceResponse_TASK_COMPLETE; r.fCompletionStatus = kSCSITaskStatus_GOOD; if (op == 0x28 /*READ(10)*/ || op == 0x2A /*WRITE(10)*/) { const uint64_t lba = be32(&parallelTask.fCommandDescriptorBlock[2]); IOBufferMemoryDescriptor * buf = nullptr; // contiguous kernel copy of the client buffer, any layout: UserGetDataBuffer(parallelTask.fTargetID, parallelTask.fControllerTaskIdentifier, &buf); IOAddressSegment seg = {}; buf->GetAddressRange(&seg); if (op == 0x2A) writeMedia(lba * kBlockLen, (void *)seg.address, len); else readMedia (lba * kBlockLen, (void *)seg.address, len); OSSafeReleaseNULL(buf); r.fBytesTransferred = len; } // ... INQUIRY / READ CAPACITY / TUR / SYNCHRONIZE CACHE handled similarly ... ParallelTaskCompletion(completion, r); } ```