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

1.1       root        1: /*
1.1.1.3   root        2:   Hatari - hdc.c
1.1       root        3: 
1.1.1.15  root        4:   This file is distributed under the GNU General Public License, version 2
                      5:   or at 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: 
1.1.1.17! root       11: #include <errno.h>
        !            12: 
1.1       root       13: #include "main.h"
1.1.1.3   root       14: #include "configuration.h"
1.1.1.6   root       15: #include "debugui.h"
1.1.1.7   root       16: #include "file.h"
1.1       root       17: #include "fdc.h"
                     18: #include "hdc.h"
1.1.1.14  root       19: #include "ioMem.h"
1.1.1.7   root       20: #include "log.h"
1.1       root       21: #include "memorySnapShot.h"
                     22: #include "mfp.h"
                     23: #include "stMemory.h"
1.1.1.6   root       24: #include "tos.h"
1.1.1.9   root       25: #include "statusbar.h"
                     26: 
1.1       root       27: 
                     28: /*
                     29:   ACSI emulation: 
                     30:   ACSI commands are six byte-packets sent to the
                     31:   hard drive controller (which is on the HD unit, not in the ST)
                     32: 
                     33:   While the hard drive is busy, DRQ is high, polling the DRQ during
                     34:   operation interrupts the current operation. The DRQ status can
                     35:   be polled non-destructively in GPIP.
1.1.1.7   root       36: 
1.1.1.15  root       37:   (For simplicity, the operation is finished immediately,
1.1       root       38:   this is a potential bug, but I doubt it is significant,
                     39:   we just appear to have a very fast hard drive.)
                     40: 
                     41:   The ACSI command set is a subset of the SCSI standard.
                     42:   (for details, see the X3T9.2 SCSI draft documents
                     43:   from 1985, for an example of writing ACSI commands,
                     44:   see the TOS DMA boot code) 
                     45: */
                     46: 
1.1.1.7   root       47: // #define DISALLOW_HDC_WRITE
                     48: // #define HDC_VERBOSE           /* display operations */
1.1.1.17! root       49: #define WITH_NCR5380 0
1.1       root       50: 
1.1.1.14  root       51: #define HDC_ReadInt16(a, i) (((unsigned) a[i] << 8) | a[i + 1])
                     52: #define HDC_ReadInt24(a, i) (((unsigned) a[i] << 16) | ((unsigned) a[i + 1] << 8) | a[i + 2])
                     53: #define HDC_ReadInt32(a, i) (((unsigned) a[i] << 24) | ((unsigned) a[i + 1] << 16) | ((unsigned) a[i + 2] << 8) | a[i + 3])
                     54: 
                     55: /**
1.1.1.16  root       56:  * Information about a ACSI/SCSI drive
1.1.1.14  root       57:  */
                     58: typedef struct {
1.1.1.16  root       59:        bool enabled;
                     60:        FILE *image_file;
                     61:        Uint32 nLastBlockAddr;      /* The specified sector number */
                     62:        bool bSetLastBlockAddr;
                     63:        Uint8 nLastError;
                     64:        unsigned long hdSize;       /* Size of the hard disk in sectors */
                     65: } SCSI_DEV;
                     66: 
                     67: /**
                     68:  * Status of the ACSI/SCSI bus/controller including the current command block.
                     69:  */
                     70: typedef struct {
                     71:        int target;
                     72:        int byteCount;              /* number of command bytes received */
                     73:        Uint8 command[16];
                     74:        Uint8 opcode;
                     75:        bool bDmaError;
                     76:        short int returnCode;       /* return code from the HDC operation */
1.1.1.17! root       77:        Uint8 *resp;                /* Response buffer */
        !            78:        int respbufsize;
        !            79:        int respcnt;
        !            80:        int respidx;
1.1.1.16  root       81:        SCSI_DEV devs[8];
                     82: } SCSI_CTRLR;
1.1.1.14  root       83: 
1.1       root       84: /* HDC globals */
1.1.1.17! root       85: static SCSI_CTRLR AcsiBus;
        !            86: int nAcsiPartitions = 0;
1.1.1.11  root       87: bool bAcsiEmuOn = false;
1.1.1.7   root       88: 
1.1.1.17! root       89: #if WITH_NCR5380
        !            90: static SCSI_CTRLR ScsiBus;
        !            91: #endif
1.1       root       92: 
                     93: /* Our dummy INQUIRY response data */
1.1.1.7   root       94: static unsigned char inquiry_bytes[] =
1.1       root       95: {
1.1.1.7   root       96:        0,                /* device type 0 = direct access device */
                     97:        0,                /* device type qualifier (nonremovable) */
1.1.1.16  root       98:        1,                /* ACSI/SCSI version */
1.1.1.7   root       99:        0,                /* reserved */
1.1.1.16  root      100:        31,               /* length of the following data */
                    101:        0, 0, 0,          /* Vendor specific data */
                    102:        'H','a','t','a','r','i',' ',' ',    /* Vendor ID */
                    103:        'E','m','u','l','a','t','e','d',    /* Product ID 1 */
                    104:        'H','a','r','d','d','i','s','k',    /* Product ID 2 */
                    105:        '0','1','8','0',                    /* Revision */
1.1       root      106: };
                    107: 
1.1.1.7   root      108: 
1.1       root      109: /*---------------------------------------------------------------------*/
1.1.1.8   root      110: /**
1.1.1.16  root      111:  * Return the LUN (logical unit number) specified in the current
                    112:  * ACSI/SCSI command block.
1.1.1.14  root      113:  */
1.1.1.16  root      114: static unsigned char HDC_GetLUN(SCSI_CTRLR *ctr)
1.1.1.14  root      115: {
1.1.1.16  root      116:        return (ctr->command[1] & 0xE0) >> 5;
1.1.1.14  root      117: }
                    118: 
                    119: /**
1.1.1.16  root      120:  * Return the start sector (logical block address) specified in the
                    121:  * current ACSI/SCSI command block.
1.1.1.8   root      122:  */
1.1.1.16  root      123: static unsigned long HDC_GetLBA(SCSI_CTRLR *ctr)
1.1.1.4   root      124: {
1.1.1.14  root      125:        /* offset = logical block address * 512 */
1.1.1.16  root      126:        if (ctr->opcode < 0x20)                         /* Class 0? */
                    127:                return HDC_ReadInt24(ctr->command, 1) & 0x1FFFFF;
                    128:        else
                    129:                return HDC_ReadInt32(ctr->command, 2);  /* Class 1 */
1.1.1.14  root      130: }
1.1       root      131: 
1.1.1.14  root      132: /**
                    133:  * Return the count specified in the current ACSI command block.
                    134:  */
1.1.1.16  root      135: static int HDC_GetCount(SCSI_CTRLR *ctr)
1.1.1.14  root      136: {
1.1.1.16  root      137:        if (ctr->opcode < 0x20)
                    138:                return ctr->command[4];                 /* Class 0 */
                    139:        else
                    140:                return HDC_ReadInt16(ctr->command, 7);  /* Class 1 */
1.1.1.14  root      141: }
1.1.1.7   root      142: 
1.1.1.14  root      143: /**
                    144:  * Return the control byte specified in the current ACSI command block.
                    145:  */
