Annotation of hatari/src/hdc.c, revision 1.1.1.14

1.1       root        1: /*
1.1.1.3   root        2:   Hatari - hdc.c
1.1       root        3: 
1.1.1.3   root        4:   This file is distributed under the GNU Public License, version 2 or at
                      5:   your option any later version. Read the file gpl.txt for details.
1.1       root        6: 
1.1.1.3   root        7:   Low-level hard drive emulation
1.1       root        8: */
1.1.1.10  root        9: const char HDC_fileid[] = "Hatari hdc.c : " __DATE__ " " __TIME__;
1.1       root       10: 
                     11: #include "main.h"
1.1.1.3   root       12: #include "configuration.h"
1.1.1.6   root       13: #include "debugui.h"
1.1.1.7   root       14: #include "file.h"
1.1       root       15: #include "fdc.h"
                     16: #include "hdc.h"
1.1.1.14! root       17: #include "ioMem.h"
1.1.1.7   root       18: #include "log.h"
1.1       root       19: #include "memorySnapShot.h"
                     20: #include "mfp.h"
                     21: #include "stMemory.h"
1.1.1.6   root       22: #include "tos.h"
1.1.1.9   root       23: #include "statusbar.h"
                     24: 
1.1       root       25: 
                     26: /*
                     27:   ACSI emulation: 
                     28:   ACSI commands are six byte-packets sent to the
                     29:   hard drive controller (which is on the HD unit, not in the ST)
                     30: 
                     31:   While the hard drive is busy, DRQ is high, polling the DRQ during
                     32:   operation interrupts the current operation. The DRQ status can
                     33:   be polled non-destructively in GPIP.
1.1.1.7   root       34: 
1.1       root       35:   (For simplicity, the operation is finished immediatly,
                     36:   this is a potential bug, but I doubt it is significant,
                     37:   we just appear to have a very fast hard drive.)
                     38: 
                     39:   The ACSI command set is a subset of the SCSI standard.
                     40:   (for details, see the X3T9.2 SCSI draft documents
                     41:   from 1985, for an example of writing ACSI commands,
                     42:   see the TOS DMA boot code) 
                     43: */
                     44: 
1.1.1.7   root       45: // #define DISALLOW_HDC_WRITE
                     46: // #define HDC_VERBOSE           /* display operations */
                     47: // #define HDC_REALLY_VERBOSE    /* display command packets */
1.1       root       48: 
1.1.1.14! root       49: #define HDC_ReadInt16(a, i) (((unsigned) a[i] << 8) | a[i + 1])
        !            50: #define HDC_ReadInt24(a, i) (((unsigned) a[i] << 16) | ((unsigned) a[i + 1] << 8) | a[i + 2])
        !            51: #define HDC_ReadInt32(a, i) (((unsigned) a[i] << 24) | ((unsigned) a[i + 1] << 16) | ((unsigned) a[i + 2] << 8) | a[i + 3])
        !            52: 
        !            53: /**
        !            54:  *  Structure representing an ACSI command block.
        !            55:  */
        !            56: typedef struct {
        !            57:   int readCount;    /* count of number of command bytes written */
        !            58:   unsigned char target;
        !            59:   unsigned char opcode;
        !            60:   bool extended;
        !            61: 
        !            62:   int byteCount;             /* count of number of command bytes written */
        !            63:   unsigned char command[10];
        !            64:   short int returnCode;      /* return code from the HDC operation */
        !            65: } HDCOMMAND;
        !            66: 
1.1       root       67: /* HDC globals */
                     68: HDCOMMAND HDCCommand;
                     69: int nPartitions = 0;
1.1.1.14! root       70: unsigned long hdSize = 0;
1.1       root       71: short int HDCSectorCount;
1.1.1.11  root       72: bool bAcsiEmuOn = false;
1.1.1.7   root       73: 
1.1.1.12  root       74: static FILE *hd_image_file = NULL;
1.1.1.7   root       75: static Uint32 nLastBlockAddr;
1.1.1.9   root       76: static bool bSetLastBlockAddr;
1.1.1.7   root       77: static Uint8 nLastError;
1.1       root       78: 
1.1.1.7   root       79: /*
1.1.1.4   root       80:   FDC registers used:
                     81:   - FDCSectorCountRegister
1.1       root       82: */
                     83: 
                     84: 
                     85: /* Our dummy INQUIRY response data */
1.1.1.7   root       86: static unsigned char inquiry_bytes[] =
1.1       root       87: {
1.1.1.7   root       88:        0,                /* device type 0 = direct access device */
                     89:        0,                /* device type qualifier (nonremovable) */
                     90:        1,                /* ANSI version */
                     91:        0,                /* reserved */
                     92:        26,               /* length of the following data */
                     93:        ' ', ' ', ' ',                         /* Vendor specific data */
1.1.1.12  root       94:        'H','a','t','a','r','i',' ',' ',       /* Vendor */
                     95:        'E','m','u','l','a','t','e','d',       /* Model */
1.1.1.7   root       96:        ' ',' ',' ',' ',                       /* Revision */
                     97:        0,0,0,0,0,0,0,0,0,0                    /* ?? */
1.1       root       98: };
                     99: 
1.1.1.7   root      100: 
1.1       root      101: /*---------------------------------------------------------------------*/
1.1.1.8   root      102: /**
1.1.1.14! root      103:  * Return the device specified in the current ACSI command block.
        !           104:  */
        !           105: static unsigned char HDC_GetDevice(void)
        !           106: {
        !           107:        return (HDCCommand.command[1] & 0xE0) >> 5;
        !           108: }
        !           109: 
        !           110: /**
        !           111:  * Return the file offset of the sector specified in the current ACSI command block.
1.1.1.8   root      112:  */
1.1.1.4   root      113: static unsigned long HDC_GetOffset(void)
                    114: {
1.1.1.14! root      115:        /* offset = logical block address * 512 */
        !           116:        return HDCCommand.opcode < 0x20?
        !           117:                // class 0
        !           118:                (HDC_ReadInt24(HDCCommand.command, 1) & 0x1FFFFF) << 9 :
        !           119:                // class 1
        !           120:                HDC_ReadInt32(HDCCommand.command, 2) << 9;
        !           121: }
