#include #include "usb.h" #include "scsiglue.h" #include "smcommon.h" #include "smil.h" static int Conv_D_MediaAddr(struct us_data *, DWORD); static int Inc_D_MediaAddr(struct us_data *); static int Media_D_ReadOneSect(struct us_data *, WORD, BYTE *); static int Copy_D_BlockAll(struct us_data *, DWORD); static int Assign_D_WriteBlock(void); static int Release_D_ReadBlock(struct us_data *); static int Release_D_WriteBlock(struct us_data *); static int Release_D_CopySector(struct us_data *); static int Copy_D_PhyOneSect(struct us_data *); static int Read_D_PhyOneSect(struct us_data *, WORD, BYTE *); static int Erase_D_PhyOneBlock(struct us_data *); static int Set_D_PhyFmtValue(struct us_data *); static int Search_D_CIS(struct us_data *); static int Make_D_LogTable(struct us_data *); static int MarkFail_D_PhyOneBlock(struct us_data *); static DWORD ErrCode; static BYTE WorkBuf[SECTSIZE]; static BYTE Redundant[REDTSIZE]; static BYTE WorkRedund[REDTSIZE]; /* 128 x 1000, Log2Phy[MAX_ZONENUM][MAX_LOGBLOCK]; */ static WORD *Log2Phy[MAX_ZONENUM]; static BYTE Assign[MAX_ZONENUM][MAX_BLOCKNUM / 8]; static WORD AssignStart[MAX_ZONENUM]; WORD ReadBlock; WORD WriteBlock; DWORD MediaChange; static DWORD SectCopyMode; /* BIT Control Macro */ static BYTE BitData[] = { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 }; #define Set_D_Bit(a, b) (a[(BYTE)((b) / 8)] |= BitData[(b) % 8]) #define Clr_D_Bit(a, b) (a[(BYTE)((b) / 8)] &= ~BitData[(b) % 8]) #define Chk_D_Bit(a, b) (a[(BYTE)((b) / 8)] & BitData[(b) % 8]) /* ----- SM_FreeMem() ------------------------------------------------- */ int SM_FreeMem(void) { int i; pr_info("SM_FreeMem start\n"); for (i = 0; i < MAX_ZONENUM; i++) { if (Log2Phy[i] != NULL) { pr_info("Free Zone = %x, Addr = %p\n", i, Log2Phy[i]); kfree(Log2Phy[i]); Log2Phy[i] = NULL; } } return NO_ERROR; } /* SmartMedia Read/Write/Erase Function */ /* ----- Media_D_ReadSector() ------------------------------------------- */ int Media_D_ReadSector(struct us_data *us, DWORD start, WORD count, BYTE *buf) { WORD len, bn; if (Conv_D_MediaAddr(us, start)) return ErrCode; while (1) { len = Ssfdc.MaxSectors - Media.Sector; if (count > len) bn = len; else bn = count; if (Media_D_ReadOneSect(us, bn, buf)) { ErrCode = ERR_EccReadErr; return ErrCode; } Media.Sector += bn; count -= bn; if (count <= 0) break; buf += bn * SECTSIZE; if (Inc_D_MediaAddr(us)) return ErrCode; } return NO_ERROR; } /* here */ /* ----- Media_D_CopySector() ------------------------------------------ */ int Media_D_CopySector(struct us_data *us, DWORD start, WORD count, BYTE *buf) { WORD len, bn; /* pr_info("Media_D_CopySector !!!\n"); */ if (Conv_D_MediaAddr(us, start)) return ErrCode; while (1) { if (Assign_D_WriteBlock()) return ERROR; len = Ssfdc.MaxSectors - Media.Sector; if (count > len) bn = len; else bn = count; if (Ssfdc_D_CopyBlock(us, bn, buf, Redundant)) { ErrCode = ERR_WriteFault; return ErrCode; } Media.Sector = 0x1F; if (Release_D_CopySector(us)) { if (ErrCode == ERR_HwError) { ErrCode = ERR_WriteFault; return ErrCode; } } count -= bn; if (count <= 0) break; buf += bn * SECTSIZE; if (Inc_D_MediaAddr(us)) return ErrCode; } return NO_ERROR; } /* ----- Release_D_CopySector() ------------------------------------------ */ static int Release_D_CopySector(struct us_data *us) { Log2Phy[Media.Zone][Media.LogBlock] = WriteBlock; Media.PhyBlock = ReadBlock; if (Media.PhyBlock == NO_ASSIGN) { Media.PhyBlock = WriteBlock; return SMSUCCESS; } Clr_D_Bit(Assign[Media.Zone], Media.PhyBlock); Media.PhyBlock = WriteBlock; return SMSUCCESS; } /* SmartMedia Physical Format Test Subroutine */ /* ----- Check_D_MediaFmt() --------------------------------------------- */ int Check_D_MediaFmt(struct us_data *us) { pr_info("Check_D_MediaFmt\n"); if (!MediaChange) return SMSUCCESS; MediaChange = ERROR; SectCopyMode = COMPLETED; if (Set_D_PhyFmtValue(us)) { ErrCode = ERR_UnknownMedia; return ERROR; } if (Search_D_CIS(us)) { ErrCode = ERR_IllegalFmt; return ERROR; } MediaChange = SMSUCCESS; return SMSUCCESS; } /* SmartMedia Physical Address Control Subroutine */ /* ----- Conv_D_MediaAddr() --------------------------------------------- */ static int Conv_D_MediaAddr(struct us_data *us, DWORD addr) { DWORD temp; temp = addr / Ssfdc.MaxSectors; Media.Zone = (BYTE) (temp / Ssfdc.MaxLogBlocks); if (Log2Phy[Media.Zone] == NULL) { if (Make_D_LogTable(us)) { ErrCode = ERR_IllegalFmt; return ERROR; } } Media.Sector = (BYTE) (addr % Ssfdc.MaxSectors); Media.LogBlock = (WORD) (temp % Ssfdc.MaxLogBlocks); if (Media.Zone < Ssfdc.MaxZones) { Clr_D_RedundantData(Redundant); Set_D_LogBlockAddr(Redundant); Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock]; return SMSUCCESS; } ErrCode = ERR_OutOfLBA; return ERROR; } /* ----- Inc_D_MediaAddr() ---------------------------------------------- */ static int Inc_D_MediaAddr(struct us_data *us) { WORD LogBlock = Media.LogBlock; if (++Media.Sector < Ssfdc.MaxSectors) return SMSUCCESS; if (Log2Phy[Media.Zone] == NULL) { if (Make_D_LogTable(us)) { ErrCode = ERR_IllegalFmt; return ERROR; } } Media.Sector = 0; Media.LogBlock = LogBlock; if (++Media.LogBlock < Ssfdc.MaxLogBlocks) { Clr_D_RedundantData(Redundant); Set_D_LogBlockAddr(Redundant); Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock]; return SMSUCCESS; } Media.LogBlock = 0; if (++Media.Zone < Ssfdc.MaxZones) { if (Log2Phy[Media.Zone] == NULL) { if (Make_D_LogTable(us)) { ErrCode = ERR_IllegalFmt; return ERROR; } } Media.LogBlock = 0; Clr_D_RedundantData(Redundant); Set_D_LogBlockAddr(Redundant); Media.PhyBlock = Log2Phy[Media.Zone][Media.LogBlock]; return SMSUCCESS; } Media.Zone = 0; ErrCode = ERR_OutOfLBA; return ERROR; } /* SmartMedia Read/Write Subroutine with Retry */ /* ----- Media_D_ReadOneSect() ------------------------------------------ */ static int Media_D_ReadOneSect(struct us_data *us, WORD count, BYTE *buf) { DWORD err, retry; if (!Read_D_PhyOneSect(us, count, buf)) return SMSUCCESS; if (ErrCode == ERR_HwError) return ERROR; if (ErrCode == ERR_DataStatus) return ERROR; #ifdef RDERR_REASSIGN if (Ssfdc.Attribute & MWP) { if (ErrCode == ERR_CorReadErr) return SMSUCCESS; return ERROR; } err = ErrCode; for (retry = 0; retry < 2; retry++) { if (Copy_D_BlockAll(us, (err == ERR_EccReadErr) ? REQ_FAIL : REQ_ERASE)) { if (ErrCode == ERR_HwError) return ERROR; continue; } ErrCode = err; if (ErrCode == ERR_CorReadErr) return SMSUCCESS; return ERROR; } MediaChange = ERROR; #else if (ErrCode == ERR_CorReadErr) return SMSUCCESS; #endif return ERROR; } /* SmartMedia Physical Sector Data Copy Subroutine */ /* ----- Copy_D_BlockAll() ---------------------------------------------- */ static int Copy_D_BlockAll(struct us_data *us, DWORD mode) { BYTE sect; sect = Media.Sector; if (Assign_D_WriteBlock()) return ERROR; if (mode == REQ_FAIL) SectCopyMode = REQ_FAIL; for (Media.Sector = 0; Media.Sector < Ssfdc.MaxSectors; Media.Sector++) { if (Copy_D_PhyOneSect(us)) { if (ErrCode == ERR_HwError) return ERROR; if (Release_D_WriteBlock(us)) return ERROR; ErrCode = ERR_WriteFault; Media.PhyBlock = ReadBlock; Media.Sector = sect; return ERROR; } } if (Release_D_ReadBlock(us)) return ERROR; Media.PhyBlock = WriteBlock; Media.Sector = sect; return SMSUCCESS; } /* SmartMedia Physical Block Assign/Release Subroutine */ /* ----- Assign_D_WriteBlock() ------------------------------------------ */ static int Assign_D_WriteBlock(void) { ReadBlock = Media.PhyBlock; for (WriteBlock = AssignStart[Media.Zone]; WriteBlock < Ssfdc.MaxBlocks; WriteBlock++) { if (!Chk_D_Bit(Assign[Media.Zone], WriteBlock)) { Set_D_Bit(Assign[Media.Zone], WriteBlock); AssignStart[Media.Zone] = WriteBlock + 1; Media.PhyBlock = WriteBlock; SectCopyMode = REQ_ERASE; return SMSUCCESS; } } for (WriteBlock = 0; WriteBlock < AssignStart[Media.Zone]; WriteBlock++) { if (!Chk_D_Bit(Assign[Media.Zone], WriteBlock)) { Set_D_Bit(Assign[Media.Zone], WriteBlock); AssignStart[Media.Zone] = WriteBlock + 1; Media.PhyBlock = WriteBlock; SectCopyMode = REQ_ERASE; return SMSUCCESS; } } WriteBlock = NO_ASSIGN; ErrCode = ERR_WriteFault; return ERROR; } /* ----- Release_D_ReadBlock() ------------------------------------------ */ static int Release_D_ReadBlock(struct us_data *us) { DWORD mode; mode = SectCopyMode; SectCopyMode = COMPLETED; if (mode == COMPLETED) return SMSUCCESS; Log2Phy[Media.Zone][Media.LogBlock] = WriteBlock; Media.PhyBlock = ReadBlock; if (Media.PhyBlock == NO_ASSIGN) { Media.PhyBlock = WriteBlock; return SMSUCCESS; } if (mode == REQ_ERASE) { if (Erase_D_PhyOneBlock(us)) { if (ErrCode == ERR_HwError) return ERROR; if (MarkFail_D_PhyOneBlock(us)) return ERROR; } else Clr_D_Bit(Assign[Media.Zone], Media.PhyBlock); } else if (MarkFail_D_PhyOneBlock(us)) return ERROR; Media.PhyBlock = WriteBlock; return SMSUCCESS; } /* ----- Release_D_WriteBlock() ----------------------------------------- */ static int Release_D_WriteBlock(struct us_data *us) { SectCopyMode = COMPLETED; Media.PhyBlock = WriteBlock; if (MarkFail_D_PhyOneBlock(us)) return ERROR; Media.PhyBlock = ReadBlock; return SMSUCCESS; } /* SmartMedia Physical Sector Data Copy Subroutine */ /* ----- Copy_D_PhyOneSect() -------------------------------------------- */ static int Copy_D_PhyOneSect(struct us_data *us) { int i; DWORD err, retry; /* pr_info("Copy_D_PhyOneSect --- Sector = %x\n", Media.Sector); */ if (ReadBlock != NO_ASSIGN) { Media.PhyBlock = ReadBlock; for (retry = 0; retry < 2; retry++) { if (retry != 0) { Ssfdc_D_Reset(us); if (Ssfdc_D_ReadCisSect(us, WorkBuf, WorkRedund)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } if (Check_D_CISdata(WorkBuf, WorkRedund)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } } if (Ssfdc_D_ReadSect(us, WorkBuf, WorkRedund)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } if (Check_D_DataStatus(WorkRedund)) { err = ERROR; break; } if (!Check_D_ReadError(WorkRedund)) { err = SMSUCCESS; break; } if (!Check_D_Correct(WorkBuf, WorkRedund)) { err = SMSUCCESS; break; } err = ERROR; SectCopyMode = REQ_FAIL; } } else { err = SMSUCCESS; for (i = 0; i < SECTSIZE; i++) WorkBuf[i] = DUMMY_DATA; Clr_D_RedundantData(WorkRedund); } Set_D_LogBlockAddr(WorkRedund); if (err == ERROR) { Set_D_RightECC(WorkRedund); Set_D_DataStaus(WorkRedund); } Media.PhyBlock = WriteBlock; if (Ssfdc_D_WriteSectForCopy(us, WorkBuf, WorkRedund)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } if (Ssfdc_D_CheckStatus()) { ErrCode = ERR_WriteFault; return ERROR; } Media.PhyBlock = ReadBlock; return SMSUCCESS; } /* SmartMedia Physical Sector Read/Write/Erase Subroutine */ /* ----- Read_D_PhyOneSect() -------------------------------------------- */ static int Read_D_PhyOneSect(struct us_data *us, WORD count, BYTE *buf) { int i; DWORD retry; if (Media.PhyBlock == NO_ASSIGN) { for (i = 0; i < SECTSIZE; i++) *buf++ = DUMMY_DATA; return SMSUCCESS; } for (retry = 0; retry < 2; retry++) { if (retry != 0) { Ssfdc_D_Reset(us); if (Ssfdc_D_ReadCisSect(us, WorkBuf, WorkRedund)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } if (Check_D_CISdata(WorkBuf, WorkRedund)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } } if (Ssfdc_D_ReadBlock(us, count, buf, Redundant)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } if (Check_D_DataStatus(Redundant)) { ErrCode = ERR_DataStatus; return ERROR; } if (!Check_D_ReadError(Redundant)) return SMSUCCESS; if (!Check_D_Correct(buf, Redundant)) { ErrCode = ERR_CorReadErr; return ERROR; } } ErrCode = ERR_EccReadErr; return ERROR; } /* ----- Erase_D_PhyOneBlock() ------------------------------------------ */ static int Erase_D_PhyOneBlock(struct us_data *us) { if (Ssfdc_D_EraseBlock(us)) { ErrCode = ERR_HwError; MediaChange = ERROR; return ERROR; } if (Ssfdc_D_CheckStatus()) { ErrCode = ERR_WriteFault; return ERROR; } return SMSUCCESS; } /* SmartMedia Physical Format Check Local Subroutine */ /* ----- Set_D_PhyFmtValue() -------------------------------------------- */ static int Set_D_PhyFmtValue(struct us_data *us) { if (Set_D_SsfdcModel(us->SM_DeviceID)) return ERROR; return SMSUCCESS; } /* ----- Search_D_CIS() ------------------------------------------------- */ static int Search_D_CIS(struct us_data *us) { Media.Zone = 0; Media.Sector = 0; for (Media.PhyBlock = 0; Media.PhyBlock < (Ssfdc.MaxBlocks - Ssfdc.MaxLogBlocks - 1); Media.PhyBlock++) { if (Ssfdc_D_ReadRedtData(us, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } if (!Check_D_FailBlock(Redundant)) break; } if (Media.PhyBlock == (Ssfdc.MaxBlocks - Ssfdc.MaxLogBlocks - 1)) { Ssfdc_D_Reset(us); return ERROR; } while (Media.Sector < CIS_SEARCH_SECT) { if (Media.Sector) { if (Ssfdc_D_ReadRedtData(us, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } } if (!Check_D_DataStatus(Redundant)) { if (Ssfdc_D_ReadSect(us, WorkBuf, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } if (Check_D_CISdata(WorkBuf, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } CisArea.PhyBlock = Media.PhyBlock; CisArea.Sector = Media.Sector; Ssfdc_D_Reset(us); return SMSUCCESS; } Media.Sector++; } Ssfdc_D_Reset(us); return ERROR; } /* ----- Make_D_LogTable() ---------------------------------------------- */ static int Make_D_LogTable(struct us_data *us) { WORD phyblock, logblock; if (Log2Phy[Media.Zone] == NULL) { Log2Phy[Media.Zone] = kmalloc(MAX_LOGBLOCK * sizeof(WORD), GFP_KERNEL); /* pr_info("ExAllocatePool Zone = %x, Addr = %x\n", Media.Zone, Log2Phy[Media.Zone]); */ if (Log2Phy[Media.Zone] == NULL) return ERROR; } Media.Sector = 0; /* pr_info("Make_D_LogTable --- MediaZone = 0x%x\n", Media.Zone); */ for (Media.LogBlock = 0; Media.LogBlock < Ssfdc.MaxLogBlocks; Media.LogBlock++) Log2Phy[Media.Zone][Media.LogBlock] = NO_ASSIGN; for (Media.PhyBlock = 0; Media.PhyBlock < (MAX_BLOCKNUM / 8); Media.PhyBlock++) Assign[Media.Zone][Media.PhyBlock] = 0x00; for (Media.PhyBlock = 0; Media.PhyBlock < Ssfdc.MaxBlocks; Media.PhyBlock++) { if ((!Media.Zone) && (Media.PhyBlock <= CisArea.PhyBlock)) { Set_D_Bit(Assign[Media.Zone], Media.PhyBlock); continue; } if (Ssfdc_D_ReadRedtData(us, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } if (!Check_D_DataBlank(Redundant)) continue; Set_D_Bit(Assign[Media.Zone], Media.PhyBlock); if (Check_D_FailBlock(Redundant)) continue; if (Load_D_LogBlockAddr(Redundant)) continue; if (Media.LogBlock >= Ssfdc.MaxLogBlocks) continue; if (Log2Phy[Media.Zone][Media.LogBlock] == NO_ASSIGN) { Log2Phy[Media.Zone][Media.LogBlock] = Media.PhyBlock; continue; } phyblock = Media.PhyBlock; logblock = Media.LogBlock; Media.Sector = (BYTE)(Ssfdc.MaxSectors - 1); if (Ssfdc_D_ReadRedtData(us, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } if (!Load_D_LogBlockAddr(Redundant) && (Media.LogBlock == logblock)) { Media.PhyBlock = Log2Phy[Media.Zone][logblock]; if (Ssfdc_D_ReadRedtData(us, Redundant)) { Ssfdc_D_Reset(us); return ERROR; } Media.PhyBlock = phyblock; if (!Load_D_LogBlockAddr(Redundant)) { if (Media.LogBlock != logblock) { Media.PhyBlock = Log2Phy[Media.Zone][logblock]; Log2Phy[Media.Zone][logblock] = phyblock; } } else { Media.PhyBlock = Log2Phy[Media.Zone][logblock]; Log2Phy[Media.Zone][logblock] = phyblock; } } Media.Sector = 0; Media.PhyBlock = phyblock; AssignStart[Media.Zone] = 0; } /* End for (Media.Zone