1.1.1.16  root      146: static inline Uint8 HDC_GetControl(SCSI_CTRLR *ctr)
1.1.1.14  root      147: {
1.1.1.16  root      148:        if (ctr->opcode < 0x20)
                    149:                return ctr->command[5];                 /* Class 0 */
                    150:        else
                    151:                return ctr->command[9];                 /* Class 1 */
                    152: }
                    153: 
                    154: /**
1.1.1.17! root      155:  * Get pointer to response buffer, set up size indicator - and allocate
        !           156:  * a new buffer if it is not big enough
        !           157:  */
        !           158: static Uint8 *HDC_PrepRespBuf(SCSI_CTRLR *ctr, int size)
        !           159: {
        !           160:        ctr->respcnt = size;
        !           161:        ctr->respidx = 0;
        !           162: 
        !           163:        if (size > ctr->respbufsize)
        !           164:        {
        !           165:                ctr->respbufsize = size;
        !           166:                ctr->resp = realloc(ctr->resp, size);
        !           167:        }
        !           168: 
        !           169:        return ctr->resp;
        !           170: }
        !           171: 
        !           172: /**
1.1.1.16  root      173:  * Get info string for SCSI/ACSI command packets.
                    174:  */
                    175: static inline char *HDC_CmdInfoStr(SCSI_CTRLR *ctr)
                    176: {
                    177:        static char str[80];
                    178: 
                    179:        snprintf(str, sizeof(str), "t=%i, lun=%i, opc=%i, cnt=0x%x, ctrl=0x%x",
                    180:                 ctr->target, HDC_GetLUN(ctr), ctr->opcode, HDC_GetCount(ctr),
                    181:                 HDC_GetControl(ctr));
                    182: 
                    183:        return str;
1.1       root      184: }
                    185: 
1.1.1.7   root      186: 
1.1.1.8   root      187: /**
                    188:  * Seek - move to a sector
                    189:  */
1.1.1.16  root      190: static void HDC_Cmd_Seek(SCSI_CTRLR *ctr)
1.1       root      191: {
1.1.1.16  root      192:        SCSI_DEV *dev = &ctr->devs[ctr->target];
                    193: 
                    194:        dev->nLastBlockAddr = HDC_GetLBA(ctr);
                    195: 
1.1.1.17! root      196:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: SEEK (%s), LBA=%i",
1.1.1.16  root      197:                  HDC_CmdInfoStr(ctr), dev->nLastBlockAddr);
1.1       root      198: 
1.1.1.16  root      199:        if (dev->nLastBlockAddr < dev->hdSize &&
                    200:            fseeko(dev->image_file, (off_t)dev->nLastBlockAddr * 512L, SEEK_SET) == 0)
1.1.1.7   root      201:        {
1.1.1.17! root      202:                LOG_TRACE(TRACE_SCSI_CMD, " -> OK\n");
1.1.1.16  root      203:                ctr->returnCode = HD_STATUS_OK;
                    204:                dev->nLastError = HD_REQSENS_OK;
1.1.1.7   root      205:        }
                    206:        else
                    207:        {
1.1.1.17! root      208:                LOG_TRACE(TRACE_SCSI_CMD, " -> ERROR\n");
1.1.1.16  root      209:                ctr->returnCode = HD_STATUS_ERROR;
                    210:                dev->nLastError = HD_REQSENS_INVADDR;
1.1.1.7   root      211:        }
1.1       root      212: 
1.1.1.16  root      213:        dev->bSetLastBlockAddr = true;
1.1       root      214: }
                    215: 
1.1.1.7   root      216: 
1.1.1.8   root      217: /**
                    218:  * Inquiry - return some disk information
                    219:  */
1.1.1.16  root      220: static void HDC_Cmd_Inquiry(SCSI_CTRLR *ctr)
1.1.1.7   root      221: {
1.1.1.16  root      222:        SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root      223:        Uint8 *buf;
1.1.1.12  root      224:        int count;
                    225: 
1.1.1.16  root      226:        count = HDC_GetCount(ctr);
1.1.1.12  root      227: 
1.1.1.17! root      228:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: INQUIRY (%s)", HDC_CmdInfoStr(ctr));
        !           229: 
        !           230:        buf = HDC_PrepRespBuf(ctr, count);
        !           231:        memcpy(buf, inquiry_bytes, count);
1.1.1.7   root      232: 
1.1.1.12  root      233:        if (count > (int)sizeof(inquiry_bytes))
                    234:                count = sizeof(inquiry_bytes);
                    235: 
1.1.1.16  root      236:        /* For unsupported LUNs set the Peripheral Qualifier and the
                    237:         * Peripheral Device Type according to the SCSI standard */
1.1.1.17! root      238:        buf[0] = HDC_GetLUN(ctr) == 0 ? 0 : 0x7F;
1.1.1.16  root      239: 
1.1.1.17! root      240:        buf[4] = count - 5;
1.1.1.12  root      241: 
1.1.1.17! root      242:        ctr->returnCode = HD_STATUS_OK;
1.1.1.7   root      243: 
1.1.1.16  root      244:        dev->nLastError = HD_REQSENS_OK;
                    245:        dev->bSetLastBlockAddr = false;
1.1.1.7   root      246: }
                    247: 
                    248: 
1.1.1.8   root      249: /**
                    250:  * Request sense - return some disk information
                    251:  */
