#define ZERO_BUF_SIZE   2048
U0 BlkWriteZero(CDrive *drive, I64 blk, I64 count)
{//Fill blk count with zeros in Drive.
        I64  n;
        U8      *z = CAlloc(ZERO_BUF_SIZE << BLK_SIZE_BITS);
        Bool show_progress;

        if (count > ZERO_BUF_SIZE && drive->bd->type != BDT_RAM)
        {
                progress1 = 0;
                progress1_max = count;
                StrCopy(progress1_desc, "Zeroing");
                show_progress = TRUE;
        }
        else
                show_progress = FALSE;
        while (count > 0)
        {
                n = count;
                if (n > ZERO_BUF_SIZE)
                        n = ZERO_BUF_SIZE;
                BlkWrite(drive, z, blk, n);
                blk += n;
                count -= n;
                if (show_progress)
                        progress1 += n;
                Yield;  //Prevent locking
        }
        Free(z);
        if (show_progress)
        {
                *progress1_desc = 0;
                progress1 = progress1_max = 0;
        }
}

Bool BlkRead(CDrive *drive, U8 *buf, I64 blk, I64 count)
{//Read blk count from Drive to buf.
        Bool     res = TRUE, unlock;
        CBlkDev *bd  = drive->bd;

        if (count <= 0)
                return TRUE;
        DriveCheck(drive);
        try
        {
                unlock = DriveLock(drive);
                BlkDevInit(bd);
                if (drive->drv_offset && blk < drive->drv_offset || blk + count > drive->drv_offset + drive->size)
                        throw('Drive');
                if (bd->flags & BDF_READ_CACHE)
                        RCache(drive, &buf, &blk, &count);
                if (count > 0)
                {
                        switch (bd->type)
                        {
                                case BDT_RAM:
                                        MemCopy(buf, bd->RAM_disk + blk << BLK_SIZE_BITS, count << BLK_SIZE_BITS);
                                        break;

                                case BDT_ISO_FILE_READ:
                                case BDT_ISO_FILE_WRITE:
                                        FBlkRead(bd->file_disk, buf, blk, count);
                                        break;

                                case BDT_ATA:
                                        res = AHCIAtaRBlks(drive, buf, blk, count);
                                        break;
                                case BDT_ATAPI:
                                        res = AHCIAtapiRBlks(drive, buf, blk, count);
                                        break;
                        }
                        bd->last_time = tS;
                        if (bd->flags & BDF_READ_CACHE)
                                DiskCacheAdd(drive, buf, blk, count);
                }
                if (unlock)
                        DriveUnlock(drive);
        }
        catch
                if (unlock)
                        DriveUnlock(drive);

        return res;
}

Bool BlkWrite(CDrive *drive, U8 *buf, I64 blk, I64 count)
{//Write blk count from buf to Drive.
        Bool     res = TRUE, unlock;
        CBlkDev *bd  = drive->bd;

        if (count <= 0)
                return TRUE;
        DriveCheck(drive);
        try
        {
                unlock = DriveLock(drive);
                BlkDevInit(bd);
                if (bd->flags & BDF_READ_ONLY && !(bd->flags & BDF_READ_ONLY_OVERRIDE))
                        throw('BlkDev');
                if (drive->drv_offset && blk<drive->drv_offset || blk + count>drive->drv_offset + drive->size)
                        throw('Drive');
                if (count > 0)
                {
                        switch (bd->type)
                        {
                                case BDT_RAM:
                                        MemCopy(bd->RAM_disk + blk << BLK_SIZE_BITS, buf, count << BLK_SIZE_BITS);
                                        break;

                                case BDT_ISO_FILE_READ:
                                case BDT_ISO_FILE_WRITE:
                                        FBlkWrite(bd->file_disk, buf, blk, count);
                                        break;

                                case BDT_ATA:
                                case BDT_ATAPI:
                                        res = AHCIAtaWBlks(drive, buf, blk, count);
                                        break;
                        }
                        bd->last_time = tS;
                        if (bd->flags & BDF_READ_CACHE)
                                DiskCacheAdd(drive, buf, blk, count);
                }
                if (unlock)
                        DriveUnlock(drive);
        }
        catch
                if (unlock)
                        DriveUnlock(drive);

        return res;
}