1.1       root      122: 
1.1.1.14! root      123: /**
        !           124:  * Return the count specified in the current ACSI command block.
        !           125:  */
        !           126: static int HDC_GetCount(void)
        !           127: {
        !           128:        return HDCCommand.opcode < 0x20?
        !           129:                // class 0
        !           130:                HDCCommand.command[4] :
        !           131:                // class1
        !           132:                HDC_ReadInt16(HDCCommand.command, 7);
        !           133: }
1.1.1.7   root      134: 
1.1.1.14! root      135: /**
        !           136:  * Return the control byte specified in the current ACSI command block.
        !           137:  */
        !           138: #ifdef HDC_REALLY_VERBOSE
        !           139: static unsigned char HDC_GetControl(void)
        !           140: {
        !           141:        return HDCCommand.opcode < 0x20?
        !           142:                // class 0
        !           143:                HDCCommand.command[5] :
        !           144:                // class1
        !           145:                HDCCommand.command[9];
1.1       root      146: }
1.1.1.14! root      147: #endif
1.1       root      148: 
1.1.1.7   root      149: 
1.1       root      150: /*---------------------------------------------------------------------*/
1.1.1.8   root      151: /**
                    152:  * Seek - move to a sector
                    153:  */
1.1.1.7   root      154: static void HDC_Cmd_Seek(void)
1.1       root      155: {
1.1.1.7   root      156:        nLastBlockAddr = HDC_GetOffset();
1.1       root      157: 
1.1.1.7   root      158:        if (fseek(hd_image_file, nLastBlockAddr, SEEK_SET) == 0)
                    159:        {
                    160:                HDCCommand.returnCode = HD_STATUS_OK;
                    161:                nLastError = HD_REQSENS_OK;
                    162:        }
                    163:        else
                    164:        {
                    165:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    166:                nLastError = HD_REQSENS_INVADDR;
                    167:        }
1.1       root      168: 
1.1.1.11  root      169:        FDC_SetDMAStatus(false);              /* no DMA error */
1.1.1.7   root      170:        FDC_AcknowledgeInterrupt();
1.1.1.11  root      171:        bSetLastBlockAddr = true;
1.1.1.7   root      172:        //FDCSectorCountRegister = 0;
1.1       root      173: }
                    174: 
1.1.1.7   root      175: 
1.1       root      176: /*---------------------------------------------------------------------*/
1.1.1.8   root      177: /**
                    178:  * Inquiry - return some disk information
                    179:  */
1.1.1.7   root      180: static void HDC_Cmd_Inquiry(void)
                    181: {
1.1.1.12  root      182:        Uint32 nDmaAddr;
                    183:        int count;
                    184: 
1.1.1.14! root      185:        nDmaAddr = FDC_GetDMAAddress();
        !           186:        count = HDC_GetCount();
1.1.1.12  root      187: 
1.1.1.7   root      188: #ifdef HDC_VERBOSE
1.1.1.12  root      189:        fprintf(stderr,"HDC: Inquiry, %i bytes to 0x%x.\n", count, nDmaAddr);
1.1.1.7   root      190: #endif
                    191: 
1.1.1.12  root      192:        if (count > (int)sizeof(inquiry_bytes))
                    193:                count = sizeof(inquiry_bytes);
                    194: 
                    195:        inquiry_bytes[4] = count - 8;
                    196: 
1.1.1.13  root      197:        if (STMemory_SafeCopy(nDmaAddr, inquiry_bytes, count, "HDC DMA inquiry"))
                    198:                HDCCommand.returnCode = HD_STATUS_OK;
                    199:        else
                    200:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    201: 
1.1.1.12  root      202:        FDC_WriteDMAAddress(nDmaAddr + count);
1.1.1.7   root      203: 
1.1.1.11  root      204:        FDC_SetDMAStatus(false);              /* no DMA error */
1.1.1.7   root      205:        FDC_AcknowledgeInterrupt();
                    206:        nLastError = HD_REQSENS_OK;
1.1.1.11  root      207:        bSetLastBlockAddr = false;
1.1.1.7   root      208:        //FDCSectorCountRegister = 0;
                    209: }
                    210: 
                    211: 
                    212: /*---------------------------------------------------------------------*/
1.1.1.8   root      213: /**
                    214:  * Request sense - return some disk information
                    215:  */