1.1.1.16  root      252: static void HDC_Cmd_RequestSense(SCSI_CTRLR *ctr)
1.1       root      253: {
1.1.1.16  root      254:        SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.7   root      255:        int nRetLen;
1.1.1.17! root      256:        Uint8 *retbuf;
1.1.1.7   root      257: 
1.1.1.16  root      258:        nRetLen = HDC_GetCount(ctr);
1.1.1.7   root      259: 
1.1.1.16  root      260:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: REQUEST SENSE (%s).\n", HDC_CmdInfoStr(ctr));
1.1.1.7   root      261: 
                    262:        if ((nRetLen < 4 && nRetLen != 0) || nRetLen > 22)
                    263:        {
1.1.1.9   root      264:                Log_Printf(LOG_WARN, "HDC: *** Strange REQUEST SENSE ***!\n");
1.1.1.7   root      265:        }
                    266: 
                    267:        /* Limit to sane length */
                    268:        if (nRetLen <= 0)
                    269:        {
                    270:                nRetLen = 4;
                    271:        }
                    272:        else if (nRetLen > 22)
                    273:        {
                    274:                nRetLen = 22;
                    275:        }
                    276: 
1.1.1.17! root      277:        retbuf = HDC_PrepRespBuf(ctr, nRetLen);
1.1.1.7   root      278:        memset(retbuf, 0, nRetLen);
                    279: 
                    280:        if (nRetLen <= 4)
                    281:        {
1.1.1.16  root      282:                retbuf[0] = dev->nLastError;
                    283:                if (dev->bSetLastBlockAddr)
1.1.1.7   root      284:                {
                    285:                        retbuf[0] |= 0x80;
1.1.1.16  root      286:                        retbuf[1] = dev->nLastBlockAddr >> 16;
                    287:                        retbuf[2] = dev->nLastBlockAddr >> 8;
                    288:                        retbuf[3] = dev->nLastBlockAddr;
1.1.1.7   root      289:                }
                    290:        }
                    291:        else
                    292:        {
                    293:                retbuf[0] = 0x70;
1.1.1.16  root      294:                if (dev->bSetLastBlockAddr)
1.1.1.7   root      295:                {
                    296:                        retbuf[0] |= 0x80;
1.1.1.16  root      297:                        retbuf[4] = dev->nLastBlockAddr >> 16;
                    298:                        retbuf[5] = dev->nLastBlockAddr >> 8;
                    299:                        retbuf[6] = dev->nLastBlockAddr;
1.1.1.7   root      300:                }
1.1.1.16  root      301:                switch (dev->nLastError)
1.1.1.7   root      302:                {
                    303:                 case HD_REQSENS_OK:  retbuf[2] = 0; break;
                    304:                 case HD_REQSENS_OPCODE:  retbuf[2] = 5; break;
                    305:                 case HD_REQSENS_INVADDR:  retbuf[2] = 5; break;
                    306:                 case HD_REQSENS_INVARG:  retbuf[2] = 5; break;
1.1.1.16  root      307:                 case HD_REQSENS_INVLUN:  retbuf[2] = 5; break;
1.1.1.7   root      308:                 default: retbuf[2] = 4; break;
                    309:                }
                    310:                retbuf[7] = 14;
1.1.1.16  root      311:                retbuf[12] = dev->nLastError;
                    312:                retbuf[19] = dev->nLastBlockAddr >> 16;
                    313:                retbuf[20] = dev->nLastBlockAddr >> 8;
                    314:                retbuf[21] = dev->nLastBlockAddr;
1.1.1.7   root      315:        }
                    316: 
                    317:        /*
                    318:        fprintf(stderr,"*** Requested sense packet:\n");
                    319:        int i;
                    320:        for (i = 0; i<nRetLen; i++) fprintf(stderr,"%2x ",retbuf[i]);
                    321:        fprintf(stderr,"\n");
                    322:        */
                    323: 
1.1.1.17! root      324:        ctr->returnCode = HD_STATUS_OK;
1.1.1.7   root      325: }
                    326: 
                    327: 
1.1.1.8   root      328: /**
                    329:  * Mode sense - Get parameters from disk.
                    330:  * (Just enough to make the HDX tool from AHDI 5.0 happy)
                    331:  */
1.1.1.16  root      332: static void HDC_Cmd_ModeSense(SCSI_CTRLR *ctr)
1.1.1.7   root      333: {
1.1.1.16  root      334:        SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root      335:        Uint8 *buf;
1.1.1.7   root      336: 
1.1.1.16  root      337:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: MODE SENSE (%s).\n", HDC_CmdInfoStr(ctr));
1.1.1.7   root      338: 
1.1.1.17! root      339:        dev->bSetLastBlockAddr = false;
1.1.1.12  root      340: 
1.1.1.17! root      341:        if (ctr->command[2] != 0 || HDC_GetCount(ctr) != 0x10)
1.1.1.7   root      342:        {
1.1.1.9   root      343:                Log_Printf(LOG_TODO, "HDC: Unsupported MODE SENSE command\n");
1.1.1.16  root      344:                ctr->returnCode = HD_STATUS_ERROR;
                    345:                dev->nLastError = HD_REQSENS_INVARG;
1.1.1.17! root      346:                return;
1.1.1.7   root      347:        }
                    348: 
1.1.1.17! root      349:        buf = HDC_PrepRespBuf(ctr, 16);
        !           350: 
        !           351:        buf[0] = 0;
        !           352:        buf[1] = 0;
        !           353:        buf[2] = 0;
        !           354:        buf[3] = 8;
        !           355:        buf[4] = 0;
        !           356: 
        !           357:        buf[5] = dev->hdSize >> 16;  // Number of blocks, high
        !           358:        buf[6] = dev->hdSize >> 8;   // Number of blocks, med
        !           359:        buf[7] = dev->hdSize;        // Number of blocks, low
        !           360: 
        !           361:        buf[8] = 0;
        !           362: 
        !           363:        buf[9] = 0;      // Block size in bytes, high
        !           364:        buf[10] = 2;     // Block size in bytes, med
        !           365:        buf[11] = 0;     // Block size in bytes, low
        !           366: 
        !           367:        buf[12] = 0;
        !           368:        buf[13] = 0;
        !           369:        buf[14] = 0;
        !           370:        buf[15] = 0;
        !           371: 
        !           372:        ctr->returnCode = HD_STATUS_OK;
        !           373:        dev->nLastError = HD_REQSENS_OK;
1.1.1.7   root      374: }
                    375: 
                    376: 
1.1.1.8   root      377: /**
                    378:  * Format drive.
                    379:  */
1.1.1.16  root      380: static void HDC_Cmd_FormatDrive(SCSI_CTRLR *ctr)
1.1.1.7   root      381: {
1.1.1.16  root      382:        SCSI_DEV *dev = &ctr->devs[ctr->target];
                    383: 
                    384:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: FORMAT DRIVE (%s).\n", HDC_CmdInfoStr(ctr));
1.1.1.7   root      385: 
                    386:        /* Should erase the whole image file here... */
                    387: 
1.1.1.16  root      388:        ctr->returnCode = HD_STATUS_OK;
                    389:        dev->nLastError = HD_REQSENS_OK;
                    390:        dev->bSetLastBlockAddr = false;
1.1       root      391: }
                    392: 
1.1.1.16  root      393: 
1.1.1.14  root      394: /**
                    395:  * Read capacity of our disk.
                    396:  */
1.1.1.16  root      397: static void HDC_Cmd_ReadCapacity(SCSI_CTRLR *ctr)
1.1.1.14  root      398: {
1.1.1.16  root      399:        SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root      400:        int nSectors = dev->hdSize - 1;
        !           401:        Uint8 *buf;
1.1.1.14  root      402: 
1.1.1.17! root      403:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: READ CAPACITY (%s)\n", HDC_CmdInfoStr(ctr));
1.1.1.14  root      404: 
1.1.1.17! root      405:        buf = HDC_PrepRespBuf(ctr, 8);
1.1.1.14  root      406: 
1.1.1.17! root      407:        buf[0] = (nSectors >> 24) & 0xFF;
        !           408:        buf[1] = (nSectors >> 16) & 0xFF;
        !           409:        buf[2] = (nSectors >> 8) & 0xFF;
        !           410:        buf[3] = (nSectors) & 0xFF;
        !           411:        buf[4] = 0x00;
        !           412:        buf[5] = 0x00;
        !           413:        buf[6] = 0x02;
        !           414:        buf[7] = 0x00;
1.1.1.14  root      415: 
1.1.1.17! root      416:        ctr->returnCode = HD_STATUS_OK;
        !           417:        dev->nLastError = HD_REQSENS_OK;
1.1.1.16  root      418:        dev->bSetLastBlockAddr = false;
1.1.1.14  root      419: }
                    420: 
