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

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
1.1.1.18! root      626:  *   Normal and extended partition tables are described in:
        !           627:  *   http://dev-docs.atariforge.org/files/AHDI_3_RN_4-18-1990.pdf
        !           628:  * - Support partition tables with other endianness
1.1.1.8   root      629:  */
1.1.1.17  root      630: int HDC_PartitionCount(FILE *fp, const Uint64 tracelevel)
1.1       root      631: {
1.1.1.17  root      632:        unsigned char *pinfo, bootsector[512];
                    633:        Uint32 start, sectors, total = 0;
                    634:        int i, parts = 0;
                    635:        off_t offset;
1.1       root      636: 
1.1.1.17  root      637:        if (!fp)
                    638:                return 0;
                    639:        offset = ftello(fp);
1.1.1.7   root      640: 
1.1.1.17  root      641:        if (fseeko(fp, 0, SEEK_SET) != 0
                    642:            || fread(bootsector, sizeof(bootsector), 1, fp) != 1)
1.1.1.11  root      643:        {
1.1.1.17  root      644:                perror("HDC_PartitionCount");
                    645:                return 0;
1.1.1.11  root      646:        }
1.1       root      647: 
1.1.1.17  root      648:        if (bootsector[0x1FE] == 0x55 && bootsector[0x1FF] == 0xAA)
                    649:        {
                    650:                int ptype, boot;
1.1       root      651: 
1.1.1.17  root      652:                LOG_TRACE(tracelevel, "DOS MBR:\n");
                    653:                /* first partition table entry */
                    654:                pinfo = bootsector + 0x1BE;
                    655:                for (i = 0; i < 4; i++, pinfo += 16)
                    656:                {
                    657:                        boot = pinfo[0];
                    658:                        ptype = pinfo[4];
1.1.1.18! root      659:                        start = SDL_SwapLE32(*(long*)(pinfo+8));
        !           660:                        sectors = SDL_SwapLE32(*(long*)(pinfo+12));
1.1.1.17  root      661:                        total += sectors;
1.1.1.18! root      662:                        LOG_TRACE(tracelevel, "- Partition %d: type=0x%02x, start=0x%08x, size=%.1f MB %s%s\n",
        !           663:                                  i, ptype, start, sectors/2048.0, boot ? "(boot)" : "", sectors ? "" : "(invalid)");
1.1.1.17  root      664:                        if (ptype)
                    665:                                parts++;
                    666:                }
1.1.1.18! root      667:                LOG_TRACE(tracelevel, "- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
1.1.1.17  root      668:        }
                    669:        else
                    670:        {
                    671:                /* Partition table contains hd size + 4 partition entries
                    672:                 * (composed of flag byte, 3 char ID, start offset
                    673:                 * and size), this is followed by bad sector list +
                    674:                 * count and the root sector checksum. Before this
                    675:                 * there's the boot code.
                    676:                 */
                    677:                char c, pid[4];
                    678:                int j, flags;
1.1.1.18! root      679:                bool extended;
1.1.1.17  root      680: 
                    681:                LOG_TRACE(tracelevel, "ATARI MBR:\n");
                    682:                pinfo = bootsector + 0x1C6;
                    683:                for (i = 0; i < 4; i++, pinfo += 12)
                    684:                {
                    685:                        flags = pinfo[0];
                    686:                        for (j = 0; j < 3; j++)
                    687:                        {
                    688:                                c = pinfo[j+1];
                    689:                                if (c < 32 || c >= 127)
                    690:                                        c = '.';
                    691:                                pid[j] = c;
                    692:                        }
                    693:                        pid[3] = '\0';
1.1.1.18! root      694:                        extended = strcmp("XGM", pid) == 0;
1.1.1.17  root      695:                        start = HDC_ReadInt32(pinfo, 4);
                    696:                        sectors = HDC_ReadInt32(pinfo, 8);
1.1.1.18! root      697:                        LOG_TRACE(tracelevel,
        !           698:                                  "- Partition %d: ID=%s, start=0x%08x, size=%.1f MB, flags=0x%x %s%s\n",
        !           699:                                  i, pid, start, sectors/2048.0, flags,
        !           700:                                  (flags & 0x80) ? "(boot)": "",
        !           701:                                  extended ? "(extended)" : "");
1.1.1.17  root      702:                        if (flags & 0x1)
                    703:                                parts++;
                    704:                }
                    705:                total = HDC_ReadInt32(bootsector, 0x1C2);
1.1.1.18! root      706:                LOG_TRACE(tracelevel, "- Total size: %.1f MB in %d partitions\n", total/2048.0, parts);
1.1.1.17  root      707:        }
1.1       root      708: 
1.1.1.17  root      709:        if (fseeko(fp, offset, SEEK_SET) != 0)
                    710:                perror("HDC_PartitionCount");
                    711:        return parts;
1.1       root      712: }
                    713: 
1.1.1.17  root      714: /**
1.1.1.18! root      715:  * Check file size for sane values (non-zero, multiple of 512),
        !           716:  * and return the size
1.1.1.17  root      717:  */
1.1.1.18! root      718: off_t HDC_CheckAndGetSize(const char *filename)
1.1.1.17  root      719: {
                    720:        off_t filesize;
1.1.1.18! root      721:        char shortname[48];
1.1.1.17  root      722: 
1.1.1.18! root      723:        File_ShrinkName(shortname, filename, sizeof(shortname));
1.1.1.17  root      724: 
                    725:        filesize = File_Length(filename);
                    726:        if (filesize < 0)
                    727:        {
1.1.1.18! root      728:                Log_AlertDlg(LOG_ERROR, "Unable to get size of HD image file\n'%s'!",
        !           729:                             shortname);
        !           730:                if (sizeof(off_t) < 8)
        !           731:                {
        !           732:                        Log_Printf(LOG_ERROR, "Note: This version of Hatari has been built"
        !           733:                                              " _without_ support for large files,\n"
        !           734:                                              "      so you can not use HD images > 2 GB.\n");
        !           735:                }
        !           736:                return -EFBIG;
        !           737:        }
        !           738:        if (filesize == 0)
        !           739:        {
        !           740:                Log_AlertDlg(LOG_ERROR, "Can not use HD image file\n'%s'\n"
        !           741:                                        "since the file is empty.",
        !           742:                             shortname);
1.1.1.17  root      743:                return -EINVAL;
                    744:        }
1.1.1.18! root      745:        if ((filesize & 0x1ff) != 0)
1.1.1.17  root      746:        {
1.1.1.18! root      747:                Log_AlertDlg(LOG_ERROR, "Can not use the hard disk image file\n"
        !           748:                                        "'%s'\nsince its size is not a multiple"
        !           749:                                        " of 512.",
        !           750:                            shortname);
1.1.1.17  root      751:                return -EINVAL;
                    752:        }
                    753: 
1.1.1.18! root      754:        return filesize;
        !           755: }
        !           756: 
        !           757: /**
        !           758:  * Open a disk image file
        !           759:  */
        !           760: static int HDC_InitDevice(SCSI_DEV *dev, char *filename)
        !           761: {
        !           762:        off_t filesize;
        !           763:        FILE *fp;
        !           764: 
        !           765:        dev->enabled = false;
        !           766:        Log_Printf(LOG_INFO, "Mounting hard drive image '%s'\n", filename);
        !           767: 
        !           768:        /* Check size for sanity */
        !           769:        filesize = HDC_CheckAndGetSize(filename);
        !           770:        if (filesize < 0)
        !           771:                return filesize;
        !           772: 
1.1.1.17  root      773:        fp = fopen(filename, "rb+");
                    774:        if (fp == NULL)
                    775:        {
                    776:                Log_Printf(LOG_ERROR, "ERROR: cannot open HD file read/write!\n");
                    777:                return -ENOENT;
                    778:        }
                    779:        if (!File_Lock(fp))
                    780:        {
                    781:                Log_Printf(LOG_ERROR, "ERROR: cannot lock HD file for writing!\n");
                    782:                fclose(fp);
                    783:                return -ENOLCK;
                    784:        }
                    785: 
                    786:        dev->hdSize = filesize / 512;
                    787:        dev->image_file = fp;
                    788:        dev->enabled = true;
                    789: 
                    790:        return 0;
                    791: }
1.1.1.7   root      792: 
1.1.1.8   root      793: /**
                    794:  * Open the disk image file, set partitions.
1.1       root      795:  */
1.1.1.12  root      796: bool HDC_Init(void)
1.1       root      797: {
1.1.1.16  root      798:        int i;
1.1       root      799: 
1.1.1.17  root      800:        /* ACSI */
                    801:        nAcsiPartitions = 0;
1.1.1.16  root      802:        bAcsiEmuOn = false;
1.1.1.17  root      803:        memset(&AcsiBus, 0, sizeof(AcsiBus));
                    804:        AcsiBus.respbufsize = 512;
                    805:        AcsiBus.resp = malloc(AcsiBus.respbufsize);
                    806:        if (!AcsiBus.resp)
                    807:        {
                    808:                perror("HDC_Init");
                    809:                return false;
                    810:        }
1.1.1.16  root      811:        for (i = 0; i < MAX_ACSI_DEVS; i++)
1.1.1.7   root      812:        {
1.1.1.16  root      813:                if (!ConfigureParams.Acsi[i].bUseDevice)
                    814:                        continue;
1.1.1.17  root      815:                if (HDC_InitDevice(&AcsiBus.devs[i], ConfigureParams.Acsi[i].sDeviceFile) == 0)
1.1.1.16  root      816:                {
1.1.1.17  root      817:                        bAcsiEmuOn = true;
                    818:                        nAcsiPartitions += HDC_PartitionCount(AcsiBus.devs[i].image_file, TRACE_SCSI_CMD);
1.1.1.16  root      819:                }
1.1.1.17  root      820:        }
1.1.1.16  root      821: 
1.1.1.17  root      822:        /* SCSI */
                    823: #if WITH_NCR5380
                    824:        memset(&ScsiBus, 0, sizeof(ScsiBus));
                    825:        ScsiBus.respbufsize = 512;
                    826:        ScsiBus.resp = malloc(ScsiBus.respbufsize);
                    827:        if (!ScsiBus.resp)
                    828:        {
                    829:                perror("HDC_Init");
                    830:                return bAcsiEmuOn;
                    831:        }
                    832:        for (i = 0; i < MAX_SCSI_DEVS; i++)
                    833:        {
                    834:                if (!ConfigureParams.Scsi[i].bUseDevice)
1.1.1.16  root      835:                        continue;
1.1.1.17  root      836:                HDC_InitDevice(&ScsiBus.devs[i], ConfigureParams.Scsi[i].sDeviceFile);
1.1.1.16  root      837:        }
1.1.1.17  root      838: #endif
1.1.1.7   root      839: 
                    840:        /* set number of partitions */
1.1.1.17  root      841:        nNumDrives += nAcsiPartitions;
1.1.1.7   root      842: 
1.1.1.16  root      843:        return bAcsiEmuOn;
1.1       root      844: }
1.1.1.3   root      845: 
1.1.1.7   root      846: 
1.1       root      847: /*---------------------------------------------------------------------*/
1.1.1.8   root      848: /**
                    849:  * HDC_UnInit - close image file
                    850:  *
1.1       root      851:  */
1.1.1.4   root      852: void HDC_UnInit(void)
1.1       root      853: {
1.1.1.16  root      854:        int i;
                    855: 
1.1.1.18! root      856:        for (i = 0; bAcsiEmuOn && i < MAX_ACSI_DEVS; i++)
1.1.1.16  root      857:        {
                    858:                if (!AcsiBus.devs[i].enabled)
                    859:                        continue;
1.1.1.17  root      860:                File_UnLock(AcsiBus.devs[i].image_file);
1.1.1.16  root      861:                fclose(AcsiBus.devs[i].image_file);
                    862:                AcsiBus.devs[i].image_file = NULL;
                    863:                AcsiBus.devs[i].enabled = false;
                    864:        }
1.1.1.17  root      865:        free(AcsiBus.resp);
                    866:        AcsiBus.resp = NULL;
1.1.1.7   root      867: 
1.1.1.17  root      868: #if WITH_NCR5380
                    869:        for (i = 0; i < MAX_SCSI_DEVS; i++)
                    870:        {
                    871:                if (!ScsiBus.devs[i].enabled)
                    872:                        continue;
                    873:                File_UnLock(ScsiBus.devs[i].image_file);
                    874:                fclose(ScsiBus.devs[i].image_file);
                    875:                ScsiBus.devs[i].image_file = NULL;
                    876:                ScsiBus.devs[i].enabled = false;
                    877:        }
                    878:        free(ScsiBus.resp);
                    879:        ScsiBus.resp = NULL;
                    880: #endif
                    881: 
1.1.1.18! root      882:        if (bAcsiEmuOn)
        !           883:                nNumDrives -= nAcsiPartitions;
1.1.1.17  root      884:        nAcsiPartitions = 0;
1.1.1.11  root      885:        bAcsiEmuOn = false;
1.1       root      886: }
                    887: 
1.1.1.7   root      888: 
1.1       root      889: /*---------------------------------------------------------------------*/
1.1.1.8   root      890: /**
1.1.1.14  root      891:  * Reset command status.
                    892:  */
                    893: void HDC_ResetCommandStatus(void)
                    894: {
1.1.1.18! root      895:        if (!Config_IsMachineFalcon())
1.1.1.16  root      896:                AcsiBus.returnCode = 0;
1.1.1.14  root      897: }
                    898: 
                    899: 
                    900: /**
1.1.1.16  root      901:  * Process HDC command packets (SCSI/ACSI) bytes.
1.1.1.17  root      902:  * @return true if command has been executed.
1.1.1.14  root      903:  */
1.1.1.17  root      904: static bool HDC_WriteCommandPacket(SCSI_CTRLR *ctr, Uint8 b)
1.1.1.14  root      905: {
1.1.1.17  root      906:        bool bDidCmd = false;
1.1.1.16  root      907:        SCSI_DEV *dev = &ctr->devs[ctr->target];
                    908: 
                    909:        /* Abort if the target device is not enabled */
                    910:        if (!dev->enabled)
                    911:        {
                    912:                ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17  root      913:                return false;
1.1.1.16  root      914:        }
                    915: 
                    916:        /* Extract ACSI/SCSI opcode */
                    917:        if (ctr->byteCount == 0)
                    918:        {
                    919:                ctr->opcode = b;
                    920:                ctr->bDmaError = false;
                    921:        }
1.1.1.14  root      922: 
1.1.1.16  root      923:        /* Successfully received one byte, and increase the byte-count */
                    924:        if (ctr->byteCount < (int)sizeof(ctr->command))
                    925:                ctr->command[ctr->byteCount] = b;
                    926:        ++ctr->byteCount;
                    927: 
                    928:        /* have we received a complete 6-byte class 0 or 10-byte class 1 packet yet? */
                    929:        if ((ctr->opcode < 0x20 && ctr->byteCount >= 6) ||
                    930:            (ctr->opcode < 0x60 && ctr->byteCount >= 10))
                    931:        {
                    932:                /* We currently only support LUN 0, however INQUIRY must
                    933:                 * always be handled, see SCSI standard */
                    934:                if (HDC_GetLUN(ctr) == 0 || ctr->opcode == HD_INQUIRY)
                    935:                {
                    936:                        HDC_EmulateCommandPacket(ctr);
1.1.1.17  root      937:                        bDidCmd = true;
1.1.1.16  root      938:                }
                    939:                else
                    940:                {
                    941:                        Log_Printf(LOG_WARN, "HDC: Access to non-existing LUN."
                    942:                                   " Command = 0x%02x\n", ctr->opcode);
                    943:                        dev->nLastError = HD_REQSENS_INVLUN;
                    944:                        /* REQUEST SENSE is still handled for invalid LUNs */
                    945:                        if (ctr->opcode == HD_REQ_SENSE)
1.1.1.17  root      946:                        {
1.1.1.16  root      947:                                HDC_Cmd_RequestSense(ctr);
1.1.1.17  root      948:                                bDidCmd = true;
                    949:                        }
1.1.1.16  root      950:                        else
1.1.1.17  root      951:                        {
1.1.1.16  root      952:                                ctr->returnCode = HD_STATUS_ERROR;
1.1.1.17  root      953:                        }
1.1.1.16  root      954:                }
                    955: 
                    956:                ctr->byteCount = 0;
                    957:        }
                    958:        else if (ctr->opcode >= 0x60)
                    959:        {
                    960:                /* Commands >= 0x60 are not supported right now */
                    961:                ctr->returnCode = HD_STATUS_ERROR;
                    962:                dev->nLastError = HD_REQSENS_OPCODE;
                    963:                dev->bSetLastBlockAddr = false;
                    964:                if (ctr->byteCount == 10)
                    965:                {
                    966:                        LOG_TRACE(TRACE_SCSI_CMD, "HDC: Unsupported command (%s).\n",
                    967:                                  HDC_CmdInfoStr(ctr));
                    968:                }
                    969:        }
                    970:        else
                    971:        {
                    972:                ctr->returnCode = HD_STATUS_OK;
                    973:        }
1.1.1.17  root      974: 
                    975:        return bDidCmd;
1.1.1.16  root      976: }
1.1.1.14  root      977: 
                    978: /*---------------------------------------------------------------------*/
1.1.1.16  root      979: 
                    980: static struct ncr5380_regs
                    981: {
                    982:        Uint8 initiator_cmd;
                    983:        Uint8 current_bus_status;
                    984:        Uint8 bus_and_status;
                    985: } ncr_regs;
                    986: 
1.1.1.14  root      987: /**
1.1.1.16  root      988:  * Emulate external reset "pin": Clear registers etc.
1.1.1.14  root      989:  */
1.1.1.16  root      990: void Ncr5380_Reset(void)
1.1.1.14  root      991: {
1.1.1.16  root      992:        ncr_regs.initiator_cmd &= 0x7f;
1.1.1.14  root      993: }
                    994: 
                    995: /**
1.1.1.16  root      996:  * Write a command byte to the NCR 5380 SCSI controller
1.1.1.8   root      997:  */
1.1.1.16  root      998: static void Ncr5380_WriteByte(int addr, Uint8 byte)
1.1       root      999: {
1.1.1.17  root     1000: #if WITH_NCR5380
1.1.1.16  root     1001:        switch (addr)
1.1.1.14  root     1002:        {
1.1.1.16  root     1003:        case 0:                 /* Output Data register */
                   1004:                ncr_regs.current_bus_status |= 0x40;
                   1005:                break;
                   1006:        case 1:                 /* Initiator Command register */
                   1007:                ncr_regs.initiator_cmd = byte;
                   1008:                break;
                   1009:        case 2:                 /* Mode register */
                   1010:                break;
                   1011:        case 3:                 /* Target Command register */
                   1012:                break;
                   1013:        case 4:                 /* Select Enable register */
                   1014:                break;
                   1015:        case 5:                 /* Start DMA Send register */
                   1016:                break;
                   1017:        case 6:                 /* Start DMA Target Receive register */
                   1018:                break;
                   1019:        case 7:                 /* Start DMA Initiator Receive register */
                   1020:                break;
                   1021:        default:
                   1022:                fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.14  root     1023:        }
1.1.1.17  root     1024: #endif
1.1.1.16  root     1025: }
1.1.1.12  root     1026: 
1.1.1.16  root     1027: /**
                   1028:  * Read a command byte from the NCR 5380 SCSI controller
                   1029:  */
                   1030: static Uint8 Ncr5380_ReadByte(int addr)
                   1031: {
1.1.1.17  root     1032: #if WITH_NCR5380
1.1.1.16  root     1033:        switch (addr)
1.1.1.12  root     1034:        {
1.1.1.16  root     1035:        case 0:                 /* Current SCSI Data register */
                   1036:                break;
                   1037:        case 1:                 /* Initiator Command register */
                   1038:                return ncr_regs.initiator_cmd & 0x9f;
                   1039:        case 2:                 /* Mode register */
                   1040:                break;
                   1041:        case 3:                 /* Target Command register */
                   1042:                break;
                   1043:        case 4:                 /* Current SCSI Bus Status register */
                   1044:                if (ncr_regs.current_bus_status & 0x40) /* BUSY? */
                   1045:                        ncr_regs.current_bus_status |= 0x20;
                   1046:                else
                   1047:                        ncr_regs.current_bus_status &= ~0x20;
                   1048:                if (ncr_regs.initiator_cmd & 0x80)      /* ASSERT RST? */
                   1049:                        ncr_regs.current_bus_status |= 0x80;
                   1050:                else
                   1051:                        ncr_regs.current_bus_status &= ~0x80;
                   1052:                if (ncr_regs.initiator_cmd & 0x04)      /* ASSERT BUSY? */
                   1053:                        ncr_regs.current_bus_status |= 0x40;
                   1054:                else
                   1055:                        ncr_regs.current_bus_status &= ~0x40;
                   1056:                return ncr_regs.current_bus_status;
                   1057:        case 5:                 /* Bus and Status register */
                   1058:                return ncr_regs.bus_and_status;
                   1059:        case 6:                 /* Input Data register */
                   1060:                break;
                   1061:        case 7:                 /* Reset Parity/Interrupts register */
                   1062:                /* Reset PARITY ERROR, IRQ REQUEST and BUSY ERROR bits */
                   1063:                ncr_regs.bus_and_status &= 0xcb;
                   1064:                return 0;  /* TODO: Is this return value ok? */
                   1065:        default:
                   1066:                fprintf(stderr, "Unexpected NCR5380 address\n");
1.1.1.12  root     1067:        }
1.1.1.17  root     1068: #endif
1.1.1.12  root     1069: 
1.1.1.16  root     1070:        return 0;
                   1071: }
1.1.1.7   root     1072: 
1.1.1.16  root     1073: 
                   1074: static void Acsi_WriteCommandByte(int addr, Uint8 byte)
                   1075: {
1.1.1.17  root     1076:        /* Clear IRQ initially (will be set again if byte has been accepted) */
                   1077:        FDC_ClearHdcIRQ();
                   1078: 
                   1079:        /* When the A1 pin is pushed to 0, we want to start a new command.
                   1080:         * We ignore the pin for the second byte in the packet since this
                   1081:         * seems to happen on real hardware too (some buggy driver relies
                   1082:         * on this behavior). */
                   1083:        if ((addr & 2) == 0 && AcsiBus.byteCount != 1)
1.1.1.7   root     1084:        {
1.1.1.16  root     1085:                AcsiBus.byteCount = 0;
                   1086:                AcsiBus.target = ((byte & 0xE0) >> 5);
                   1087:                /* Only process the first byte if it is not
                   1088:                 * an extended ICD command marker byte */
                   1089:                if ((byte & 0x1F) != 0x1F)
1.1.1.7   root     1090:                {
1.1.1.16  root     1091:                        HDC_WriteCommandPacket(&AcsiBus, byte & 0x1F);
1.1.1.7   root     1092:                }
                   1093:                else
                   1094:                {
1.1.1.16  root     1095:                        AcsiBus.returnCode = HD_STATUS_OK;
                   1096:                        AcsiBus.bDmaError = false;
1.1.1.7   root     1097:                }
1.1.1.16  root     1098:        }
                   1099:        else
                   1100:        {
                   1101:                /* Process normal command byte */
1.1.1.17  root     1102:                bool bDidCmd = HDC_WriteCommandPacket(&AcsiBus, byte);
                   1103:                if (bDidCmd && AcsiBus.returnCode == HD_STATUS_OK && AcsiBus.respcnt)
                   1104:                {
                   1105:                        /* DMA transfer necessary */
                   1106:                        Uint32 nDmaAddr = FDC_GetDMAAddress();
                   1107:                        if (!STMemory_SafeCopy(nDmaAddr, AcsiBus.resp, AcsiBus.respcnt, "ACSI DMA"))
                   1108:                        {
                   1109:                                AcsiBus.bDmaError = true;
                   1110:                                AcsiBus.returnCode = HD_STATUS_ERROR;
                   1111:                        }
                   1112:                        FDC_WriteDMAAddress(nDmaAddr + AcsiBus.respcnt);
                   1113:                        AcsiBus.respcnt = 0;
                   1114:                }
1.1.1.16  root     1115:        }
1.1.1.7   root     1116: 
1.1.1.16  root     1117:        if (AcsiBus.devs[AcsiBus.target].enabled)
                   1118:        {
                   1119:                FDC_SetDMAStatus(AcsiBus.bDmaError);    /* Mark DMA error */
                   1120:                FDC_SetIRQ(FDC_IRQ_SOURCE_HDC);
1.1.1.7   root     1121:        }
1.1       root     1122: }
1.1.1.16  root     1123: 
                   1124: /**
                   1125:  * Called when command bytes have been written to $FFFF8606 and
                   1126:  * the HDC (not the FDC) is selected.
                   1127:  */
                   1128: void HDC_WriteCommandByte(int addr, Uint8 byte)
                   1129: {
                   1130:        // fprintf(stderr, "HDC: Write cmd byte addr=%i, byte=%02x\n", addr, byte);
                   1131: 
1.1.1.18! root     1132:        if (Config_IsMachineFalcon())
1.1.1.16  root     1133:                Ncr5380_WriteByte(addr, byte);
                   1134:        else if (bAcsiEmuOn)
                   1135:                Acsi_WriteCommandByte(addr, byte);
                   1136: }
                   1137: 
                   1138: /**
                   1139:  * Get command byte.
                   1140:  */
                   1141: short int HDC_ReadCommandByte(int addr)
                   1142: {
                   1143:        Uint16 ret;
1.1.1.18! root     1144:        if (Config_IsMachineFalcon())
1.1.1.16  root     1145:                ret = Ncr5380_ReadByte(addr);
                   1146:        else
                   1147:                ret = AcsiBus.returnCode;       /* ACSI status */
                   1148:        return ret;
                   1149: }

unix.superglobalmegacorp.com

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