1.1.1.7   root      216: static void HDC_Cmd_RequestSense(void)
1.1       root      217: {
1.1.1.7   root      218:        Uint32 nDmaAddr;
                    219:        int nRetLen;
                    220:        Uint8 retbuf[22];
                    221: 
                    222: #ifdef HDC_VERBOSE
                    223:        fprintf(stderr,"HDC: Request Sense.\n");
                    224: #endif
                    225: 
1.1.1.14! root      226:        nRetLen = HDC_GetCount();
1.1.1.7   root      227: 
                    228:        if ((nRetLen < 4 && nRetLen != 0) || nRetLen > 22)
                    229:        {
1.1.1.9   root      230:                Log_Printf(LOG_WARN, "HDC: *** Strange REQUEST SENSE ***!\n");
1.1.1.7   root      231:        }
                    232: 
                    233:        /* Limit to sane length */
                    234:        if (nRetLen <= 0)
                    235:        {
                    236:                nRetLen = 4;
                    237:        }
                    238:        else if (nRetLen > 22)
                    239:        {
                    240:                nRetLen = 22;
                    241:        }
                    242: 
1.1.1.14! root      243:        nDmaAddr = FDC_GetDMAAddress();
1.1.1.7   root      244: 
                    245:        memset(retbuf, 0, nRetLen);
                    246: 
                    247:        if (nRetLen <= 4)
                    248:        {
                    249:                retbuf[0] = nLastError;
                    250:                if (bSetLastBlockAddr)
                    251:                {
                    252:                        retbuf[0] |= 0x80;
                    253:                        retbuf[1] = nLastBlockAddr >> 16;
                    254:                        retbuf[2] = nLastBlockAddr >> 8;
                    255:                        retbuf[3] = nLastBlockAddr;
                    256:                }
                    257:        }
                    258:        else
                    259:        {
                    260:                retbuf[0] = 0x70;
                    261:                if (bSetLastBlockAddr)
                    262:                {
                    263:                        retbuf[0] |= 0x80;
                    264:                        retbuf[4] = nLastBlockAddr >> 16;
                    265:                        retbuf[5] = nLastBlockAddr >> 8;
                    266:                        retbuf[6] = nLastBlockAddr;
                    267:                }
                    268:                switch (nLastError)
                    269:                {
                    270:                 case HD_REQSENS_OK:  retbuf[2] = 0; break;
                    271:                 case HD_REQSENS_OPCODE:  retbuf[2] = 5; break;
                    272:                 case HD_REQSENS_INVADDR:  retbuf[2] = 5; break;
                    273:                 case HD_REQSENS_INVARG:  retbuf[2] = 5; break;
                    274:                 case HD_REQSENS_NODRIVE:  retbuf[2] = 2; break;
                    275:                 default: retbuf[2] = 4; break;
                    276:                }
                    277:                retbuf[7] = 14;
                    278:                retbuf[12] = nLastError;
                    279:                retbuf[19] = nLastBlockAddr >> 16;
                    280:                retbuf[20] = nLastBlockAddr >> 8;
                    281:                retbuf[21] = nLastBlockAddr;
                    282:        }
                    283: 
                    284:        /*
                    285:        fprintf(stderr,"*** Requested sense packet:\n");
                    286:        int i;
                    287:        for (i = 0; i<nRetLen; i++) fprintf(stderr,"%2x ",retbuf[i]);
                    288:        fprintf(stderr,"\n");
                    289:        */
                    290: 
1.1.1.13  root      291:        if (STMemory_SafeCopy(nDmaAddr, retbuf, nRetLen, "HDC request sense"))
                    292:                HDCCommand.returnCode = HD_STATUS_OK;
                    293:        else
                    294:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    295: 
1.1.1.12  root      296:        FDC_WriteDMAAddress(nDmaAddr + nRetLen);
1.1.1.7   root      297: 
1.1.1.11  root      298:        FDC_SetDMAStatus(false);            /* no DMA error */
1.1.1.7   root      299:        FDC_AcknowledgeInterrupt();
                    300:        //FDCSectorCountRegister = 0;
                    301: }
                    302: 
                    303: 
                    304: /*---------------------------------------------------------------------*/
1.1.1.8   root      305: /**
                    306:  * Mode sense - Get parameters from disk.
                    307:  * (Just enough to make the HDX tool from AHDI 5.0 happy)
                    308:  */
1.1.1.7   root      309: static void HDC_Cmd_ModeSense(void)
                    310: {
                    311:        Uint32 nDmaAddr;
                    312: 
                    313: #ifdef HDC_VERBOSE
                    314:        fprintf(stderr,"HDC: Mode Sense.\n");
                    315: #endif
                    316: 
1.1.1.14! root      317:        nDmaAddr = FDC_GetDMAAddress();
1.1.1.7   root      318: 
1.1.1.13  root      319:        if (!STMemory_ValidArea(nDmaAddr, 16))
                    320:        {
                    321:                Log_Printf(LOG_WARN, "HCD mode sense uses invalid RAM range 0x%x+%i\n", nDmaAddr, 16);
                    322:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    323:        }
1.1.1.14! root      324:        else if (HDCCommand.command[2] == 0 && HDC_GetCount() == 0x10)
1.1.1.7   root      325:        {
                    326:                size_t blocks;
                    327:                blocks = File_Length(ConfigureParams.HardDisk.szHardDiskImage) / 512;
                    328: 
                    329:                STRam[nDmaAddr+0] = 0;
                    330:                STRam[nDmaAddr+1] = 0;
                    331:                STRam[nDmaAddr+2] = 0;
                    332:                STRam[nDmaAddr+3] = 8;
                    333:                STRam[nDmaAddr+4] = 0;
                    334: 
                    335:                STRam[nDmaAddr+5] = blocks >> 16;  // Number of blocks, high (?)
                    336:                STRam[nDmaAddr+6] = blocks >> 8;   // Number of blocks, med (?)
                    337:                STRam[nDmaAddr+7] = blocks;        // Number of blocks, low (?)
                    338: 
                    339:                STRam[nDmaAddr+8] = 0;
                    340: 
                    341:                STRam[nDmaAddr+9] = 0;      // Block size in bytes, high
                    342:                STRam[nDmaAddr+10] = 2;     // Block size in bytes, med
                    343:                STRam[nDmaAddr+11] = 0;     // Block size in bytes, low
                    344: 
                    345:                STRam[nDmaAddr+12] = 0;
                    346:                STRam[nDmaAddr+13] = 0;
                    347:                STRam[nDmaAddr+14] = 0;
                    348:                STRam[nDmaAddr+15] = 0;
                    349: 
1.1.1.12  root      350:                FDC_WriteDMAAddress(nDmaAddr + 16);
                    351: 
1.1.1.7   root      352:                HDCCommand.returnCode = HD_STATUS_OK;
                    353:                nLastError = HD_REQSENS_OK;
                    354:        }
                    355:        else
                    356:        {
1.1.1.9   root      357:                Log_Printf(LOG_TODO, "HDC: Unsupported MODE SENSE command\n");
1.1.1.7   root      358:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    359:                nLastError = HD_REQSENS_INVARG;
                    360:        }
                    361: 
1.1.1.11  root      362:        FDC_SetDMAStatus(false);            /* no DMA error */
1.1.1.7   root      363:        FDC_AcknowledgeInterrupt();
1.1.1.11  root      364:        bSetLastBlockAddr = false;
1.1.1.7   root      365:        //FDCSectorCountRegister = 0;
                    366: }
                    367: 
                    368: 
                    369: /*---------------------------------------------------------------------*/