1.1.1.7   root      421: 
1.1.1.8   root      422: /**
                    423:  * Write a sector off our disk - (seek implied)
                    424:  */
1.1.1.16  root      425: static void HDC_Cmd_WriteSector(SCSI_CTRLR *ctr)
1.1       root      426: {
1.1.1.16  root      427:        SCSI_DEV *dev = &ctr->devs[ctr->target];
                    428:        Uint32 nDmaAddr = FDC_GetDMAAddress();
1.1.1.11  root      429:        int n = 0;
                    430: 
1.1.1.16  root      431:        dev->nLastBlockAddr = HDC_GetLBA(ctr);
                    432: 
1.1.1.17! root      433:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: WRITE SECTOR (%s) with LBA 0x%x from 0x%x",
1.1.1.16  root      434:                  HDC_CmdInfoStr(ctr), dev->nLastBlockAddr, nDmaAddr);
1.1       root      435: 
1.1.1.7   root      436:        /* seek to the position */
1.1.1.16  root      437:        if (dev->nLastBlockAddr >= dev->hdSize ||
                    438:            fseeko(dev->image_file, (off_t)dev->nLastBlockAddr * 512L, SEEK_SET) != 0)
1.1.1.7   root      439:        {
1.1.1.16  root      440:                ctr->returnCode = HD_STATUS_ERROR;
                    441:                dev->nLastError = HD_REQSENS_INVADDR;
1.1.1.7   root      442:        }
                    443:        else
                    444:        {
                    445:                /* write - if allowed */
1.1       root      446: #ifndef DISALLOW_HDC_WRITE
1.1.1.17! root      447:                if ( STMemory_CheckAreaType ( nDmaAddr , 512 * HDC_GetCount(ctr) , ABFLAG_RAM ) )
1.1.1.13  root      448:                {
                    449:                        n = fwrite(&STRam[nDmaAddr], 512,
1.1.1.16  root      450:                                   HDC_GetCount(ctr), dev->image_file);
1.1.1.13  root      451:                }
                    452:                else
                    453:                {
                    454:                        Log_Printf(LOG_WARN, "HDC sector write uses invalid RAM range 0x%x+%i\n",
1.1.1.16  root      455:                                   nDmaAddr, 512 * HDC_GetCount(ctr));
                    456:                        ctr->bDmaError = true;
1.1.1.13  root      457:                }
1.1       root      458: #endif
1.1.1.16  root      459:                if (n == HDC_GetCount(ctr))
1.1.1.11  root      460:                {
1.1.1.16  root      461:                        ctr->returnCode = HD_STATUS_OK;
                    462:                        dev->nLastError = HD_REQSENS_OK;
1.1.1.11  root      463:                }
                    464:                else
                    465:                {
1.1.1.16  root      466:                        ctr->returnCode = HD_STATUS_ERROR;
                    467:                        dev->nLastError = HD_REQSENS_WRITEERR;
1.1.1.11  root      468:                }
                    469: 
1.1.1.9   root      470:                /* Update DMA counter */
1.1.1.13  root      471:                FDC_WriteDMAAddress(nDmaAddr + 512*n);
1.1.1.7   root      472:        }
1.1.1.17! root      473:        LOG_TRACE(TRACE_SCSI_CMD, " -> %s (%d)\n",
        !           474:                  ctr->returnCode == HD_STATUS_OK ? "OK" : "ERROR",
        !           475:                  dev->nLastError);
1.1       root      476: 
1.1.1.16  root      477:        dev->bSetLastBlockAddr = true;
1.1       root      478: }
                    479: 
1.1.1.7   root      480: 
1.1.1.8   root      481: /**
                    482:  * Read a sector off our disk - (implied seek)
                    483:  */
1.1.1.16  root      484: static void HDC_Cmd_ReadSector(SCSI_CTRLR *ctr)
1.1       root      485: {
1.1.1.16  root      486:        SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1.1.17! root      487:        Uint8 *buf;
1.1.1.11  root      488:        int n;
                    489: 
1.1.1.16  root      490:        dev->nLastBlockAddr = HDC_GetLBA(ctr);
1.1       root      491: 
1.1.1.17! root      492:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: READ SECTOR (%s) with LBA 0x%x",
        !           493:                  HDC_CmdInfoStr(ctr), dev->nLastBlockAddr);
1.1       root      494: 
1.1.1.7   root      495:        /* seek to the position */
1.1.1.16  root      496:        if (dev->nLastBlockAddr >= dev->hdSize ||
                    497:            fseeko(dev->image_file, (off_t)dev->nLastBlockAddr * 512L, SEEK_SET) != 0)
1.1.1.7   root      498:        {
1.1.1.16  root      499:                ctr->returnCode = HD_STATUS_ERROR;
                    500:                dev->nLastError = HD_REQSENS_INVADDR;
1.1.1.7   root      501:        }
                    502:        else
                    503:        {
1.1.1.17! root      504:                buf = HDC_PrepRespBuf(ctr, 512 * HDC_GetCount(ctr));
        !           505:                n = fread(buf, 512, HDC_GetCount(ctr), dev->image_file);
1.1.1.16  root      506:                if (n == HDC_GetCount(ctr))
1.1.1.11  root      507:                {
1.1.1.16  root      508:                        ctr->returnCode = HD_STATUS_OK;
                    509:                        dev->nLastError = HD_REQSENS_OK;
1.1.1.11  root      510:                }
                    511:                else
                    512:                {
1.1.1.16  root      513:                        ctr->returnCode = HD_STATUS_ERROR;
                    514:                        dev->nLastError = HD_REQSENS_NOSECTOR;
1.1.1.11  root      515:                }
1.1.1.7   root      516:        }
1.1.1.17! root      517:        LOG_TRACE(TRACE_SCSI_CMD, " -> %s (%d)\n",
        !           518:                  ctr->returnCode == HD_STATUS_OK ? "OK" : "ERROR",
        !           519:                  dev->nLastError);
1.1       root      520: 
1.1.1.16  root      521:        dev->bSetLastBlockAddr = true;
1.1       root      522: }
                    523: 
1.1.1.7   root      524: 
1.1.1.8   root      525: /**
1.1.1.12  root      526:  * Test unit ready
                    527:  */
1.1.1.16  root      528: static void HDC_Cmd_TestUnitReady(SCSI_CTRLR *ctr)
1.1.1.12  root      529: {
1.1.1.16  root      530:        LOG_TRACE(TRACE_SCSI_CMD, "HDC: TEST UNIT READY (%s).\n", HDC_CmdInfoStr(ctr));
                    531:        ctr->returnCode = HD_STATUS_OK;
1.1.1.12  root      532: }
                    533: 
                    534: 
                    535: /**
1.1.1.8   root      536:  * Emulation routine for HDC command packets.
                    537:  */
