gonzui


Format: Advanced Search

tkernel_2/driver/tef_em1d/sysdsk/src/ata.cbare sourcepermlink (0.10 seconds)

Search this content:

    1: /*
    2:  *----------------------------------------------------------------------
    3:  *    T-Kernel 2.0 Software Package
    4:  *
    5:  *    Copyright 2011 by Ken Sakamura.
    6:  *    This software is distributed under the latest version of T-License 2.x.
    7:  *----------------------------------------------------------------------
    8:  *
    9:  *    Released by T-Engine Forum(http://www.t-engine.org/) at 2011/05/17.
   10:  *    Modified by T-Engine Forum at 2014/09/10.
   11:  *    Modified by TRON Forum(http://www.tron.org/) at 2015/06/01.
   12:  *
   13:  *----------------------------------------------------------------------
   14:  */
   15: 
   16: 
   17: /*
   18:  *      ata.c                System disk driver
   19:  *
   20:  *      ATA Disk access processing
   21:  */
   22: 
   23: #include "sdisk.h"
   24: #include "ata.h"
   25: 
   26: /*
   27:  *      Drive initialization
   28:  */
   29: LOCAL   void      ataDriveInit(DrvTab *drv)
   30: {
   31:         ER     er;
   32: 
   33:         /* Since power has been just turned ON, wait for a while until it become ready status  */
   34:         ataWaitReady(drv);
   35: 
   36:         /* Issue "SET MULTIPLE" command when "MULTIPLE" command is valid. */
   37:         if (drv->MultiCnt >= 2) {
   38:                 /* Output the "SET MULTIPLE" command */
   39:                 er = ataCmd(drv, ATA_SETMULTI, 0, 0, NULL);
   40:                 if (er < E_OK) drv->MultiCnt = 0;
   41:         }
   42: 
   43:         /* Release the drive's reset status */
   44:         drv->Reset = FALSE;
   45: }
   46: 
   47: /*
   48:  *      The actual read-in/writing of disk block
   49:  *              "buf == NULL" at the time of "FORMAT"
   50:  *              return      The number of processed blocks
   51:  */
   52: LOCAL   INT       ataRWblks(DrvTab *drv, W blk, W cnt, void *buf, W cmd)
   53: {
   54:         ER     er;
   55:         W      nblks, nsec, maxlen;
   56: 
   57: #define WRKBUFSZ        (64 * 1024)
   58: 
   59:         /* Read-in/Write every "MAX_IOSEC" for the number of the requested blocks */
   60: 
   61:         ataSelDrv(drv);                /* Wait-for-interrupt setting */
   62: 
   63:         /* Reinitialize drive : response to the power-OFF status */
   64:         if (drv->Reset) ataDriveInit(drv);
   65: 
   66:         maxlen = MAX_IOSEC * ATA_SECSZ;
   67: 
   68:         /* The maximum number of sectors at one time transfer */
   69:         maxlen /= drv->SecSize;
   70:         er = E_OK;
   71: 
   72:         for (nblks = 0; cnt > 0; cnt -= nsec) {
   73:                 /* The number of processing request sectors */
   74:                 if ((nsec = cnt) > maxlen) nsec = maxlen;
   75: 
   76:                 er = ataCmd(drv, cmd, blk, nsec, buf);
   77:                 if (er < E_OK) break;
   78: 
   79:                 nblks += nsec;
   80:                 blk += nsec;
   81:                 if (buf != NULL) buf += nsec * drv->SecSize;
   82:         }
   83:         return (er < E_OK) ? er  : nblks;
   84: }
   85: 
   86: /*
   87:  *      The read-in/writing of the disk block
   88:  */
   89: EXPORT  INT      ataReadWrite(DrvTab *drv, W blk, W cnt, void *mptr, BOOL write)
   90: {
   91:         /* The validity of "blk" and "cnt" is already checked (cnt > 0) */
   92: 
   93:         /* The actual Reading/writing of the disk block */
   94:         return ataRWblks(drv, blk, cnt, mptr, (write) ? ATA_WRITE : ATA_READ);
   95: }
   96: 
   97: /*
   98:  *      Format processing
   99:  *              ATA's format commander is vendor definition, and
  100:  *              the refraining from using is recommended.
  101:  *              Therefore, specific data shall be written in format processing
  102:  */
  103: EXPORT  ER       ataFormat(DrvTab *drv, DiskFormat *fmt, W dcnt)
  104: {
  105:         ER     er;
  106:         W      blk, cnt, nfm;
  107: 
  108:         nfm = *fmt;
  109:         if (nfm != DiskFmt_STD) return E_PAR;
  110: 
  111:         /* Start block & The number of the blocks */
  112:         blk = drv->s.SUnit[drv->CurSUnit].StartBlock;
  113:         cnt = drv->s.SUnit[drv->CurSUnit].EndBlock - blk;
  114:         if (cnt <= 0) return E_PAR;
  115: 
  116:         /* Initialize the number of the valid units in the case of physical unit */
  117:         if (drv->CurSUnit == 0) drv->nSUnit = 0;
  118: 
  119:         /* Actual writing of the disk block */
  120:         er = ataRWblks(drv, blk, cnt, NULL, ATA_WRITE);
  121:         return (er >= E_OK) ? E_OK : er;
  122: }
  123: 
  124: /*
  125:  *      Set the CHS information to be notified to external :
  126:  *              Calculate CHS for "BIOS"setting by "Phoenix method"
  127:  *              (Increase the number of heads by "2 ** n" times so that "the number of cylinders <= 1024" is available)
  128:  */
  129: EXPORT  W        ataSetXCHS(DrvTab *drv)
  130: {
  131:         W      xt, xc, xh, xs;
  132: 
  133:         /* Set the actual "IDE" */
  134:         xc = drv->nCyl;
  135:         xh = drv->nHead;
  136:         xs = drv->nSec;
  137:         xt = xc * xh * xs;
  138: 
  139:         /* Adjust the number of heads so that "the number of cylinders <= 1024" is available */
  140:         while (xc > 1024) {xc >>= 1; xh <<= 1;}
  141: 
  142:         if (xs > 63) xs = 63;                  /* The number of sectors <= 63 */
  143:         if (xh > 255) xh = 255;                        /* The number of heads <= 255        */
  144:         if (xt != 0) xc = xt / xh / xs;
  145:         if (xc > 1024) xc = 1024;              /* The number of cylinders <= 1024  */
  146:         if (xc > 0) xc--;                      /* The last cylinder is unused     */
  147: 
  148:         /* CHS information to be notified to external */
  149:         drv->nXSec = xs;
  150:         drv->nXHead = xh;
  151:         drv->nXCyl = xc;
  152:         return xc * xh * xs;
  153: }
  154: 
  155: /*
  156:  *      Reading of disk information
  157:  */
  158: EXPORT  ER       ataIdentify(DrvTab *drv, BOOL check)
  159: {
  160:         ER     er;
  161:         W      cyl, head, sec, tsec, n, i;
  162:         BOOL   uselba;
  163:         UH     buf[ATA_SECSZ / sizeof(UH)];
  164: 
  165:         /* Set drive */
  166:         for (n = 0; (er = ataSetDrive(drv, -1)) != E_OK; n++) {
  167:                 /* Ignore errors because it might not be the ready-status yet
  168:                                 when PC card is inserted */
  169:                 if (drv->Spec.pccard) break;
  170: 
  171:                 /* Reset and re-try it when it is not PC card */
  172:                 if (n != 0) goto E_EXIT;
  173:                 ataReset(drv);
  174:         }
  175: 
  176:         /* Since power has been just turned ON, wait for a while until it become ready status */
  177:         if ((er = ataWaitReady(drv)) != E_OK) goto E_EXIT;
  178: 
  179:         /* Wait-for-interrupt setting */
  180:         ataSelDrv(drv);
  181: 
  182:         /* "IDENTIFY" command output */
  183:         for (;;) {
  184:                 er = ataCmd(drv, ATA_IDENTIFY, 0, 1, (void*)buf);
  185:                 if (er >= E_OK) break;
  186:                 goto E_EXIT;
  187:         }
  188: 
  189:         /* Move the necessary data that follows "IDENT_DTSZ"   */
  190:         buf[2] = buf[49];
  191:         buf[4] = buf[80];
  192:         buf[5] = CnvLeH(buf[53]) & 0x00FF;     /* Upper level is the internal flag */
  193:         buf[7] = buf[54];
  194:         buf[8] = buf[55];
  195:         buf[9] = buf[56];
  196:         buf[20] = buf[60];
  197:         buf[21] = buf[61];
  198:         buf[22] = 0;                           /* DMA No Support */
  199:         buf[127] = 0;                          /* MSN No Support */
  200:         buf[5] = CnvLeH(buf[5]);
  201: 
  202:         tsec = 0;
  203:         drv->DiskFmt = DiskFmt_STD;
  204:         drv->SecSize = ATA_SECSZ;
  205:         drv->SecBias = 0;
  206: 
  207:         /* Set the number of sectors for "R/W- MULTIPLE" : any of  0,2,4,8,16,and 32 */
  208:         n = CnvLeH(buf[47]) & 0xFF;            /* Maximum value */
  209:         for (i = 32; i > n; i >>= 1);
  210:         drv->MultiCnt = (i > 1) ? i : 0;
  211:         drv->DiskFmt = DiskFmt_STD;
  212: 
  213:         /* Initialize the drive */
  214:         drv->MediaOK = TRUE;
  215:         ataDriveInit(drv);
  216: 
  217:         if (check) {   /* Check whether it is same as before or not :
  218:                 Compare the absence or presence of media, write-protect, and ID data */
  219:                 if (!drv->MediaOK ||
  220:                     drv->Wprotect != drv->Spec.readonly ||
  221:                     MEMCMP((void*)drv->Ident, (void*)&buf[0], IDENT_DTSZ) != 0) {
  222:                         er = ERR_NOTSAME;
  223:                         goto E_EXIT;
  224:                 }
  225:                 return E_OK;
  226:         }
  227: 
  228:         /* Save ID data */
  229:         MEMCPY((void*)drv->Ident, (void*)&buf[0], IDENT_DTSZ);
  230: 
  231:         /* Set write-protect */
  232:         if (!drv->Spec.wlock) drv->Spec.readonly = drv->Wprotect;
  233: 
  234:         sec = head = cyl = 0;
  235: 
  236:         if (!drv->MediaOK) {           /* There is no media     */
  237:                 tsec = 0              ;
  238:                 uselba = FALSE;               /* It is meaninless, however... */
  239: 
  240:         } else {                       /* ATA device*/
  241:                 /* Fetch the information of "Cyl", "Head", and "Sec"  */
  242:                 cyl  = CnvLeH(buf[1]);                        /* The number of cylinders   */
  243:                 head = CnvLeH(buf[3]);                        /* The number of heads       */
  244:                 sec = CnvLeH(buf[6]);                 /* The number of sectors */
  245:                 tsec = cyl * head * sec;              /* The total number of sectors      */
  246: 
  247:                 n = CnvLeH(buf[80]);
  248:                 if ((n & ~0x7FFE) == 0 && n >= (1 << 3)) {
  249:                         uselba = TRUE;               /* ATA-3 or more : LBA OK */
  250:                 } else {
  251:                         uselba = (CnvLeH(buf[49]) & 0x200) ? TRUE : FALSE;
  252:                 }
  253: 
  254:                 if (uselba) {
  255:                         /* When LBA is used, checking shall be required on
  256:                 whether "Total Number of Sectors on LBA [60][61]" is correctly set or not */
  257:                         n = CnvLeW(*((UW*)&buf[60]));
  258:                         if (tsec == n || tsec ==
  259:                                 (((n >> 16) & 0xFFFF)|((n & 0xFFFF) << 16))) {
  260:                                 ;   /* OK */
  261:                         } else if (n < tsec) {
  262:                                 uselba = FALSE;             /* Illegal */
  263: 
  264:                         } else if (tsec > 1032192) {
  265:                                 tsec = n;   /* Actual total number of sectors */
  266:                                 cyl = n / head / sec;       /* The actual number of "Cyl"s */
  267:                                 if (cyl > 32767) cyl = 32767;
  268: 
  269:                         } else if (tsec == 0 && n > 16514064) {
  270:                                 tsec = n;   /* The actual number of sectors */
  271:                                 /* Set "CHS" as a matter of convenience though it is unsupported */
  272:                                 cyl = 16383; head = 15; sec = 63;
  273:                         }
  274:                 }
  275: 
  276:                 /* Use "CHS" when "LBA" is unused (translation mode) */
  277:                 if (!uselba && (CnvLeH(buf[53]) & 0x1) != 0) {
  278:                         cyl = CnvLeH(buf[54]);               /* The number of the current cylinders       */
  279:                         head = CnvLeH(buf[55]);              /* The number of the current heads  */
  280:                         sec = CnvLeH(buf[56]);               /* The number of the current sectors */
  281:                         tsec = cyl * head * sec;     /* The total number of sectors      */
  282:                 }
  283:         }
  284: 
  285:         drv->UseLBA = uselba;                  /* Use "LBA"   */
  286: 
  287:         /* Set "CHS" information to be used internally */
  288:         drv->nSec = sec;                       /* The number of sectors / head */
  289:         drv->nHead = head;                     /* The number of heads / cylinder */
  290:         drv->nCyl = cyl;                       /* The number of cylinders          */
  291: 
  292:         /* Set physical unit information */
  293:         drv->s.SUnit[0].SystemId = DSID_NONE;
  294:         drv->s.SUnit[0].StartBlock = 0;
  295:         drv->s.SUnit[0].EndBlock = tsec;
  296:         drv->s.SUnit[0].OpenCnt = 0;
  297: 
  298:         /* Set "CHS" information (tentative) to be notified to outside  */
  299:         tsec = ataSetXCHS(drv);
  300:         drv->SetXCHS = FALSE;
  301: 
  302:         if (drv->MediaOK) {
  303:                 if (drv->s.SUnit[0].EndBlock <= 0 || tsec <= 0) {
  304:                         er = ERR_NOBLK;
  305:                         goto E_EXIT;
  306:                 }
  307:         }
  308:         return E_OK;
  309: 
  310: E_EXIT:
  311:         /* Set it to drive 0 to make sure */
  312:         ataSetDrive(drv, 0);
  313:         return er;
  314: }
  315: 
  316: /*
  317:  *      Set the partition information (MBR)
  318:  */
  319: EXPORT  ER       ataSetupPart(DrvTab *drv)
  320: {
  321:         ER     er;
  322:         W      i, n, k;
  323:         UW     sblk, eblk;
  324:         UB     buf[ATA_SECSZ];
  325:         PartTab        *part;
  326:         W      xCyl, xSec, xHead;
  327: 
  328:         /* Confirm the sector size */
  329:         /* if (drv->SecSize != ATA_SECSZ) return ERR_MEDIA; */
  330: 
  331:         /* The number of the sectors and heads in BIOS setting */
  332:         xSec = xHead = 0;
  333: 
  334:         /* Reading of master boot block */
  335:         if ((er = (*drv->ReadWrite)(drv, 0, 1, (void*)buf, FALSE))
  336:                                                         < E_OK) return er;
  337: 
  338:         /* Check the validity of boot block */
  339:         if (*((UH*)&buf[OFS_SIGN]) != VALID_SIGN) {
  340: 
  341:                 /* Consider it as the unused partition table */
  342:                 MEMSET((void*)buf, 0, SIZE_PARTTAB);
  343: 
  344:         } else {
  345:                 /* Move the partition table to adjust to the word align */
  346:                 MEMMOVE((void*)buf, (void*)&buf[OFS_PART], SIZE_PARTTAB);
  347:         }
  348: 
  349:         part = (PartTab*)buf;
  350: 
  351:         /* Set the unit information according to partition information:
  352:                         Simply register in order of partition information */
  353: 
  354:         for (i = n = 0; i < N_PART; i++) {
  355:                 sblk = part[i].StartBlock;
  356:                 sblk = CnvLeW(sblk);
  357:                 eblk = part[i].BlockCnt;
  358:                 eblk = sblk + CnvLeW(eblk);
  359: 
  360:                 if (part[i].SysInd == DSID_NONE) {
  361: INVALID_PART:
  362:                         /* Register it as the unused partition  */
  363:                         if (n < MAX_PART) {
  364:                                 drv->s.SUnit[++n].SystemId = DSID_NONE;
  365:                                 drv->s.SUnit[n].StartBlock = 0;
  366:                                 drv->s.SUnit[n].EndBlock = 0;
  367:                                 drv->s.SUnit[n].OpenCnt = 0;
  368:                         }
  369:                         continue;
  370:                 }
  371: 
  372:                 /* Check whether it is illegal or not */
  373:                 if (sblk >= eblk || eblk > drv->s.SUnit[0].EndBlock) {
  374:                         goto INVALID_PART;
  375:                 }
  376: 
  377:                 /* Check the duplication of the already registered partition */
  378:                 for (k = n; k > 0; k--) {
  379:                         if (sblk < drv->s.SUnit[k].EndBlock &&
  380:                             eblk > drv->s.SUnit[k].StartBlock) break;
  381:                 }
  382:                 if (k > 0) {  /* There is duplication */
  383:                         goto INVALID_PART;
  384:                 }
  385:                 /* There is no duplication: Register */
  386:                 if (n < MAX_PART) {
  387:                         drv->s.SUnit[++n].SystemId = part[i].SysInd;
  388:                         drv->s.SUnit[n].StartBlock = sblk;
  389:                         drv->s.SUnit[n].EndBlock = eblk;
  390:                         drv->s.SUnit[n].OpenCnt = 0;
  391: 
  392:                         /* Seek the number of sectors and heads in "BIOS" setting
  393:                 from the partition setting (cylinder align) */
  394:                         if (xSec == 0) {
  395:                                 xSec = part[i].EndSec & 0x3F;
  396:                                 xHead = (UH)part[i].EndHead + 1;
  397:                                 xCyl = (UH)part[i].EndCyl + 1 +
  398:                                         (((UH)part[i].EndSec & 0xC0) << 2);
  399:                                 if ((k = xSec * xHead) != 0) {
  400:                                         k = ((eblk % k) != 0) ? 0 : eblk / k;
  401:                                 }
  402:                                 if (xCyl != 1024 && xCyl != k && xCyl != k - 1)
  403:                                         xSec = -1; /* Illegal */
  404:                         } else if (xSec > 0) {
  405:                                 if (xSec != (part[i].EndSec & 0x3F) ||
  406:                                     xHead != ((UH)part[i].EndHead + 1))
  407:                                         xSec = -1; /* Illegal */
  408:                         }
  409:                 }
  410:         }
  411:         /* Set the number of valid units */
  412:         drv->nSUnit = n;
  413: 
  414:         /* Reset the CHS information to be notified to outside by prioritizing the partition setting information */
  415:         if (!drv->SetXCHS) {
  416:                 if (xSec > 0) {
  417:                         drv->nXSec = xSec;
  418:                         drv->nXHead = xHead;
  419:                         drv->nXCyl = (drv->nCyl * drv->nHead * drv->nSec) /
  420:                                 xHead / xSec - 1;  /* Last cylinder is unused */
  421:                         if (drv->nXCyl >= 1024) drv->nXCyl = 1023;
  422:                 }
  423:                 drv->SetXCHS = TRUE;
  424:         }
  425:         return E_OK;
  426: }
  427: 
  428: /*
  429:  *      Disk initialization (set the partition information)
  430:  */
  431: EXPORT  ER       ataDiskInit(DrvTab *drv)
  432: {
  433:         ER     er;
  434: 
  435:         /* Initialize the number of valid units */
  436:         drv->nSUnit = 0;
  437:         drv->CurSUnit = 0;
  438: 
  439:         /* "DISKMBR" is unsupported */
  440:         drv->SuptMBR = FALSE;
  441: 
  442:         if (drv->Aborted) {
  443:                 /* No processing shall be executed when there is already an abort request :
  444:                         Response to the case where format is aborted. */
  445:                 er = ERR_ABORT;
  446: 
  447:         } else if (!drv->MediaOK) {
  448:                 er = ERR_NOMEDIA;     /* There is no media */
  449: 
  450:         } else if (drv->SecSize != ATA_SECSZ) {
  451:                 er = ERR_BLKSZ;               /* Illegal block size */
  452: 
  453:         } else {                       /* HD */
  454:                 /* Set the partition information (MBR)  */
  455:                 er = ataSetupPart(drv);
  456:                 if (er == E_OK) drv->SuptMBR = TRUE;  /* "DISKMBR" support*/
  457:         }
  458:         if (er < E_OK) goto E_EXIT;
  459: 
  460:         return E_OK;
  461: 
  462: E_EXIT:
  463:         return er;
  464: }
  465: 
  466: /*
  467:  *      The open/close processings
  468:  */
  469: LOCAL   void      ataOpenClose(DrvTab *drv, W cmd)
  470: {
  471:         switch(cmd) {
  472:         case DC_OPEN:          /* Open processing */
  473:                 /* Check the injectable media in the case of physical unit */
  474:                 break;
  475: 
  476:         case DC_CLOSE:         /* Close processing */
  477:         case DC_CLOSEALL:
  478:                 ataSelDrv(drv);               /* Wait-for-interrupt setting        */
  479:         }
  480: }
  481: 
  482: /*
  483:  *      Various processings
  484:  */
  485: EXPORT  ER       ataMisc(DrvTab *drv, W cmd)
  486: {
  487:         switch(cmd) {
  488:         case DC_TSKINIT:       /* Task initialization processing(Top "drv")  */
  489:         case DC_TSKTMO:                /* Task time-out processing      (Top "drv")  */
  490:         case DC_DRVCHG:                /* Drive change processing       (Top "drv")  */
  491:                 break;
  492: 
  493:         case DC_OPEN:          /* Open processing               (Top "drv")        */
  494:         case DC_CLOSE:         /* Close processing             (Top "drv")      */
  495:         case DC_CLOSEALL:      /* Close processing           (Top "drv")    */
  496:                 ataOpenClose(drv, cmd);
  497:                 break;
  498:         }
  499: 
  500:         drv->ReqTmout = TMO_FEVR;
  501:         return E_OK;
  502: }