1.1.1.8   root      370: /**
                    371:  * Format drive.
                    372:  */
1.1.1.7   root      373: static void HDC_Cmd_FormatDrive(void)
                    374: {
                    375: #ifdef HDC_VERBOSE
                    376:        fprintf(stderr,"HDC: Format drive!\n");
                    377: #endif
                    378: 
                    379:        /* Should erase the whole image file here... */
                    380: 
1.1.1.11  root      381:        FDC_SetDMAStatus(false);            /* no DMA error */
1.1.1.7   root      382:        FDC_AcknowledgeInterrupt();
                    383:        HDCCommand.returnCode = HD_STATUS_OK;
                    384:        nLastError = HD_REQSENS_OK;
1.1.1.11  root      385:        bSetLastBlockAddr = false;
1.1.1.7   root      386:        //FDCSectorCountRegister = 0;
1.1       root      387: }
                    388: 
1.1.1.14! root      389: /*---------------------------------------------------------------------*/
        !           390: /**
        !           391:  * Read capacity of our disk.
        !           392:  */
        !           393: static void HDC_Cmd_ReadCapacity(void)
        !           394: {
        !           395:        Uint32 nDmaAddr = FDC_GetDMAAddress();
        !           396: 
        !           397: #ifdef HDC_VERBOSE
        !           398:        fprintf(stderr,"Reading 8 bytes capacity data to addr: 0x%x\n", nDmaAddr);
        !           399: #endif
        !           400: 
        !           401:        /* seek to the position */
        !           402:        if (STMemory_ValidArea(nDmaAddr, 8))
        !           403:        {
        !           404:                int nSectors = hdSize / 512;
        !           405:                STRam[nDmaAddr++] = (nSectors >> 24) & 0xFF;
        !           406:                STRam[nDmaAddr++] = (nSectors >> 16) & 0xFF;
        !           407:                STRam[nDmaAddr++] = (nSectors >> 8) & 0xFF;
        !           408:                STRam[nDmaAddr++] = (nSectors) & 0xFF;
        !           409:                STRam[nDmaAddr++] = 0x00;
        !           410:                STRam[nDmaAddr++] = 0x00;
        !           411:                STRam[nDmaAddr++] = 0x02;
        !           412:                STRam[nDmaAddr++] = 0x00;
        !           413: 
        !           414:                /* Update DMA counter */
        !           415:                FDC_WriteDMAAddress(nDmaAddr + 8);
        !           416: 
        !           417:                HDCCommand.returnCode = HD_STATUS_OK;
        !           418:                nLastError = HD_REQSENS_OK;
        !           419:        }
        !           420:        else
        !           421:        {
        !           422:                Log_Printf(LOG_WARN, "HDC capacity read uses invalid RAM range 0x%x+%i\n", nDmaAddr, 8);
        !           423:                HDCCommand.returnCode = HD_STATUS_ERROR;
        !           424:                nLastError = HD_REQSENS_NOSECTOR;
        !           425:        }
        !           426: 
        !           427:        FDC_SetDMAStatus(false);              /* no DMA error */
        !           428:        FDC_AcknowledgeInterrupt();
        !           429:        bSetLastBlockAddr = false;
        !           430:        //FDCSectorCountRegister = 0;
        !           431: }
        !           432: 
1.1.1.7   root      433: 
1.1       root      434: /*---------------------------------------------------------------------*/
1.1.1.8   root      435: /**
                    436:  * Write a sector off our disk - (seek implied)
                    437:  */
1.1.1.7   root      438: static void HDC_Cmd_WriteSector(void)
1.1       root      439: {
1.1.1.11  root      440:        int n = 0;
                    441: 
1.1.1.7   root      442:        nLastBlockAddr = HDC_GetOffset();
1.1       root      443: 
1.1.1.7   root      444:        /* seek to the position */
                    445:        if (fseek(hd_image_file, nLastBlockAddr, SEEK_SET) != 0)
                    446:        {
                    447:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    448:                nLastError = HD_REQSENS_INVADDR;
                    449:        }
                    450:        else
                    451:        {
                    452:                /* write - if allowed */
1.1.1.14! root      453:                Uint32 nDmaAddr = FDC_GetDMAAddress();
1.1       root      454: #ifndef DISALLOW_HDC_WRITE
1.1.1.14! root      455:                if (STMemory_ValidArea(nDmaAddr, 512*HDC_GetCount()))
1.1.1.13  root      456:                {
                    457:                        n = fwrite(&STRam[nDmaAddr], 512,
1.1.1.14! root      458:                                   HDC_GetCount(), hd_image_file);
1.1.1.13  root      459:                }
                    460:                else
                    461:                {
                    462:                        Log_Printf(LOG_WARN, "HDC sector write uses invalid RAM range 0x%x+%i\n",
1.1.1.14! root      463:                                   nDmaAddr, 512*HDC_GetCount());
1.1.1.13  root      464:                }
1.1       root      465: #endif
1.1.1.14! root      466:                if (n == HDC_GetCount())
1.1.1.11  root      467:                {
                    468:                        HDCCommand.returnCode = HD_STATUS_OK;
                    469:                        nLastError = HD_REQSENS_OK;
                    470:                }
                    471:                else
                    472:                {
                    473:                        HDCCommand.returnCode = HD_STATUS_ERROR;
                    474:                        nLastError = HD_REQSENS_WRITEERR;
                    475:                }
                    476: 
1.1.1.9   root      477:                /* Update DMA counter */
1.1.1.13  root      478:                FDC_WriteDMAAddress(nDmaAddr + 512*n);
1.1.1.7   root      479:        }
1.1       root      480: 
1.1.1.11  root      481:        FDC_SetDMAStatus(false);              /* no DMA error */
1.1.1.7   root      482:        FDC_AcknowledgeInterrupt();
1.1.1.11  root      483:        bSetLastBlockAddr = true;
1.1.1.7   root      484:        //FDCSectorCountRegister = 0;
1.1       root      485: }
                    486: 