1.1.1.16  root      538: static void HDC_EmulateCommandPacket(SCSI_CTRLR *ctr)
1.1       root      539: {
1.1.1.16  root      540:        SCSI_DEV *dev = &ctr->devs[ctr->target];
1.1       root      541: 
1.1.1.17! root      542:        ctr->respcnt = 0;
        !           543: 
1.1.1.16  root      544:        switch (ctr->opcode)
1.1.1.7   root      545:        {
1.1.1.12  root      546:         case HD_TEST_UNIT_RDY:
1.1.1.16  root      547:                HDC_Cmd_TestUnitReady(ctr);
1.1.1.12  root      548:                break;
                    549: 
1.1.1.16  root      550:         case HD_READ_CAPACITY1:
                    551:                HDC_Cmd_ReadCapacity(ctr);
1.1.1.14  root      552:                break;
                    553: 
1.1.1.7   root      554:         case HD_READ_SECTOR:
1.1.1.14  root      555:         case HD_READ_SECTOR1:
1.1.1.16  root      556:                HDC_Cmd_ReadSector(ctr);
1.1.1.7   root      557:                break;
1.1.1.14  root      558: 
1.1.1.7   root      559:         case HD_WRITE_SECTOR:
1.1.1.14  root      560:         case HD_WRITE_SECTOR1:
1.1.1.16  root      561:                HDC_Cmd_WriteSector(ctr);
1.1.1.7   root      562:                break;
                    563: 
                    564:         case HD_INQUIRY:
1.1.1.16  root      565:                HDC_Cmd_Inquiry(ctr);
1.1.1.7   root      566:                break;
                    567: 
                    568:         case HD_SEEK:
1.1.1.16  root      569:                HDC_Cmd_Seek(ctr);
1.1.1.7   root      570:                break;
                    571: 
                    572:         case HD_SHIP:
1.1.1.16  root      573:                LOG_TRACE(TRACE_SCSI_CMD, "HDC: SHIP (%s).\n", HDC_CmdInfoStr(ctr));
                    574:                ctr->returnCode = 0xFF;
1.1.1.7   root      575:                break;
                    576: 
                    577:         case HD_REQ_SENSE:
1.1.1.16  root      578:                HDC_Cmd_RequestSense(ctr);
1.1.1.7   root      579:                break;
                    580: 
                    581:         case HD_MODESELECT:
1.1.1.16  root      582:                LOG_TRACE(TRACE_SCSI_CMD, "HDC: MODE SELECT (%s) TODO!\n", HDC_CmdInfoStr(ctr));
                    583:                ctr->returnCode = HD_STATUS_OK;
                    584:                dev->nLastError = HD_REQSENS_OK;
                    585:                dev->bSetLastBlockAddr = false;
1.1.1.7   root      586:                break;
                    587: 
                    588:         case HD_MODESENSE:
1.1.1.16  root      589:                HDC_Cmd_ModeSense(ctr);
1.1.1.7   root      590:                break;
                    591: 
                    592:         case HD_FORMAT_DRIVE:
1.1.1.16  root      593:                HDC_Cmd_FormatDrive(ctr);
1.1.1.7   root      594:                break;
                    595: 
                    596:         /* as of yet unsupported commands */
                    597:         case HD_VERIFY_TRACK:
                    598:         case HD_FORMAT_TRACK:
                    599:         case HD_CORRECTION:
                    600: 
                    601:         default:
1.1.1.16  root      602:                LOG_TRACE(TRACE_SCSI_CMD, "HDC: Unsupported command (%s)!\n", HDC_CmdInfoStr(ctr));
                    603:                ctr->returnCode = HD_STATUS_ERROR;
                    604:                dev->nLastError = HD_REQSENS_OPCODE;
                    605:                dev->bSetLastBlockAddr = false;
1.1.1.7   root      606:                break;
                    607:        }
1.1.1.9   root      608: 
                    609:        /* Update the led each time a command is processed */
1.1.1.15  root      610:        Statusbar_EnableHDLed( LED_STATE_ON );
1.1       root      611: }
                    612: 
1.1.1.7   root      613: 
1.1       root      614: /*---------------------------------------------------------------------*/
1.1.1.8   root      615: /**
1.1.1.17! root      616:  * Return given image file (primary) partition count and with tracing
        !           617:  * print also partition table.
        !           618:  *
        !           619:  * Supports both DOS and Atari master boot record partition tables
        !           620:  * (with 4 entries).
        !           621:  *
        !           622:  * TODO:
        !           623:  * - Support also Atari ICD (12 entries, at offset 0x156) and
        !           624:  *   extended partition schemes.  Linux kernel has code for those:
        !           625:  *   http://lxr.free-electrons.com/source/block/partitions/atari.c
        !           626:  * - Support partition tables with other endianess
1.1.1.8   root      627:  */
1.1.1.17! root      628: int HDC_PartitionCount(FILE *fp, const Uint64 tracelevel)
1.1       root      629: {
1.1.1.17! root      630:        unsigned char *pinfo, bootsector[512];
        !           631:        Uint32 start, sectors, total = 0;
        !           632:        int i, parts = 0;
        !           633:        off_t offset;
1.1       root      634: 
1.1.1.17! root      635:        if (!fp)
        !           636:                return 0;
        !           637:        offset = ftello(fp);
1.1.1.7   root      638: 
1.1.1.17! root      639:        if (fseeko(fp, 0, SEEK_SET) != 0
        !           640:            || fread(bootsector, sizeof(bootsector), 1, fp) != 1)
1.1.1.11  root      641:        {
1.1.1.17! root      642:                perror("HDC_PartitionCount");
        !           643:                return 0;
1.1.1.11  root      644:        }
1.1       root      645: 
1.1.1.17! root      646:        if (bootsector[0x1FE] == 0x55 && bootsector[0x1FF] == 0xAA)
        !           647:        {
        !           648:                int ptype, boot;
1.1       root      649: 
1.1.1.17! root      650:                LOG_TRACE(tracelevel, "DOS MBR:\n");
        !           651:                /* first partition table entry */
        !           652:                pinfo = bootsector + 0x1BE;
        !           653:                for (i = 0; i < 4; i++, pinfo += 16)
        !           654:                {
        !           655:                        boot = pinfo[0];
        !           656:                        ptype = pinfo[4];
        !           657:                        start = HDC_ReadInt32(pinfo, 8);
        !           658:                        sectors = HDC_ReadInt32(pinfo, 12);
        !           659:                        total += sectors;
        !           660:                        LOG_TRACE(tracelevel, "- Partition %d: type=0x%02x, start=0x%08x, size=%d MB %s\n",
        !           661:                                  i, ptype, start, sectors/2048, boot ? "(boot)" : "");
        !           662:                        if (ptype)
        !           663:                                parts++;
        !           664:                }
        !           665:                LOG_TRACE(tracelevel, "- Total size: %i MB in %d partitions\n", total/2048, parts);
        !           666:        }
        !           667:        else
        !           668:        {
        !           669:                /* Partition table contains hd size + 4 partition entries
        !           670:                 * (composed of flag byte, 3 char ID, start offset
        !           671:                 * and size), this is followed by bad sector list +
        !           672:                 * count and the root sector checksum. Before this
        !           673:                 * there's the boot code.
        !           674:                 */
        !           675:                char c, pid[4];
        !           676:                int j, flags;
        !           677: 
        !           678:                LOG_TRACE(tracelevel, "ATARI MBR:\n");
        !           679:                pinfo = bootsector + 0x1C6;
        !           680:                for (i = 0; i < 4; i++, pinfo += 12)
        !           681:                {
        !           682:                        flags = pinfo[0];
        !           683:                        for (j = 0; j < 3; j++)
        !           684:                        {
        !           685:                                c = pinfo[j+1];
        !           686:                                if (c < 32 || c >= 127)
        !           687:                                        c = '.';
        !           688:                                pid[j] = c;
        !           689:                        }
        !           690:                        pid[3] = '\0';
        !           691:                        start = HDC_ReadInt32(pinfo, 4);
        !           692:                        sectors = HDC_ReadInt32(pinfo, 8);
        !           693:                        LOG_TRACE(tracelevel, "- Partition %d: ID=%s, start=0x%08x, size=%d MB, flags=0x%x\n",
        !           694:                                  i, pid, start, sectors/2048, flags);
        !           695:                        if (flags & 0x1)
        !           696:                                parts++;
        !           697:                }
        !           698:                total = HDC_ReadInt32(bootsector, 0x1C2);
        !           699:                LOG_TRACE(tracelevel, "- Total size: %i MB in %d partitions\n", total/2048, parts);
        !           700:        }
1.1       root      701: 
1.1.1.17! root      702:        if (fseeko(fp, offset, SEEK_SET) != 0)
        !           703:                perror("HDC_PartitionCount");
        !           704:        return parts;
1.1       root      705: }
                    706: 
