21 #include "ScsiCommands.h" 22 #include "ScsiController.h" 23 #include "pedigree/kernel/Log.h" 24 #include "pedigree/kernel/Service.h" 25 #include "pedigree/kernel/ServiceFeatures.h" 26 #include "pedigree/kernel/ServiceManager.h" 27 #include "pedigree/kernel/processor/PhysicalMemoryManager.h" 28 #include "pedigree/kernel/processor/types.h" 29 #include "pedigree/kernel/time/Time.h" 30 #include "pedigree/kernel/utilities/Cache.h" 31 #include "pedigree/kernel/utilities/PointerGuard.h" 32 #include "pedigree/kernel/utilities/assert.h" 33 #include "pedigree/kernel/utilities/utility.h" 35 #define READAHEAD_ENABLED 0 38 #define SCSI_DEBUG_LOG DEBUG_LOG 40 #define SCSI_DEBUG_LOG(...) 43 void ScsiDisk::cacheCallback(
44 CacheConstants::CallbackCause cause, uintptr_t loc, uintptr_t page,
51 case CacheConstants::WriteBack:
56 case CacheConstants::Eviction:
60 WARNING(
"ScsiDisk: unknown cache callback -- could indicate " 61 "potential future I/O issues.");
68 m_nAlignPoints(0), m_NumBlocks(0), m_BlockSize(0x1000),
69 m_DeviceType(NoDevice)
71 m_Cache.setCallback(cacheCallback,
this);
80 m_pController = pController;
89 bool success = sendCommand(
90 pCommand, reinterpret_cast<uintptr_t>(m_Inquiry),
sizeof(
Inquiry));
93 ERROR(
"ScsiDisk: INQUIRY failed!");
101 static_cast<ScsiPeripheralType
>(m_Inquiry->Peripheral & 0x1F);
111 "ScsiDisk: Unit not yet ready, sense data: [sk=" 112 << s->SenseKey <<
", asc=" << s->Asc <<
", ascq=" << s->AscQ
115 if (s->SenseKey == 0x2)
125 success = sendCommand(pCommand, 0, 0,
true);
130 "ScsiDisk: unit startup failed! Sense data: [sk=" 131 << s->SenseKey <<
", asc=" << s->Asc
132 <<
", ascq=" << s->AscQ <<
"]");
139 Time::delay(100 * Time::Multiplier::Millisecond);
146 "ScsiDisk: Unit not yet ready, sense data: [sk=" 147 << s->SenseKey <<
", asc=" << s->Asc <<
", ascq=" << s->AscQ
150 Time::delay(100 * Time::Multiplier::Millisecond);
156 "ScsiDisk: disk never became ready. Sense data: [sk=" 157 << s->SenseKey <<
", asc=" << s->Asc <<
", ascq=" << s->AscQ
165 getCapacityInternal(&m_NumBlocks, &m_NativeBlockSize);
167 "ScsiDisk: Capacity: " <<
Dec << m_NumBlocks <<
" blocks, each " 168 << m_NativeBlockSize <<
" bytes - " 169 << (m_NativeBlockSize * m_NumBlocks) <<
Hex 170 <<
" bytes in total.");
179 NOTICE(
"Attempting to inform the partitioner of our presence...");
184 sizeof(static_cast<Disk *>(
this))))
190 ERROR(
"ScsiDisk: Couldn't tell the partition service about the new " 194 ERROR(
"ScsiDisk: Partition service doesn't appear to support touch");
200 ByteSet(sense, 0xFF,
sizeof(
Sense));
205 uint8_t *response =
new uint8_t[
sizeof(
Sense)];
206 bool success = sendCommand(
207 pCommand, reinterpret_cast<uintptr_t>(response),
sizeof(
Sense));
210 WARNING(
"ScsiDisk: SENSE command failed");
216 MemoryCopy(sense, response,
sizeof(
Sense));
220 return ((sense->ResponseCode & 0x70) == 0x70);
226 bool success = sendCommand(pCommand, 0, 0);
234 bool ScsiDisk::getCapacityInternal(
size_t *blockNumber,
size_t *blockSize)
238 WARNING(
"ScsiDisk::getCapacityInternal - returning to defaults, unit " 241 *blockSize = defaultBlockSize();
247 ByteSet(capacity, 0,
sizeof(
Capacity));
250 bool success = sendCommand(
251 pCommand, reinterpret_cast<uintptr_t>(capacity),
sizeof(
Capacity),
256 WARNING(
"ScsiDisk::getCapacityInternal - READ CAPACITY command failed");
260 *blockNumber = BIG_TO_HOST32(capacity->LBA);
261 uint32_t blockSz = BIG_TO_HOST32(capacity->BlockSize);
262 *blockSize = blockSz ? blockSz : defaultBlockSize();
267 bool ScsiDisk::sendCommand(
268 ScsiCommand *pCommand, uintptr_t pRespBuffer, uint16_t nRespBytes,
271 uintptr_t pCommandBuffer = 0;
272 size_t nCommandSize = pCommand->serialise(pCommandBuffer);
273 return m_pController->sendCommand(
274 m_nUnit, pCommandBuffer, nCommandSize, pRespBuffer, nRespBytes, bWrite);
279 if (!(getBlockSize() && getNativeBlockSize()))
281 ERROR(
"ScsiDisk::read - block size is zero.");
285 size_t endLocation = location + getNativeBlockSize();
286 if (endLocation > getSize())
289 "ScsiDisk::read - location too high (end location " 290 << endLocation <<
" > " << getSize() <<
")");
294 size_t blockNum = location / getNativeBlockSize();
295 if (blockNum > getBlockCount())
298 "ScsiDisk::read - location too high (block " 299 << blockNum <<
" > " << getBlockCount() <<
")");
304 uint64_t alignPoint = 0;
305 for (
size_t i = 0; i < m_nAlignPoints; i++)
306 if (m_AlignPoints[i] <= location && m_AlignPoints[i] > alignPoint)
307 alignPoint = m_AlignPoints[i];
310 ssize_t offs = -((location - alignPoint) % 4096);
313 if ((buffer = m_Cache.lookup(location + offs)))
315 return buffer - offs;
319 size_t loc = (location + offs) & ~(getBlockSize() - 1);
323 0, SCSI_REQUEST_READ, reinterpret_cast<uint64_t>(
this), loc);
324 if (numRead < getBlockSize())
327 WARNING(
"ScsiDisk::read - short read!");
330 #if READAHEAD_ENABLED 332 for (
size_t i = 0; i < 2; ++i)
334 loc += getBlockSize();
336 0, SCSI_REQUEST_READ, reinterpret_cast<uint64_t>(
this), loc);
339 return m_Cache.lookup(location + offs) - offs;
345 if (!(getBlockSize() && getNativeBlockSize()))
347 ERROR(
"ScsiDisk::write - block size is zero.");
351 if ((location + getNativeBlockSize()) > getSize())
353 ERROR(
"ScsiDisk::write - location too high");
354 ERROR(
" -> " << location <<
" vs " << getSize());
358 if ((location / getNativeBlockSize()) > getBlockCount())
360 ERROR(
"ScsiDisk::write - location too high");
362 " -> block " << (location / getNativeBlockSize()) <<
" vs " 368 uint64_t alignPoint = 0;
369 for (
size_t i = 0; i < m_nAlignPoints; i++)
370 if (m_AlignPoints[i] <= location && m_AlignPoints[i] > alignPoint)
371 alignPoint = m_AlignPoints[i];
374 ssize_t offs = -((location - alignPoint) % 4096);
377 if (!(buffer = m_Cache.lookup(location + offs)))
379 ERROR(
"ScsiDisk::write - no buffer!");
387 0, SCSI_REQUEST_WRITE, reinterpret_cast<uint64_t>(
this),
395 if (!(getBlockSize() && getNativeBlockSize()))
397 ERROR(
"ScsiDisk::flush - block size is zero.");
401 if ((location + getNativeBlockSize()) > getSize())
403 ERROR(
"ScsiDisk::flush - location too high");
407 if ((location / getNativeBlockSize()) > getBlockCount())
409 ERROR(
"ScsiDisk::flush - location too high");
414 uint64_t alignPoint = 0;
415 for (
size_t i = 0; i < m_nAlignPoints; i++)
416 if (m_AlignPoints[i] <= location && m_AlignPoints[i] > alignPoint)
417 alignPoint = m_AlignPoints[i];
420 ssize_t offs = -((location - alignPoint) % 4096);
423 if (!(buffer = m_Cache.lookup(location + offs)))
429 m_Cache.pin(location + offs);
433 0, SCSI_REQUEST_WRITE, reinterpret_cast<uint64_t>(
this),
435 pParent->
addRequest(0, reinterpret_cast<uint64_t>(
this), location + offs);
438 m_Cache.release(location + offs);
444 assert(m_nAlignPoints < 8);
445 m_AlignPoints[m_nAlignPoints++] = location;
452 for (
int i = 0; i < 3; i++)
454 if ((bReady = unitReady()))
460 ERROR(
"ScsiDisk::doRead - unit not ready");
466 uintptr_t buffer = m_Cache.lookup(location);
470 "ScsiDisk::doRead(" << location
471 <<
") - buffer was already in cache");
472 m_Cache.release(location);
475 buffer = m_Cache.insert(location, getBlockSize());
478 FATAL(
"ScsiDisk::doRead - no buffer");
481 size_t blockNum = location / getNativeBlockSize();
482 size_t blockCount = getBlockSize() / getNativeBlockSize();
488 if (m_DeviceType == CdDvdDevice)
492 uint8_t *toc =
new uint8_t[getNativeBlockSize()];
495 pCommand, reinterpret_cast<uintptr_t>(toc), getNativeBlockSize());
499 WARNING(
"ScsiDisk::doRead - could not find data track (READ TOC " 505 bool bHaveTrack =
false;
507 uint16_t bufLen = BIG_TO_HOST16((toc[0] << 8) | toc[1]);
510 for (i = 0; i < (bufLen / 8); i++)
512 if (Toc[i].Flags == 0x14)
522 "ScsiDisk::doRead - could not find data track (no data track)");
526 uint32_t trackStart = BIG_TO_HOST32(Toc[i].TrackStart);
527 if ((blockNum + trackStart) < blockNum)
529 WARNING(
"ScsiDisk::doRead - TOC overflow");
533 blockNum += trackStart;
536 for (
int i = 0; i < 3 && !bOk; i++)
538 SCSI_DEBUG_LOG(
"SCSI: trying read(10)");
540 bOk = sendCommand(pCommand, buffer, getBlockSize());
543 for (
int i = 0; i < 3 && !bOk; i++)
545 SCSI_DEBUG_LOG(
"SCSI: trying read(12)");
547 bOk = sendCommand(pCommand, buffer, getBlockSize());
550 for (
int i = 0; i < 3 && !bOk; i++)
552 SCSI_DEBUG_LOG(
"SCSI: trying read(16)");
554 bOk = sendCommand(pCommand, buffer, getBlockSize());
560 m_Cache.markNoLongerEditing(location, getBlockSize());
564 ERROR(
"SCSI: reading failed?");
567 return getBlockSize();
570 uint64_t ScsiDisk::doWrite(uint64_t location)
574 for (
int i = 0; i < 3; i++)
576 if ((bReady = unitReady()))
582 ERROR(
"ScsiDisk::doWrite - unit not ready");
588 uintptr_t buffer = m_Cache.lookup(location);
592 "ScsiDisk::doWrite(" << location <<
") - buffer was not in cache");
599 size_t block = location / getNativeBlockSize();
600 size_t count = 4096 / getNativeBlockSize();
605 for (
int i = 0; i < 3; i++)
607 SCSI_DEBUG_LOG(
"SCSI: trying write(10)");
609 bOk = sendCommand(pCommand, buffer, 4096,
true);
616 for (
int i = 0; i < 3; i++)
618 SCSI_DEBUG_LOG(
"SCSI: trying write(12)");
620 bOk = sendCommand(pCommand, buffer, 4096,
true);
628 for (
int i = 0; i < 3; i++)
630 SCSI_DEBUG_LOG(
"SCSI: trying write(16)");
632 bOk = sendCommand(pCommand, buffer, 4096,
true);
641 ERROR(
"SCSI: writing failed?");
644 return getBlockSize();
647 uint64_t ScsiDisk::doSync(uint64_t location)
651 for (
int i = 0; i < 3; i++)
653 if ((bReady = unitReady()))
659 ERROR(
"ScsiDisk::doSync - unit not ready");
663 size_t block = location / getNativeBlockSize();
664 size_t count = 4096 / getNativeBlockSize();
671 for (
int i = 0; i < 3; i++)
673 SCSI_DEBUG_LOG(
"SCSI: trying synchronise(10)");
675 bOk = sendCommand(pCommand, 0, 0);
683 for (
int i = 0; i < 3; i++)
685 SCSI_DEBUG_LOG(
"SCSI: trying synchronise(16)");
687 bOk = sendCommand(pCommand, 0, 0);
694 return getBlockSize();
699 m_Cache.pin(location);
704 m_Cache.release(location);
virtual void write(uint64_t location)
virtual void flush(uint64_t location)
Flush a cached page to disk.
uint64_t addAsyncRequest(size_t priority, uint64_t p1=0, uint64_t p2=0, uint64_t p3=0, uint64_t p4=0, uint64_t p5=0, uint64_t p6=0, uint64_t p7=0, uint64_t p8=0)
virtual void align(uint64_t location)
Sets the page boundary alignment after a specific location on the disk.
virtual bool provides(Type service)
virtual uint64_t doRead(uint64_t location)
Service * getService(const String &serviceName)
virtual void unpin(uint64_t location)
virtual bool serve(ServiceFeatures::Type type, void *pData, size_t dataLen)=0
bool initialise(class ScsiController *pController, size_t nUnit)
MUST_USE_RESULT uint64_t addRequest(size_t priority, uint64_t p1=0, uint64_t p2=0, uint64_t p3=0, uint64_t p4=0, uint64_t p5=0, uint64_t p6=0, uint64_t p7=0, uint64_t p8=0)
virtual uintptr_t read(uint64_t location)
ServiceFeatures * enumerateOperations(const String &serviceName)
virtual void pin(uint64_t location)
Pins a cache page.