1.1.1.7   root      487: 
1.1       root      488: /*---------------------------------------------------------------------*/
1.1.1.8   root      489: /**
                    490:  * Read a sector off our disk - (implied seek)
                    491:  */
1.1.1.7   root      492: static void HDC_Cmd_ReadSector(void)
1.1       root      493: {
1.1.1.11  root      494:        int n;
                    495: 
1.1.1.7   root      496:        nLastBlockAddr = HDC_GetOffset();
1.1       root      497: 
                    498: #ifdef HDC_VERBOSE
1.1.1.7   root      499:        fprintf(stderr,"Reading %i sectors from 0x%x to addr: 0x%x\n",
1.1.1.14! root      500:                HDC_GetCount(), nLastBlockAddr, FDC_ReadDMAAddress());
1.1       root      501: #endif
                    502: 
1.1.1.7   root      503:        /* seek to the position */
                    504:        if (fseek(hd_image_file, nLastBlockAddr, SEEK_SET) != 0)
                    505:        {
                    506:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    507:                nLastError = HD_REQSENS_INVADDR;
                    508:        }
                    509:        else
                    510:        {
1.1.1.14! root      511:                Uint32 nDmaAddr = FDC_GetDMAAddress();
        !           512:                if (STMemory_ValidArea(nDmaAddr, 512*HDC_GetCount()))
1.1.1.13  root      513:                {
                    514:                        n = fread(&STRam[nDmaAddr], 512,
1.1.1.14! root      515:                                   HDC_GetCount(), hd_image_file);
1.1.1.13  root      516:                }
                    517:                else
                    518:                {
                    519:                        Log_Printf(LOG_WARN, "HDC sector read uses invalid RAM range 0x%x+%i\n",
1.1.1.14! root      520:                                   nDmaAddr, 512*HDC_GetCount());
1.1.1.13  root      521:                        n = 0;
                    522:                }
1.1.1.14! root      523:                if (n == HDC_GetCount())
1.1.1.11  root      524:                {
                    525:                        HDCCommand.returnCode = HD_STATUS_OK;
                    526:                        nLastError = HD_REQSENS_OK;
                    527:                }
                    528:                else
                    529:                {
                    530:                        HDCCommand.returnCode = HD_STATUS_ERROR;
                    531:                        nLastError = HD_REQSENS_NOSECTOR;
                    532:                }
1.1.1.9   root      533: 
                    534:                /* Update DMA counter */
1.1.1.13  root      535:                FDC_WriteDMAAddress(nDmaAddr + 512*n);
1.1.1.7   root      536:        }
1.1       root      537: 
1.1.1.11  root      538:        FDC_SetDMAStatus(false);              /* no DMA error */
1.1.1.7   root      539:        FDC_AcknowledgeInterrupt();
1.1.1.11  root      540:        bSetLastBlockAddr = true;
1.1.1.7   root      541:        //FDCSectorCountRegister = 0;
1.1       root      542: }
                    543: 
1.1.1.7   root      544: 
1.1       root      545: /*---------------------------------------------------------------------*/
1.1.1.8   root      546: /**
1.1.1.12  root      547:  * Test unit ready
                    548:  */
                    549: static void HDC_Cmd_TestUnitReady(void)
                    550: {
                    551:        FDC_SetDMAStatus(false);            /* no DMA error */
                    552:        FDC_AcknowledgeInterrupt();
                    553:        HDCCommand.returnCode = HD_STATUS_OK;
                    554: }
                    555: 
                    556: 
                    557: /*---------------------------------------------------------------------*/
                    558: /**
1.1.1.8   root      559:  * Emulation routine for HDC command packets.
                    560:  */