1.1.1.17! root      707: /**
        !           708:  * Open a disk image file
        !           709:  */
        !           710: static int HDC_InitDevice(SCSI_DEV *dev, char *filename)
        !           711: {
        !           712:        off_t filesize;
        !           713:        FILE *fp;
        !           714: 
        !           715:        dev->enabled = false;
        !           716:        Log_Printf(LOG_INFO, "Mounting hard drive image '%s'\n", filename);
        !           717: 
        !           718:        /* Check size for sanity - is the length a multiple of 512? */
        !           719:        filesize = File_Length(filename);
        !           720:        if (filesize < 0)
        !           721:        {
        !           722:                Log_Printf(LOG_ERROR, "ERROR: unable to access/get HD file size!\n");
        !           723:                return -EINVAL;
        !           724:        }
        !           725:        if (filesize <= 0 || (filesize & 0x1ff) != 0)
        !           726:        {
        !           727:                Log_Printf(LOG_ERROR, "ERROR: HD file has strange size!\n");
        !           728:                return -EINVAL;
        !           729:        }
        !           730: 
        !           731:        fp = fopen(filename, "rb+");
        !           732:        if (fp == NULL)
        !           733:        {
        !           734:                Log_Printf(LOG_ERROR, "ERROR: cannot open HD file read/write!\n");
        !           735:                return -ENOENT;
        !           736:        }
        !           737:        if (!File_Lock(fp))
        !           738:        {
        !           739:                Log_Printf(LOG_ERROR, "ERROR: cannot lock HD file for writing!\n");
        !           740:                fclose(fp);
        !           741:                return -ENOLCK;
        !           742:        }
        !           743: 
        !           744:        dev->hdSize = filesize / 512;
        !           745:        dev->image_file = fp;
        !           746:        dev->enabled = true;
        !           747: 
        !           748:        return 0;
        !           749: }
1.1.1.7   root      750: 
1.1.1.8   root      751: /**
                    752:  * Open the disk image file, set partitions.
1.1       root      753:  */
1.1.1.12  root      754: bool HDC_Init(void)
1.1       root      755: {
1.1.1.16  root      756:        int i;
1.1       root      757: 
1.1.1.17! root      758:        /* ACSI */
        !           759:        nAcsiPartitions = 0;
1.1.1.16  root      760:        bAcsiEmuOn = false;
1.1.1.17! root      761:        memset(&AcsiBus, 0, sizeof(AcsiBus));
        !           762:        AcsiBus.respbufsize = 512;
        !           763:        AcsiBus.resp = malloc(AcsiBus.respbufsize);
        !           764:        if (!AcsiBus.resp)
        !           765:        {
        !           766:                perror("HDC_Init");
        !           767:                return false;
        !           768:        }
1.1.1.16  root      769:        for (i = 0; i < MAX_ACSI_DEVS; i++)
1.1.1.7   root      770:        {
1.1.1.16  root      771:                if (!ConfigureParams.Acsi[i].bUseDevice)
                    772:                        continue;
1.1.1.17! root      773:                if (HDC_InitDevice(&AcsiBus.devs[i], ConfigureParams.Acsi[i].sDeviceFile) == 0)
1.1.1.16  root      774:                {
1.1.1.17! root      775:                        bAcsiEmuOn = true;
        !           776:                        nAcsiPartitions += HDC_PartitionCount(AcsiBus.devs[i].image_file, TRACE_SCSI_CMD);
1.1.1.16  root      777:                }
1.1.1.17! root      778:        }
1.1.1.16  root      779: 
1.1.1.17! root      780:        /* SCSI */
        !           781: #if WITH_NCR5380
        !           782:        memset(&ScsiBus, 0, sizeof(ScsiBus));
        !           783:        ScsiBus.respbufsize = 512;
        !           784:        ScsiBus.resp = malloc(ScsiBus.respbufsize);
        !           785:        if (!ScsiBus.resp)
        !           786:        {
        !           787:                perror("HDC_Init");
        !           788:                return bAcsiEmuOn;
        !           789:        }
        !           790:        for (i = 0; i < MAX_SCSI_DEVS; i++)
        !           791:        {
        !           792:                if (!ConfigureParams.Scsi[i].bUseDevice)
1.1.1.16  root      793:                        continue;
1.1.1.17! root      794:                HDC_InitDevice(&ScsiBus.devs[i], ConfigureParams.Scsi[i].sDeviceFile);
1.1.1.16  root      795:        }
1.1.1.17! root      796: #endif
1.1.1.7   root      797: 
                    798:        /* set number of partitions */
1.1.1.17! root      799:        nNumDrives += nAcsiPartitions;
1.1.1.7   root      800: 
1.1.1.16  root      801:        return bAcsiEmuOn;
1.1       root      802: }
1.1.1.3   root      803: 
1.1.1.7   root      804: 
1.1       root      805: /*---------------------------------------------------------------------*/
1.1.1.8   root      806: /**
                    807:  * HDC_UnInit - close image file
                    808:  *
1.1       root      809:  */
1.1.1.4   root      810: void HDC_UnInit(void)
1.1       root      811: {
1.1.1.16  root      812:        int i;
                    813: 
1.1.1.7   root      814:        if (!bAcsiEmuOn)
                    815:                return;
                    816: 
1.1.1.16  root      817:        for (i = 0; i < MAX_ACSI_DEVS; i++)
                    818:        {
                    819:                if (!AcsiBus.devs[i].enabled)
                    820:                        continue;
1.1.1.17! root      821:                File_UnLock(AcsiBus.devs[i].image_file);
1.1.1.16  root      822:                fclose(AcsiBus.devs[i].image_file);
                    823:                AcsiBus.devs[i].image_file = NULL;
                    824:                AcsiBus.devs[i].enabled = false;
                    825:        }
1.1.1.17! root      826:        free(AcsiBus.resp);
        !           827:        AcsiBus.resp = NULL;
1.1.1.7   root      828: 
1.1.1.17! root      829: #if WITH_NCR5380
        !           830:        for (i = 0; i < MAX_SCSI_DEVS; i++)
        !           831:        {
        !           832:                if (!ScsiBus.devs[i].enabled)
        !           833:                        continue;
        !           834:                File_UnLock(ScsiBus.devs[i].image_file);
        !           835:                fclose(ScsiBus.devs[i].image_file);
        !           836:                ScsiBus.devs[i].image_file = NULL;
        !           837:                ScsiBus.devs[i].enabled = false;
        !           838:        }
        !           839:        free(ScsiBus.resp);
        !           840:        ScsiBus.resp = NULL;
        !           841: #endif
        !           842: 
        !           843:        nNumDrives -= nAcsiPartitions;
        !           844:        nAcsiPartitions = 0;
1.1.1.11  root      845:        bAcsiEmuOn = false;
1.1       root      846: }
                    847: 
