| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315 | // SCSI trace logging//// Copyright (c) 2022 Rabbit Hole Computing™// Copyright (c) 2023 Eric Helgeson#include "BlueSCSI_log_trace.h"#include "BlueSCSI_log.h"#include <scsi2sd.h>#include "BlueSCSI_Toolbox.h"extern "C" {#include <scsi.h>#include <scsiPhy.h>}static bool g_LogData = false;static bool g_LogInitiatorCommand = false;static int g_InByteCount = 0;static int g_OutByteCount = 0;static uint16_t g_DataChecksum = 0;static const char *getCommandName(uint8_t cmd){    switch (cmd)    {        case 0x00: return "TestUnitReady";        case 0x01: return "RezeroUnit/Rewind";        case 0x03: return "RequestSense";        case 0x04: return "FormatUnit";        case 0x05: return "ReadBlockLimits";        case 0x06: return "IomegaVendorCommand";        case 0x08: return "Read6";        case 0x0A: return "Write6";        case 0x0B: return "Seek6";        case 0x0C: return "Xebec InitializeDriveCharacteristics";        case 0x0F: return "Xebec WriteSectorBuffer";        case 0x10: return "WriteFilemarks";        case 0x11: return "Space";        case 0x12: return "Inquiry";        case 0x13: return "Verify";        case 0x15: return "ModeSelect6";        case 0x16: return "Reserve";        case 0x17: return "Release";        case 0x19: return "Erase";        case 0x1A: return "ModeSense";        case 0x1B: return "StartStopUnit";        case 0x1C: return "ReceiveDiagnostic";        case 0x1D: return "SendDiagnostic";        case 0x1E: return "PreventAllowMediumRemoval";        case 0x25: return "ReadCapacity";        case 0x28: return "Read10";        case 0x2A: return "Write10";        case 0x2B: return "Seek10";        case 0x2C: return "Erase10";        case 0x2E: return "WriteVerify";        case 0x2F: return "Verify";        case 0x34: return "PreFetch/ReadPosition";        case 0x35: return "SynchronizeCache";        case 0x36: return "LockUnlockCache";        case 0x37: return "ReadDefectData";        case 0x3B: return "WriteBuffer";        case 0x3C: return "ReadBuffer";        case 0x42: return "CDROM Read SubChannel";        case 0x43: return "CDROM Read TOC";        case 0x44: return "CDROM Read Header";        case 0x46: return "CDROM GetConfiguration";        case 0x4A: return "GetEventStatusNotification";        case 0x4B: return "CDROM PauseResume";        case 0x4E: return "CDROM StopPlayScan";        case 0x51: return "CDROM ReadDiscInformation";        case 0x45: return "CDROM PlayAudio10";        case 0xA5: return "CDROM PlayAudio12";        case 0x47: return "CDROM PlayAudioMSF";        case 0x48: return "CDROM PauseResume";        case 0x52: return "CDROM ReadTrackInformation";        case 0xBB: return "CDROM SetCDSpeed";        case 0xBD: return "CDROM MechanismStatus";        case 0xBE: return "ReadCD";        case 0xB9: return "ReadCDMSF";        case 0x55: return "ModeSelect10";        case 0x5A: return "ModeSense10";        case 0xAC: return "Erase12";        case 0xA8: return "Read12";        case 0xC0: return "OMTI-5204 DefineFlexibleDiskFormat";        case 0xC2: return "OMTI-5204 AssignDiskParameters";        case 0xE0: return "Xebec RAM Diagnostic";        case 0xE4: return "Xebec Drive Diagnostic";        case BLUESCSI_TOOLBOX_COUNT_FILES: return "BLUESCSI_TOOLBOX_COUNT_FILES";        case BLUESCSI_TOOLBOX_LIST_FILES: return "BLUESCSI_TOOLBOX_LIST_FILES";        case BLUESCSI_TOOLBOX_GET_FILE: return "BLUESCSI_TOOLBOX_GET_FILE";        case BLUESCSI_TOOLBOX_SEND_FILE_PREP: return "BLUESCSI_TOOLBOX_SEND_FILE_PREP";        case BLUESCSI_TOOLBOX_SEND_FILE_10: return "BLUESCSI_TOOLBOX_SEND_FILE_10";        case BLUESCSI_TOOLBOX_SEND_FILE_END: return "BLUESCSI_TOOLBOX_SEND_FILE_END";        case BLUESCSI_TOOLBOX_TOGGLE_DEBUG: return "BLUESCSI_TOOLBOX_TOGGLE_DEBUG";        case BLUESCSI_TOOLBOX_LIST_CDS: return "BLUESCSI_TOOLBOX_LIST_CDS";        case BLUESCSI_TOOLBOX_SET_NEXT_CD: return "BLUESCSI_TOOLBOX_SET_NEXT_CD";        case BLUESCSI_TOOLBOX_LIST_DEVICES: return "BLUESCSI_TOOLBOX_LIST_DEVICES";        case BLUESCSI_TOOLBOX_COUNT_CDS: return "BLUESCSI_TOOLBOX_COUNT_CDS";        default:   return "Unknown";    }}static void printNewPhase(int phase, bool initiator = false){    g_LogData = false;    g_LogInitiatorCommand = false;    if (!g_log_debug)    {        return;    }    switch(phase)    {        case BUS_FREE:            debuglog("-- BUS_FREE");            break;        case BUS_BUSY:            debuglog("-- BUS_BUSY");            break;        case ARBITRATION:            debuglog("---- ARBITRATION");            break;        case SELECTION:            if (initiator)                debuglog("---- SELECTION");            else                debuglog("---- SELECTION: ", (int)(*SCSI_STS_SELECTED & 7));            break;        case RESELECTION:            debuglog("---- RESELECTION");            break;        case STATUS:            if (initiator)            {                debuglog("---- STATUS");                g_LogData = true;            }            else if (scsiDev.status == GOOD)            {                debuglog("---- STATUS: 0 GOOD");            }            else if (scsiDev.status == CHECK_CONDITION && scsiDev.target)            {                debuglog("---- STATUS: 2 CHECK_CONDITION, sense ", (uint32_t)scsiDev.target->sense.asc);            }            else            {                debuglog("---- STATUS: ", (int)scsiDev.status);            }            break;        case COMMAND:            g_LogInitiatorCommand = initiator;            g_LogData = true;            break;        case DATA_IN:            if (!initiator && scsiDev.target->syncOffset > 0)                debuglog("---- DATA_IN, syncOffset ", (int)scsiDev.target->syncOffset,                                   " syncPeriod ", (int)scsiDev.target->syncPeriod);            else                debuglog("---- DATA_IN");            break;        case DATA_OUT:            if (!initiator && scsiDev.target->syncOffset > 0)                debuglog("---- DATA_OUT, syncOffset ", (int)scsiDev.target->syncOffset,                                    " syncPeriod ", (int)scsiDev.target->syncPeriod);	    // log Xebec vendor commands data	    else if (scsiDev.cdb[0] == 0x0C || scsiDev.cdb[0] == 0x0F)		    g_LogData = true;            else                debuglog("---- DATA_OUT");            break;        case MESSAGE_IN:            debuglog("---- MESSAGE_IN");            g_LogData = true;            break;        case MESSAGE_OUT:            debuglog("---- MESSAGE_OUT");            g_LogData = true;            break;        default:            debuglog("---- PHASE: ", phase);            break;    }}void scsiLogPhaseChange(int new_phase){    static int old_scsi_id = 0;    static int old_phase = BUS_FREE;    static int old_sync_period = 0;    if (new_phase != old_phase)    {        if (old_phase == DATA_IN || old_phase == DATA_OUT)        {            debuglog("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);        }	// log Xebec vendor command        if (old_phase == DATA_OUT && scsiDev.cdb[0] == 0x0C && g_OutByteCount == 8)	{		int cylinders = ((uint16_t)scsiDev.data[0] << 8) + scsiDev.data[1];		int heads = scsiDev.data[2];		int reducedWrite = ((uint16_t)scsiDev.data[3] << 8) + scsiDev.data[4];		int writePrecomp = ((uint16_t)scsiDev.data[5] << 8) + scsiDev.data[6];		int eccBurst = scsiDev.data[7];		debuglog("---- Xebec Initialize Drive Characteristics: cylinders=", cylinders, " heads=", heads,				 " reducedWrite=", reducedWrite, " writePrecomp=", writePrecomp, " eccBurst=", eccBurst);	}        g_InByteCount = g_OutByteCount = 0;        g_DataChecksum = 0;        if (old_phase >= 0 &&            scsiDev.target != NULL &&            old_scsi_id == scsiDev.target->targetId &&            old_sync_period != scsiDev.target->syncPeriod)        {            // Add a log message when negotiated synchronous speed changes.            int syncper = scsiDev.target->syncPeriod;            int syncoff = scsiDev.target->syncOffset;            if (syncper > 0)            {                int mbyte_per_s = (1000 + syncper * 2) / (syncper * 4);                log("SCSI ID ", (int)scsiDev.target->targetId,                    " negotiated synchronous mode ", mbyte_per_s, " MB/s ",                    "(period 4x", syncper, " ns, offset ", syncoff, " bytes)");            }            else            {                log("SCSI ID ", (int)scsiDev.target->targetId,                    " negotiated asynchronous mode ",                    "(period 4x", syncper, " ns, offset ", syncoff, " bytes)");            }        }        printNewPhase(new_phase);        old_phase = new_phase;        old_sync_period = scsiDev.target->syncPeriod;        old_scsi_id = scsiDev.target->targetId;    }}void scsiLogInitiatorPhaseChange(int new_phase){    static int old_phase = BUS_FREE;    if (new_phase != old_phase)    {        if (old_phase == DATA_IN || old_phase == DATA_OUT)        {            debuglog("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);        }        g_InByteCount = g_OutByteCount = 0;        g_DataChecksum = 0;        printNewPhase(new_phase, true);        old_phase = new_phase;    }}void scsiLogDataIn(const uint8_t *buf, uint32_t length){    if (g_LogData)    {        debuglog("------ IN: ", bytearray(buf, length));    }    if (g_log_debug)    {        // BSD checksum algorithm        for (uint32_t i = 0; i < length; i++)        {            g_DataChecksum = (g_DataChecksum >> 1) + ((g_DataChecksum & 1) << 15);            g_DataChecksum += buf[i];        }    }    g_InByteCount += length;}void scsiLogDataOut(const uint8_t *buf, uint32_t length){    if (buf == scsiDev.cdb || g_LogInitiatorCommand)    {        debuglog("---- COMMAND: ", getCommandName(buf[0]));    }    if (g_LogData)    {        debuglog("------ OUT: ", bytearray(buf, length));    }    if (g_log_debug)    {        // BSD checksum algorithm        for (uint32_t i = 0; i < length; i++)        {            g_DataChecksum = (g_DataChecksum >> 1) + ((g_DataChecksum & 1) << 15);            g_DataChecksum += buf[i];        }    }    g_OutByteCount += length;}
 |