1.1.1.12  root      561: static void HDC_EmulateCommandPacket(void)
1.1       root      562: {
                    563: 
1.1.1.14! root      564:        switch(HDCCommand.opcode)
1.1.1.7   root      565:        {
1.1       root      566: 
1.1.1.12  root      567:         case HD_TEST_UNIT_RDY:
                    568:                HDC_Cmd_TestUnitReady();
                    569:                break;
                    570: 
1.1.1.14! root      571:        case HD_READ_CAPACITY1:
        !           572:                HDC_Cmd_ReadCapacity();
        !           573:                break;
        !           574: 
1.1.1.7   root      575:         case HD_READ_SECTOR:
1.1.1.14! root      576:         case HD_READ_SECTOR1:
1.1.1.7   root      577:                HDC_Cmd_ReadSector();
                    578:                break;
1.1.1.14! root      579: 
1.1.1.7   root      580:         case HD_WRITE_SECTOR:
1.1.1.14! root      581:         case HD_WRITE_SECTOR1:
1.1.1.7   root      582:                HDC_Cmd_WriteSector();
                    583:                break;
                    584: 
                    585:         case HD_INQUIRY:
                    586:                HDC_Cmd_Inquiry();
                    587:                break;
                    588: 
                    589:         case HD_SEEK:
                    590:                HDC_Cmd_Seek();
                    591:                break;
                    592: 
                    593:         case HD_SHIP:
                    594:                HDCCommand.returnCode = 0xFF;
                    595:                FDC_AcknowledgeInterrupt();
                    596:                break;
                    597: 
                    598:         case HD_REQ_SENSE:
                    599:                HDC_Cmd_RequestSense();
                    600:                break;
                    601: 
                    602:         case HD_MODESELECT:
1.1.1.9   root      603:                Log_Printf(LOG_TODO, "HDC: MODE SELECT call not implemented yet.\n");
1.1.1.7   root      604:                HDCCommand.returnCode = HD_STATUS_OK;
                    605:                nLastError = HD_REQSENS_OK;
1.1.1.11  root      606:                bSetLastBlockAddr = false;
                    607:                FDC_SetDMAStatus(false);
1.1.1.7   root      608:                FDC_AcknowledgeInterrupt();
                    609:                break;
                    610: 
                    611:         case HD_MODESENSE:
                    612:                HDC_Cmd_ModeSense();
                    613:                break;
                    614: 
                    615:         case HD_FORMAT_DRIVE:
                    616:                HDC_Cmd_FormatDrive();
                    617:                break;
                    618: 
                    619:         /* as of yet unsupported commands */
                    620:         case HD_VERIFY_TRACK:
                    621:         case HD_FORMAT_TRACK:
                    622:         case HD_CORRECTION:
                    623: 
                    624:         default:
                    625:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    626:                nLastError = HD_REQSENS_OPCODE;
1.1.1.11  root      627:                bSetLastBlockAddr = false;
1.1.1.7   root      628:                FDC_AcknowledgeInterrupt();
                    629:                break;
                    630:        }
1.1.1.9   root      631: 
                    632:        /* Update the led each time a command is processed */
                    633:        Statusbar_EnableHDLed();
1.1       root      634: }
                    635: 
1.1.1.7   root      636: 
1.1       root      637: /*---------------------------------------------------------------------*/
1.1.1.8   root      638: /**
                    639:  * Debug routine for HDC command packets.
                    640:  */
1.1.1.7   root      641: #ifdef HDC_REALLY_VERBOSE
1.1.1.12  root      642: static void HDC_DebugCommandPacket(FILE *hdlogFile)
1.1       root      643: {
1.1.1.7   root      644:        int opcode;
                    645:        static const char *psComNames[] =
                    646:        {
1.1.1.14! root      647:                "TEST UNIT READY",         // 0x00
        !           648:                "REZERO",                  // 0x01
        !           649:                "???",                     // 0x02
        !           650:                "REQUEST SENSE",           // 0x03
        !           651:                "FORMAT DRIVE",            // 0x04
        !           652:                "VERIFY TRACK (?)",        // 0x05
        !           653:                "FORMAT TRACK (?)",        // 0x06
        !           654:                "REASSIGN BLOCK",          // 0x07
        !           655:                "READ SECTOR(S)",          // 0x08
        !           656:                "???",                     // 0x09
        !           657:                "WRITE SECTOR(S)",         // 0x0A
        !           658:                "SEEK",                    // 0x0B
        !           659:                "???",                     // 0x0C
        !           660:                "CORRECTION",              // 0x0D
        !           661:                "???",                     // 0x0E
        !           662:                "TRANSLATE",               // 0x0F
        !           663:                "SET ERROR THRESHOLD",     // 0x10
        !           664:                "USAGE COUNTERS",          // 0x11
        !           665:                "INQUIRY",                 // 0x12
        !           666:                "WRITE DATA BUFFER",       // 0x13
        !           667:                "READ DATA BUFFER",        // 0x14
        !           668:                "MODE SELECT",             // 0x15
        !           669:                "???",                     // 0x16
        !           670:                "???",                     // 0x17
        !           671:                "EXTENDED READ",           // 0x18
        !           672:                "READ TOC",                // 0x19
        !           673:                "MODE SENSE",              // 0x1A
        !           674:                "SHIP",                    // 0x1B
        !           675:                "RECEIVE DIAGNOSTICS",     // 0x1C
        !           676:                "SEND DIAGNOSTICS",        // 0x1D
        !           677:                "???",                     // 0x1E
        !           678:                "SET TARGET (EXTENDED)",   // 0x1F
        !           679:                "???",                     // 0x20
        !           680:                "???",                     // 0x21
        !           681:                "???",                     // 0x22
        !           682:                "???",                     // 0x23
        !           683:                "???",                     // 0x24
        !           684:                "READ CAPACITY",           // 0x25
        !           685:                "???",                     // 0x26
        !           686:                "???",                     // 0x27
        !           687:                "READ SECTOR(S)",          // 0x28
        !           688:                "???",                     // 0x29
        !           689:                "WRITE SECTOR(S)",         // 0x2A
1.1.1.7   root      690:        };
                    691: 
1.1.1.14! root      692:        opcode = HDCCommand.opcode;
1.1.1.7   root      693: 
                    694:        fprintf(hdlogFile,"----\n");
                    695: 
                    696:        if (opcode >= 0 && opcode <= (int)(sizeof(psComNames)/sizeof(psComNames[0])))
                    697:        {
                    698:                fprintf(hdlogFile, "HDC opcode 0x%x : %s\n",opcode,psComNames[opcode]);
                    699:        }
                    700:        else
                    701:        {
                    702:                fprintf(hdlogFile, "Unknown HDC opcode!! Value = 0x%x\n", opcode);
                    703:        }
                    704: 
1.1.1.14! root      705:        fprintf(hdlogFile, "Target: %i\n", HDCCommand.target);
        !           706:        fprintf(hdlogFile, "Device: %i\n", HDC_GetDevice());
1.1.1.12  root      707:        fprintf(hdlogFile, "LBA: 0x%lx\n", HDC_GetOffset()/512);
1.1.1.7   root      708: 
1.1.1.14! root      709:        fprintf(hdlogFile, "Sector count: 0x%x\n", HDC_GetCount());
1.1.1.7   root      710:        fprintf(hdlogFile, "HDC sector count: 0x%x\n", HDCSectorCount);
                    711:        //fprintf(hdlogFile, "FDC sector count: 0x%x\n", FDCSectorCountRegister);
1.1.1.14! root      712:        fprintf(hdlogFile, "Control byte: 0x%x\n", HDC_GetControl());
1.1       root      713: }
1.1.1.7   root      714: #endif
                    715: 