1.1.1.7   root      848: 
1.1       root      849: /*---------------------------------------------------------------------*/
1.1.1.8   root      850: /**
1.1.1.14  root      851:  * Reset command status.
                    852:  */
                    853: void HDC_ResetCommandStatus(void)
                    854: {
1.1.1.16  root      855:        if (ConfigureParams.System.nMachineType != MACHINE_FALCON)
                    856:                AcsiBus.returnCode = 0;
1.1.1.14  root      857: }
                    858: 
                    859: 
                    860: /**
1.1.1.16  root      861:  * Process HDC command packets (SCSI/ACSI) bytes.
1.1.1.17! root      862:  * @return true if command has been executed.
1.1.1.14  root      863:  */
1.1.1.17! root      864: static bool HDC_WriteCommandPacket(SCSI_CTRLR *ctr, Uint8 b)
1.1.1.14  root      865: {
1.1.1.17! root      866:        bool bDidCmd = false;
1.1.1.16  root      867:        SCSI_DEV *dev = &ctr->devs[ctr->target];
                    868: 
                    869:        /* Abort if the target device is not enabled */
                    870:        if (!dev->enabled)
                    871:        {
                    872:                ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17! root      873:                return false;
1.1.1.16  root      874:        }
                    875: 
                    876:        /* Extract ACSI/SCSI opcode */
                    877:        if (ctr->byteCount == 0)
                    878:        {
                    879:                ctr->opcode = b;
                    880:                ctr->bDmaError = false;
                    881:        }
1.1.1.14  root      882: 
1.1.1.16  root      883:        /* Successfully received one byte, and increase the byte-count */
                    884:        if (ctr->byteCount < (int)sizeof(ctr->command))
                    885:                ctr->command[ctr->byteCount] = b;
                    886:        ++ctr->byteCount;
                    887: 
                    888:        /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */
                    889:        if ((ctr->opcode < 0x20 && ctr->byteCount >= 6) ||
                    890:            (ctr->opcode < 0x60 && ctr->byteCount >= 10))
                    891:        {
                    892:                /* We currently only support LUN 0, however INQUIRY must
                    893:                 * always be handled, see SCSI standard */
                    894:                if (HDC_GetLUN(ctr) == 0 || ctr->opcode == HD_INQUIRY)
                    895:                {
                    896:                        HDC_EmulateCommandPacket(ctr);
1.1.1.17! root      897:                        bDidCmd = true;
1.1.1.16  root      898:                }
                    899:                else
                    900:                {
                    901:                        Log_Printf(LOG_WARN, "HDC: Access to non-existing LUN."
                    902:                                   " Command = 0x%02x\n", ctr->opcode);
                    903:                        dev->nLastError = HD_REQSENS_INVLUN;
                    904:                        /* REQUEST SENSE is still handled for invalid LUNs */
                    905:                        if (ctr->opcode == HD_REQ_SENSE)
1.1.1.17! root      906:                        {
1.1.1.16  root      907:                                HDC_Cmd_RequestSense(ctr);
1.1.1.17! root      908:                                bDidCmd = true;
        !           909:                        }
1.1.1.16  root      910:                        else
1.1.1.17! root      911:                        {
1.1.1.16  root      912:                                ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17! root      913:                        }
1.1.1.16  root      914:                }
                    915: 
                    916:                ctr->byteCount = 0;
                    917:        }
                    918:        else if (ctr->opcode >= 0x60)
                    919:        {
                    920:                /* Commands >= 0x60 are not supported right now */
                    921:                ctr->returnCode = HD_STATUS_ERROR;
                    922:                dev->nLastError = HD_REQSENS_OPCODE;
                    923:                dev->bSetLastBlockAddr = false;
                    924:                if (ctr->byteCount == 10)
                    925:                {
                    926:                        LOG_TRACE(TRACE_SCSI_CMD, "HDC: Unsupported command (%s).\n",
                    927:                                  HDC_CmdInfoStr(ctr));
                    928:                }
                    929:        }
                    930:        else
                    931:        {
                    932:                ctr->returnCode = HD_STATUS_OK;
                    933:        }
1.1.1.17! root      934: 
        !           935:        return bDidCmd;
1.1.1.16  root      936: }
1.1.1.14  root      937: 
                    938: /*---------------------------------------------------------------------*/
1.1.1.16  root      939: 
                    940: static struct ncr5380_regs
                    941: {
                    942:        Uint8 initiator_cmd;
                    943:        Uint8 current_bus_status;
                    944:        Uint8 bus_and_status;
                    945: } ncr_regs;
                    946: 