1.1       root      716: 
                    717: /*---------------------------------------------------------------------*/
1.1.1.8   root      718: /**
                    719:  * Print data about the hard drive image
                    720:  */
1.1.1.4   root      721: static void HDC_GetInfo(void)
1.1       root      722: {
1.1.1.7   root      723: /* Partition table contains hd size + 4 partition entries
                    724:  * (composed of flag byte, 3 char ID, start offset and size),
                    725:  * this is followed by bad sector list + count and the root sector checksum.
                    726:  * Before this there's the boot code and with ICD hd driver additional 8
                    727:  * partition entries (at offset 0x156).
                    728:  */
                    729: #define HD_PARTITIONTABLE_SIZE (4+4*12)
                    730: #define HD_PARTITIONTABLE_OFFSET 0x1C2
                    731:        long offset;
                    732:        unsigned char hdinfo[HD_PARTITIONTABLE_SIZE];
                    733:        int i;
1.1       root      734: 
1.1.1.7   root      735:        nPartitions = 0;
                    736:        if (hd_image_file == NULL)
                    737:                return;
                    738:        offset = ftell(hd_image_file);
                    739: 
                    740:        fseek(hd_image_file, HD_PARTITIONTABLE_OFFSET, 0);
1.1.1.11  root      741:        if (fread(hdinfo, HD_PARTITIONTABLE_SIZE, 1, hd_image_file) != 1)
                    742:        {
                    743:                perror("HDC_GetInfo");
                    744:                return;
                    745:        }
1.1       root      746: 
1.1.1.14! root      747:        hdSize = HDC_ReadInt32(hdinfo, 0);
1.1.1.7   root      748: 
1.1.1.14! root      749: #ifdef HDC_VERBOSE
        !           750:        fprintf(stderr, "Total disk size %li Mb\n", hdSize>>11);
1.1.1.7   root      751:        /* flags for each partition entry are zero if they are not valid */
                    752:        fprintf(stderr, "Partition 0 exists?: %s\n", (hdinfo[4] != 0)?"Yes":"No");
                    753:        fprintf(stderr, "Partition 1 exists?: %s\n", (hdinfo[4+12] != 0)?"Yes":"No");
                    754:        fprintf(stderr, "Partition 2 exists?: %s\n", (hdinfo[4+24] != 0)?"Yes":"No");
                    755:        fprintf(stderr, "Partition 3 exists?: %s\n", (hdinfo[4+36] != 0)?"Yes":"No");
1.1       root      756: #endif
                    757: 
1.1.1.7   root      758:        for(i=0;i<4;i++)
                    759:                if(hdinfo[4 + 12*i])
                    760:                        nPartitions++;
1.1       root      761: 
1.1.1.7   root      762:        fseek(hd_image_file, offset, 0);
1.1       root      763: }
                    764: 
1.1.1.7   root      765: 
1.1       root      766: /*---------------------------------------------------------------------*/
1.1.1.8   root      767: /**
                    768:  * Open the disk image file, set partitions.
1.1       root      769:  */
1.1.1.12  root      770: bool HDC_Init(void)
1.1       root      771: {
1.1.1.12  root      772:        char *filename;
1.1.1.11  root      773:        bAcsiEmuOn = false;
1.1       root      774: 
1.1.1.12  root      775:        if (!ConfigureParams.HardDisk.bUseHardDiskImage)
                    776:                return false;
                    777:        filename = ConfigureParams.HardDisk.szHardDiskImage;
                    778: 
1.1.1.7   root      779:        /* Sanity check - is file length a multiple of 512? */
                    780:        if (File_Length(filename) & 0x1ff)
                    781:        {
                    782:                Log_Printf(LOG_ERROR, "HD file '%s' has strange size!\n", filename);
1.1.1.11  root      783:                return false;
1.1.1.7   root      784:        }
1.1.1.3   root      785: 
1.1.1.7   root      786:        if ((hd_image_file = fopen(filename, "rb+")) == NULL)
                    787:        {
                    788:                Log_Printf(LOG_ERROR, "Can not open HD file '%s'!\n", filename);
1.1.1.11  root      789:                return false;
1.1.1.7   root      790:        }
                    791: 
                    792:        HDC_GetInfo();
                    793: 
                    794:        /* set number of partitions */
                    795:        nNumDrives += nPartitions;
                    796: 
1.1.1.11  root      797:        bAcsiEmuOn = true;
1.1.1.14! root      798:        HDCCommand.readCount = 0;
1.1.1.12  root      799:        HDCCommand.byteCount = 0;
1.1.1.7   root      800: 
1.1.1.12  root      801:        printf("Hard drive image %s mounted.\n", filename);
1.1.1.11  root      802:        return true;
1.1       root      803: }
1.1.1.3   root      804: 
1.1.1.7   root      805: 
1.1       root      806: /*---------------------------------------------------------------------*/
1.1.1.8   root      807: /**
                    808:  * HDC_UnInit - close image file
                    809:  *
1.1       root      810:  */
1.1.1.4   root      811: void HDC_UnInit(void)
1.1       root      812: {
1.1.1.7   root      813:        if (!bAcsiEmuOn)
                    814:                return;
                    815: 
                    816:        fclose(hd_image_file);
                    817:        hd_image_file = NULL;
                    818: 
                    819:        nNumDrives -= nPartitions;
                    820:        nPartitions = 0;
1.1.1.11  root      821:        bAcsiEmuOn = false;
1.1       root      822: }
                    823: 
1.1.1.7   root      824: 
1.1       root      825: /*---------------------------------------------------------------------*/
1.1.1.8   root      826: /**
1.1.1.14! root      827:  * Reset command status.
        !           828:  */
        !           829: void HDC_ResetCommandStatus(void)
        !           830: {
        !           831:        /*HDCCommand.byteCount = 0;*/  /* Not done on real ST? */
        !           832:        HDCCommand.returnCode = 0;
        !           833: }
        !           834: 
        !           835: 
        !           836: /**
        !           837:  * Get command status.
        !           838:  */
        !           839: short int HDC_GetCommandStatus(void)
        !           840: {
        !           841:        return HDCCommand.returnCode;
        !           842: }
        !           843: 
        !           844: 
        !           845: /*---------------------------------------------------------------------*/
        !           846: /**
        !           847:  * Get sector count.
        !           848:  */
        !           849: short int HDC_GetSectorCount(void)
        !           850: {
        !           851:        return HDCSectorCount;
        !           852: }
        !           853: 
        !           854: 
        !           855: /*---------------------------------------------------------------------*/
        !           856: /**
1.1.1.8   root      857:  * Process HDC command packets, called when bytes are 
                    858:  * written to $FFFF8606 and the HDC (not the FDC) is selected.
                    859:  */
1.1.1.4   root      860: void HDC_WriteCommandPacket(void)
1.1       root      861: {
1.1.1.7   root      862:        /* is HDC emulation enabled? */
                    863:        if (!bAcsiEmuOn)
                    864:                return;
                    865: 
1.1.1.14! root      866:        /* command byte sent */
        !           867:        unsigned char b = IoMem_ReadByte(0xff8605);
        !           868: 
        !           869:        /* Extract target and extended mode early, read acsi opcode */
        !           870:        if (HDCCommand.readCount == 0)
        !           871:        {
        !           872:                HDCCommand.target = ((b & 0xE0) >> 5);
        !           873:                HDCCommand.opcode = (b & 0x1F);
        !           874:                HDCCommand.extended = (HDCCommand.opcode == 0x1F);
        !           875:        }
        !           876:        /* In extended mode, the scsi opcode is at position 1 */
        !           877:        else if (HDCCommand.extended && HDCCommand.readCount == 1)
        !           878:        {
        !           879:                HDCCommand.opcode = (b & 0xFF);
        !           880:        }
1.1.1.12  root      881: 
                    882:        /* We only support one target with ID 0 */
1.1.1.14! root      883:        if (HDCCommand.target != 0)
1.1.1.12  root      884:        {
                    885:                //FDC_SetDMAStatus(true);
                    886:                //FDC_AcknowledgeInterrupt();
                    887:                //FDCSectorCountRegister = 0;
                    888:                /* If there's no controller, the interrupt line stays high */
                    889:                HDCCommand.returnCode = HD_STATUS_ERROR;
                    890:                MFP_GPIP |= 0x20;
                    891:                return;
                    892:        }
                    893: 
1.1.1.14! root      894:        /* Successfully received one byte, so increase the byte-count, but in extended mode skip the first byte */
        !           895:        if (!HDCCommand.extended || HDCCommand.readCount != 0)
        !           896:        {
        !           897:                HDCCommand.command[HDCCommand.byteCount++] = b;
        !           898:        }
        !           899:        ++HDCCommand.readCount;
1.1.1.7   root      900: 
1.1.1.14! root      901:        /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */
        !           902:        if ((HDCCommand.opcode < 0x20 && HDCCommand.byteCount >= 6) ||
        !           903:                (HDCCommand.opcode < 0x40 && HDCCommand.byteCount >= 10))
1.1.1.7   root      904:        {
1.1       root      905: #ifdef HDC_REALLY_VERBOSE
1.1.1.7   root      906:                HDC_DebugCommandPacket(stderr);
1.1       root      907: #endif
1.1.1.7   root      908:                /* If it's aimed for our drive, emulate it! */
1.1.1.14! root      909:                if (HDC_GetDevice() == 0)
1.1.1.7   root      910:                {
1.1.1.12  root      911:                        HDC_EmulateCommandPacket();
1.1.1.7   root      912:                }
                    913:                else
                    914:                {
1.1.1.12  root      915:                        Log_Printf(LOG_WARN, "HDC: Access to non-existing drive.\n");
1.1.1.7   root      916:                        HDCCommand.returnCode = HD_STATUS_ERROR;
                    917:                }
                    918: 
1.1.1.14! root      919:                HDCCommand.readCount = 0;
1.1.1.7   root      920:                HDCCommand.byteCount = 0;
                    921:        }
                    922:        else
                    923:        {
1.1.1.12  root      924:                FDC_AcknowledgeInterrupt();
                    925:                FDC_SetDMAStatus(false);
                    926:                HDCCommand.returnCode = HD_STATUS_OK;
1.1.1.7   root      927:        }
1.1       root      928: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.