1.1.1.14  root      947: /**
1.1.1.16  root      948:  * Emulate external reset "pin": Clear registers etc.
1.1.1.14  root      949:  */
1.1.1.16  root      950: void Ncr5380_Reset(void)
1.1.1.14  root      951: {
1.1.1.16  root      952:        ncr_regs.initiator_cmd &= 0x7f;
1.1.1.14  root      953: }
                    954: 
                    955: /**
1.1.1.16  root      956:  * Write a command byte to the NCR 5380 SCSI controller
1.1.1.8   root      957:  */
1.1.1.16  root      958: static void Ncr5380_WriteByte(int addr, Uint8 byte)
1.1       root      959: {
1.1.1.17! root      960: #if WITH_NCR5380
1.1.1.16  root      961:        switch (addr)
1.1.1.14  root      962:        {
1.1.1.16  root      963:        case 0:                 /* Output Data register */
                    964:                ncr_regs.current_bus_status |= 0x40;
                    965:                break;
                    966:        case 1:                 /* Initiator Command register */
                    967:                ncr_regs.initiator_cmd = byte;
                    968:                break;
                    969:        case 2:                 /* Mode register */
                    970:                break;
                    971:        case 3:                 /* Target Command register */
                    972:                break;
                    973:        case 4:                 /* Select Enable register */
                    974:                break;
                    975:        case 5:                 /* Start DMA Send register */
                    976:                break;
                    977:        case 6:                 /* Start DMA Target Receive register */
                    978:                break;
                    979:        case 7:                 /* Start DMA Initiator Receive register */
                    980:                break;
                    981:        default:
                    982:                fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.14  root      983:        }
1.1.1.17! root      984: #endif
1.1.1.16  root      985: }
1.1.1.12  root      986: 
1.1.1.16  root      987: /**
                    988:  * Read a command byte from the NCR 5380 SCSI controller
                    989:  */
                    990: static Uint8 Ncr5380_ReadByte(int addr)
                    991: {
1.1.1.17! root      992: #if WITH_NCR5380
1.1.1.16  root      993:        switch (addr)
1.1.1.12  root      994:        {
1.1.1.16  root      995:        case 0:                 /* Current SCSI Data register */
                    996:                break;
                    997:        case 1:                 /* Initiator Command register */
                    998:                return ncr_regs.initiator_cmd & 0x9f;
                    999:        case 2:                 /* Mode register */
                   1000:                break;
                   1001:        case 3:                 /* Target Command register */
                   1002:                break;
                   1003:        case 4:                 /* Current SCSI Bus Status register */
                   1004:                if (ncr_regs.current_bus_status & 0x40) /* BUSY? */
                   1005:                        ncr_regs.current_bus_status |= 0x20;
                   1006:                else
                   1007:                        ncr_regs.current_bus_status &= ~0x20;
                   1008:                if (ncr_regs.initiator_cmd & 0x80)      /* ASSERT RST? */
                   1009:                        ncr_regs.current_bus_status |= 0x80;
                   1010:                else
                   1011:                        ncr_regs.current_bus_status &= ~0x80;
                   1012:                if (ncr_regs.initiator_cmd & 0x04)      /* ASSERT BUSY? */
                   1013:                        ncr_regs.current_bus_status |= 0x40;
                   1014:                else
                   1015:                        ncr_regs.current_bus_status &= ~0x40;
                   1016:                return ncr_regs.current_bus_status;
                   1017:        case 5:                 /* Bus and Status register */
                   1018:                return ncr_regs.bus_and_status;
                   1019:        case 6:                 /* Input Data register */
                   1020:                break;
                   1021:        case 7:                 /* Reset Parity/Interrupts register */
                   1022:                /* Reset PARITY ERROR, IRQ REQUEST and BUSY ERROR bits */
                   1023:                ncr_regs.bus_and_status &= 0xcb;
                   1024:                return 0;  /* TODO: Is this return value ok? */
                   1025:        default:
                   1026:                fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.12  root     1027:        }
1.1.1.17! root     1028: #endif
1.1.1.12  root     1029: 
1.1.1.16  root     1030:        return 0;
                   1031: }
1.1.1.7   root     1032: 
1.1.1.16  root     1033: 
                   1034: static void Acsi_WriteCommandByte(int addr, Uint8 byte)
                   1035: {
1.1.1.17! root     1036:        /* Clear IRQ initially (will be set again if byte has been accepted) */
        !          1037:        FDC_ClearHdcIRQ();
        !          1038: 
        !          1039:        /* When the A1 pin is pushed to 0, we want to start a new command.
        !          1040:         * We ignore the pin for the second byte in the packet since this
        !          1041:         * seems to happen on real hardware too (some buggy driver relies
        !          1042:         * on this behavior). */
        !          1043:        if ((addr & 2) == 0 && AcsiBus.byteCount != 1)
1.1.1.7   root     1044:        {
1.1.1.16  root     1045:                AcsiBus.byteCount = 0;
                   1046:                AcsiBus.target = ((byte & 0xE0) >> 5);
                   1047:                /* Only process the first byte if it is not
                   1048:                 * an extended ICD command marker byte */
                   1049:                if ((byte & 0x1F) != 0x1F)
1.1.1.7   root     1050:                {
1.1.1.16  root     1051:                        HDC_WriteCommandPacket(&AcsiBus, byte & 0x1F);
1.1.1.7   root     1052:                }
                   1053:                else
                   1054:                {
1.1.1.16  root     1055:                        AcsiBus.returnCode = HD_STATUS_OK;
                   1056:                        AcsiBus.bDmaError = false;
1.1.1.7   root     1057:                }
1.1.1.16  root     1058:        }
                   1059:        else
                   1060:        {
                   1061:                /* Process normal command byte */
1.1.1.17! root     1062:                bool bDidCmd = HDC_WriteCommandPacket(&AcsiBus, byte);
        !          1063:                if (bDidCmd && AcsiBus.returnCode == HD_STATUS_OK && AcsiBus.respcnt)
        !          1064:                {
        !          1065:                        /* DMA transfer necessary */
        !          1066:                        Uint32 nDmaAddr = FDC_GetDMAAddress();
        !          1067:                        if (!STMemory_SafeCopy(nDmaAddr, AcsiBus.resp, AcsiBus.respcnt, "ACSI DMA"))
        !          1068:                        {
        !          1069:                                AcsiBus.bDmaError = true;
        !          1070:                                AcsiBus.returnCode = HD_STATUS_ERROR;
        !          1071:                        }
        !          1072:                        FDC_WriteDMAAddress(nDmaAddr + AcsiBus.respcnt);
        !          1073:                        AcsiBus.respcnt = 0;
        !          1074:                }
1.1.1.16  root     1075:        }
1.1.1.7   root     1076: 
1.1.1.16  root     1077:        if (AcsiBus.devs[AcsiBus.target].enabled)
                   1078:        {
                   1079:                FDC_SetDMAStatus(AcsiBus.bDmaError);    /* Mark DMA error */
                   1080:                FDC_SetIRQ(FDC_IRQ_SOURCE_HDC);
1.1.1.7   root     1081:        }
1.1       root     1082: }
1.1.1.16  root     1083: 
                   1084: /**
                   1085:  * Called when command bytes have been written to $FFFF8606 and
                   1086:  * the HDC (not the FDC) is selected.
                   1087:  */
                   1088: void HDC_WriteCommandByte(int addr, Uint8 byte)
                   1089: {
                   1090:        // fprintf(stderr, "HDC: Write cmd byte addr=%i, byte=%02x\n", addr, byte);
                   1091: 
                   1092:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                   1093:                Ncr5380_WriteByte(addr, byte);
                   1094:        else if (bAcsiEmuOn)
                   1095:                Acsi_WriteCommandByte(addr, byte);
                   1096: }
                   1097: 
                   1098: /**
                   1099:  * Get command byte.
                   1100:  */
                   1101: short int HDC_ReadCommandByte(int addr)
                   1102: {
                   1103:        Uint16 ret;
                   1104:        if (ConfigureParams.System.nMachineType == MACHINE_FALCON)
                   1105:                ret = Ncr5380_ReadByte(addr);
                   1106:        else
                   1107:                ret = AcsiBus.returnCode;       /* ACSI status */
                   1108:        return ret;
                   1109: }

unix.superglobalmegacorp.com

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