15fd54aceSGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0+ 241e568d1Shuajun li #include <linux/jiffies.h> 341e568d1Shuajun li #include <linux/errno.h> 441e568d1Shuajun li #include <linux/module.h> 541e568d1Shuajun li #include <linux/slab.h> 641e568d1Shuajun li 741e568d1Shuajun li #include <scsi/scsi.h> 841e568d1Shuajun li #include <scsi/scsi_cmnd.h> 941e568d1Shuajun li 1041e568d1Shuajun li #include <linux/firmware.h> 1141e568d1Shuajun li 1241e568d1Shuajun li #include "usb.h" 1341e568d1Shuajun li #include "transport.h" 1441e568d1Shuajun li #include "protocol.h" 1541e568d1Shuajun li #include "debug.h" 16aa519be3SAkinobu Mita #include "scsiglue.h" 1741e568d1Shuajun li 18595c8970STim Gardner #define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin" 19595c8970STim Gardner #define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin" 20595c8970STim Gardner #define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin" 21595c8970STim Gardner #define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin" 22595c8970STim Gardner #define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin" 23595c8970STim Gardner #define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin" 24595c8970STim Gardner 25aa519be3SAkinobu Mita #define DRV_NAME "ums_eneub6250" 26aa519be3SAkinobu Mita 2741e568d1Shuajun li MODULE_DESCRIPTION("Driver for ENE UB6250 reader"); 2841e568d1Shuajun li MODULE_LICENSE("GPL"); 29595c8970STim Gardner MODULE_FIRMWARE(SD_INIT1_FIRMWARE); 30595c8970STim Gardner MODULE_FIRMWARE(SD_INIT2_FIRMWARE); 31595c8970STim Gardner MODULE_FIRMWARE(SD_RW_FIRMWARE); 32595c8970STim Gardner MODULE_FIRMWARE(MS_INIT_FIRMWARE); 33595c8970STim Gardner MODULE_FIRMWARE(MSP_RW_FIRMWARE); 34595c8970STim Gardner MODULE_FIRMWARE(MS_RW_FIRMWARE); 3541e568d1Shuajun li 3641e568d1Shuajun li /* 3741e568d1Shuajun li * The table of devices 3841e568d1Shuajun li */ 3941e568d1Shuajun li #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \ 4041e568d1Shuajun li vendorName, productName, useProtocol, useTransport, \ 4141e568d1Shuajun li initFunction, flags) \ 4241e568d1Shuajun li { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \ 43f61870eeSSebastian Andrzej Siewior .driver_info = (flags)} 4441e568d1Shuajun li 4536f3a14dSFelipe Balbi static struct usb_device_id ene_ub6250_usb_ids[] = { 4641e568d1Shuajun li # include "unusual_ene_ub6250.h" 4741e568d1Shuajun li { } /* Terminating entry */ 4841e568d1Shuajun li }; 4941e568d1Shuajun li MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids); 5041e568d1Shuajun li 5141e568d1Shuajun li #undef UNUSUAL_DEV 5241e568d1Shuajun li 5341e568d1Shuajun li /* 5441e568d1Shuajun li * The flags table 5541e568d1Shuajun li */ 5641e568d1Shuajun li #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \ 5741e568d1Shuajun li vendor_name, product_name, use_protocol, use_transport, \ 5841e568d1Shuajun li init_function, Flags) \ 5941e568d1Shuajun li { \ 6041e568d1Shuajun li .vendorName = vendor_name, \ 6141e568d1Shuajun li .productName = product_name, \ 6241e568d1Shuajun li .useProtocol = use_protocol, \ 6341e568d1Shuajun li .useTransport = use_transport, \ 6441e568d1Shuajun li .initFunction = init_function, \ 6541e568d1Shuajun li } 6641e568d1Shuajun li 6741e568d1Shuajun li static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = { 6841e568d1Shuajun li # include "unusual_ene_ub6250.h" 6941e568d1Shuajun li { } /* Terminating entry */ 7041e568d1Shuajun li }; 7141e568d1Shuajun li 7241e568d1Shuajun li #undef UNUSUAL_DEV 7341e568d1Shuajun li 7441e568d1Shuajun li 7541e568d1Shuajun li 7641e568d1Shuajun li /* ENE bin code len */ 7741e568d1Shuajun li #define ENE_BIN_CODE_LEN 0x800 7841e568d1Shuajun li /* EnE HW Register */ 7941e568d1Shuajun li #define REG_CARD_STATUS 0xFF83 8041e568d1Shuajun li #define REG_HW_TRAP1 0xFF89 8141e568d1Shuajun li 8241e568d1Shuajun li /* SRB Status */ 83ce553bd1SAlan Stern #define SS_SUCCESS 0x000000 /* No Sense */ 84ce553bd1SAlan Stern #define SS_NOT_READY 0x023A00 /* Medium not present */ 85ce553bd1SAlan Stern #define SS_MEDIUM_ERR 0x031100 /* Unrecovered read error */ 86ce553bd1SAlan Stern #define SS_HW_ERR 0x040800 /* Communication failure */ 87ce553bd1SAlan Stern #define SS_ILLEGAL_REQUEST 0x052000 /* Invalid command */ 88ce553bd1SAlan Stern #define SS_UNIT_ATTENTION 0x062900 /* Reset occurred */ 8941e568d1Shuajun li 9041e568d1Shuajun li /* ENE Load FW Pattern */ 9141e568d1Shuajun li #define SD_INIT1_PATTERN 1 9241e568d1Shuajun li #define SD_INIT2_PATTERN 2 9341e568d1Shuajun li #define SD_RW_PATTERN 3 9441e568d1Shuajun li #define MS_INIT_PATTERN 4 9541e568d1Shuajun li #define MSP_RW_PATTERN 5 9641e568d1Shuajun li #define MS_RW_PATTERN 6 9741e568d1Shuajun li #define SM_INIT_PATTERN 7 9841e568d1Shuajun li #define SM_RW_PATTERN 8 9941e568d1Shuajun li 10041e568d1Shuajun li #define FDIR_WRITE 0 10141e568d1Shuajun li #define FDIR_READ 1 10241e568d1Shuajun li 10333842cedSCho, Yu-Chen /* For MS Card */ 10433842cedSCho, Yu-Chen 10533842cedSCho, Yu-Chen /* Status Register 1 */ 10633842cedSCho, Yu-Chen #define MS_REG_ST1_MB 0x80 /* media busy */ 10733842cedSCho, Yu-Chen #define MS_REG_ST1_FB1 0x40 /* flush busy 1 */ 10833842cedSCho, Yu-Chen #define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */ 10933842cedSCho, Yu-Chen #define MS_REG_ST1_UCDT 0x10 /* unable to correct data */ 11033842cedSCho, Yu-Chen #define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */ 11133842cedSCho, Yu-Chen #define MS_REG_ST1_UCEX 0x04 /* unable to correct extra */ 11233842cedSCho, Yu-Chen #define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */ 11333842cedSCho, Yu-Chen #define MS_REG_ST1_UCFG 0x01 /* unable to correct overwrite flag */ 11433842cedSCho, Yu-Chen #define MS_REG_ST1_DEFAULT (MS_REG_ST1_MB | MS_REG_ST1_FB1 | MS_REG_ST1_DTER | MS_REG_ST1_UCDT | MS_REG_ST1_EXER | MS_REG_ST1_UCEX | MS_REG_ST1_FGER | MS_REG_ST1_UCFG) 11533842cedSCho, Yu-Chen 11633842cedSCho, Yu-Chen /* Overwrite Area */ 11733842cedSCho, Yu-Chen #define MS_REG_OVR_BKST 0x80 /* block status */ 11833842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */ 11933842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_NG 0x00 /* NG */ 12033842cedSCho, Yu-Chen #define MS_REG_OVR_PGST0 0x40 /* page status */ 12133842cedSCho, Yu-Chen #define MS_REG_OVR_PGST1 0x20 12233842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_MASK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) 12333842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_OK (MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) /* OK */ 12433842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_NG MS_REG_OVR_PGST1 /* NG */ 12533842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_DATA_ERROR 0x00 /* data error */ 12633842cedSCho, Yu-Chen #define MS_REG_OVR_UDST 0x10 /* update status */ 12733842cedSCho, Yu-Chen #define MS_REG_OVR_UDST_UPDATING 0x00 /* updating */ 12833842cedSCho, Yu-Chen #define MS_REG_OVR_UDST_NO_UPDATE MS_REG_OVR_UDST 12933842cedSCho, Yu-Chen #define MS_REG_OVR_RESERVED 0x08 13033842cedSCho, Yu-Chen #define MS_REG_OVR_DEFAULT (MS_REG_OVR_BKST_OK | MS_REG_OVR_PGST_OK | MS_REG_OVR_UDST_NO_UPDATE | MS_REG_OVR_RESERVED) 13133842cedSCho, Yu-Chen 13233842cedSCho, Yu-Chen /* Management Flag */ 13333842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS0 0x20 /* serial copy management system */ 13433842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS1 0x10 13533842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_MASK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1) 13633842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_COPY_OK (MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1) 13733842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_ONE_COPY MS_REG_MNG_SCMS1 13833842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_NO_COPY 0x00 13933842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG 0x08 /* address transfer table flag */ 14033842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG_OTHER MS_REG_MNG_ATFLG /* other */ 14133842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG_ATTBL 0x00 /* address transfer table */ 14233842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG 0x04 /* system flag */ 14333842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */ 14433842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_BOOT 0x00 /* system block */ 14533842cedSCho, Yu-Chen #define MS_REG_MNG_RESERVED 0xc3 14633842cedSCho, Yu-Chen #define MS_REG_MNG_DEFAULT (MS_REG_MNG_SCMS_COPY_OK | MS_REG_MNG_ATFLG_OTHER | MS_REG_MNG_SYSFLG_USER | MS_REG_MNG_RESERVED) 14733842cedSCho, Yu-Chen 14833842cedSCho, Yu-Chen 14933842cedSCho, Yu-Chen #define MS_MAX_PAGES_PER_BLOCK 32 15033842cedSCho, Yu-Chen #define MS_MAX_INITIAL_ERROR_BLOCKS 10 15133842cedSCho, Yu-Chen #define MS_LIB_BITS_PER_BYTE 8 15233842cedSCho, Yu-Chen 15333842cedSCho, Yu-Chen #define MS_SYSINF_FORMAT_FAT 1 15433842cedSCho, Yu-Chen #define MS_SYSINF_USAGE_GENERAL 0 15533842cedSCho, Yu-Chen 15633842cedSCho, Yu-Chen #define MS_SYSINF_MSCLASS_TYPE_1 1 15733842cedSCho, Yu-Chen #define MS_SYSINF_PAGE_SIZE MS_BYTES_PER_PAGE /* fixed */ 15833842cedSCho, Yu-Chen 15933842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_RDONLY 1 16033842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_RDWR 2 16133842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_HYBRID 3 16233842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY 0x01 16333842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY_NO_SUPPORT MS_SYSINF_SECURITY 16433842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY_SUPPORT 0 16533842cedSCho, Yu-Chen 16633842cedSCho, Yu-Chen #define MS_SYSINF_RESERVED1 1 16733842cedSCho, Yu-Chen #define MS_SYSINF_RESERVED2 1 16833842cedSCho, Yu-Chen 16933842cedSCho, Yu-Chen #define MS_SYSENT_TYPE_INVALID_BLOCK 0x01 17033842cedSCho, Yu-Chen #define MS_SYSENT_TYPE_CIS_IDI 0x0a /* CIS/IDI */ 17133842cedSCho, Yu-Chen 17233842cedSCho, Yu-Chen #define SIZE_OF_KIRO 1024 17333842cedSCho, Yu-Chen #define BYTE_MASK 0xff 17433842cedSCho, Yu-Chen 17533842cedSCho, Yu-Chen /* ms error code */ 17633842cedSCho, Yu-Chen #define MS_STATUS_WRITE_PROTECT 0x0106 17733842cedSCho, Yu-Chen #define MS_STATUS_SUCCESS 0x0000 17833842cedSCho, Yu-Chen #define MS_ERROR_FLASH_READ 0x8003 17933842cedSCho, Yu-Chen #define MS_ERROR_FLASH_ERASE 0x8005 18033842cedSCho, Yu-Chen #define MS_LB_ERROR 0xfff0 18133842cedSCho, Yu-Chen #define MS_LB_BOOT_BLOCK 0xfff1 18233842cedSCho, Yu-Chen #define MS_LB_INITIAL_ERROR 0xfff2 18333842cedSCho, Yu-Chen #define MS_STATUS_SUCCESS_WITH_ECC 0xfff3 18433842cedSCho, Yu-Chen #define MS_LB_ACQUIRED_ERROR 0xfff4 18533842cedSCho, Yu-Chen #define MS_LB_NOT_USED_ERASED 0xfff5 18633842cedSCho, Yu-Chen #define MS_NOCARD_ERROR 0xfff8 18733842cedSCho, Yu-Chen #define MS_NO_MEMORY_ERROR 0xfff9 18833842cedSCho, Yu-Chen #define MS_STATUS_INT_ERROR 0xfffa 18933842cedSCho, Yu-Chen #define MS_STATUS_ERROR 0xfffe 19033842cedSCho, Yu-Chen #define MS_LB_NOT_USED 0xffff 19133842cedSCho, Yu-Chen 19233842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG 0x04 /* system flag */ 19333842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_USER MS_REG_MNG_SYSFLG /* user block */ 19433842cedSCho, Yu-Chen 19533842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_ID 0x0001 19633842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_FORMAT_VERSION 0x0100 19733842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_DATA_ENTRIES 2 19833842cedSCho, Yu-Chen 19933842cedSCho, Yu-Chen #define MS_NUMBER_OF_SYSTEM_ENTRY 4 20033842cedSCho, Yu-Chen #define MS_NUMBER_OF_BOOT_BLOCK 2 20133842cedSCho, Yu-Chen #define MS_BYTES_PER_PAGE 512 20233842cedSCho, Yu-Chen #define MS_LOGICAL_BLOCKS_PER_SEGMENT 496 20333842cedSCho, Yu-Chen #define MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT 494 20433842cedSCho, Yu-Chen 20533842cedSCho, Yu-Chen #define MS_PHYSICAL_BLOCKS_PER_SEGMENT 0x200 /* 512 */ 20633842cedSCho, Yu-Chen #define MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK 0x1ff 20733842cedSCho, Yu-Chen 20833842cedSCho, Yu-Chen /* overwrite area */ 20933842cedSCho, Yu-Chen #define MS_REG_OVR_BKST 0x80 /* block status */ 21033842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_OK MS_REG_OVR_BKST /* OK */ 21133842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_NG 0x00 /* NG */ 21233842cedSCho, Yu-Chen 21333842cedSCho, Yu-Chen /* Status Register 1 */ 21433842cedSCho, Yu-Chen #define MS_REG_ST1_DTER 0x20 /* error on data(corrected) */ 21533842cedSCho, Yu-Chen #define MS_REG_ST1_EXER 0x08 /* error on extra(corrected) */ 21633842cedSCho, Yu-Chen #define MS_REG_ST1_FGER 0x02 /* error on overwrite flag(corrected) */ 21733842cedSCho, Yu-Chen 21833842cedSCho, Yu-Chen /* MemoryStick Register */ 21933842cedSCho, Yu-Chen /* Status Register 0 */ 22033842cedSCho, Yu-Chen #define MS_REG_ST0_WP 0x01 /* write protected */ 22133842cedSCho, Yu-Chen #define MS_REG_ST0_WP_ON MS_REG_ST0_WP 22233842cedSCho, Yu-Chen 22333842cedSCho, Yu-Chen #define MS_LIB_CTRL_RDONLY 0 22433842cedSCho, Yu-Chen #define MS_LIB_CTRL_WRPROTECT 1 22533842cedSCho, Yu-Chen 22633842cedSCho, Yu-Chen /*dphy->log table */ 22733842cedSCho, Yu-Chen #define ms_libconv_to_logical(pdx, PhyBlock) (((PhyBlock) >= (pdx)->MS_Lib.NumberOfPhyBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Phy2LogMap[PhyBlock]) 22833842cedSCho, Yu-Chen #define ms_libconv_to_physical(pdx, LogBlock) (((LogBlock) >= (pdx)->MS_Lib.NumberOfLogBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Log2PhyMap[LogBlock]) 22933842cedSCho, Yu-Chen 23033842cedSCho, Yu-Chen #define ms_lib_ctrl_set(pdx, Flag) ((pdx)->MS_Lib.flags |= (1 << (Flag))) 23133842cedSCho, Yu-Chen #define ms_lib_ctrl_reset(pdx, Flag) ((pdx)->MS_Lib.flags &= ~(1 << (Flag))) 23233842cedSCho, Yu-Chen #define ms_lib_ctrl_check(pdx, Flag) ((pdx)->MS_Lib.flags & (1 << (Flag))) 23333842cedSCho, Yu-Chen 23433842cedSCho, Yu-Chen #define ms_lib_iswritable(pdx) ((ms_lib_ctrl_check((pdx), MS_LIB_CTRL_RDONLY) == 0) && (ms_lib_ctrl_check(pdx, MS_LIB_CTRL_WRPROTECT) == 0)) 23533842cedSCho, Yu-Chen #define ms_lib_clear_pagemap(pdx) memset((pdx)->MS_Lib.pagemap, 0, sizeof((pdx)->MS_Lib.pagemap)) 23633842cedSCho, Yu-Chen #define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0)) 23733842cedSCho, Yu-Chen 23841e568d1Shuajun li 23941e568d1Shuajun li struct SD_STATUS { 24041e568d1Shuajun li u8 Insert:1; 24141e568d1Shuajun li u8 Ready:1; 24241e568d1Shuajun li u8 MediaChange:1; 24341e568d1Shuajun li u8 IsMMC:1; 24441e568d1Shuajun li u8 HiCapacity:1; 24541e568d1Shuajun li u8 HiSpeed:1; 24641e568d1Shuajun li u8 WtP:1; 24741e568d1Shuajun li u8 Reserved:1; 24841e568d1Shuajun li }; 24941e568d1Shuajun li 25041e568d1Shuajun li struct MS_STATUS { 25141e568d1Shuajun li u8 Insert:1; 25241e568d1Shuajun li u8 Ready:1; 25341e568d1Shuajun li u8 MediaChange:1; 25441e568d1Shuajun li u8 IsMSPro:1; 25541e568d1Shuajun li u8 IsMSPHG:1; 25641e568d1Shuajun li u8 Reserved1:1; 25741e568d1Shuajun li u8 WtP:1; 25841e568d1Shuajun li u8 Reserved2:1; 25941e568d1Shuajun li }; 26041e568d1Shuajun li 26141e568d1Shuajun li struct SM_STATUS { 26241e568d1Shuajun li u8 Insert:1; 26341e568d1Shuajun li u8 Ready:1; 26441e568d1Shuajun li u8 MediaChange:1; 26541e568d1Shuajun li u8 Reserved:3; 26641e568d1Shuajun li u8 WtP:1; 26741e568d1Shuajun li u8 IsMS:1; 26841e568d1Shuajun li }; 26941e568d1Shuajun li 27033842cedSCho, Yu-Chen struct ms_bootblock_cis { 27133842cedSCho, Yu-Chen u8 bCistplDEVICE[6]; /* 0 */ 27233842cedSCho, Yu-Chen u8 bCistplDEVICE0C[6]; /* 6 */ 27333842cedSCho, Yu-Chen u8 bCistplJEDECC[4]; /* 12 */ 27433842cedSCho, Yu-Chen u8 bCistplMANFID[6]; /* 16 */ 27533842cedSCho, Yu-Chen u8 bCistplVER1[32]; /* 22 */ 27633842cedSCho, Yu-Chen u8 bCistplFUNCID[4]; /* 54 */ 27733842cedSCho, Yu-Chen u8 bCistplFUNCE0[4]; /* 58 */ 27833842cedSCho, Yu-Chen u8 bCistplFUNCE1[5]; /* 62 */ 27933842cedSCho, Yu-Chen u8 bCistplCONF[7]; /* 67 */ 28033842cedSCho, Yu-Chen u8 bCistplCFTBLENT0[10];/* 74 */ 28133842cedSCho, Yu-Chen u8 bCistplCFTBLENT1[8]; /* 84 */ 28233842cedSCho, Yu-Chen u8 bCistplCFTBLENT2[12];/* 92 */ 28333842cedSCho, Yu-Chen u8 bCistplCFTBLENT3[8]; /* 104 */ 28433842cedSCho, Yu-Chen u8 bCistplCFTBLENT4[17];/* 112 */ 28533842cedSCho, Yu-Chen u8 bCistplCFTBLENT5[8]; /* 129 */ 28633842cedSCho, Yu-Chen u8 bCistplCFTBLENT6[17];/* 137 */ 28733842cedSCho, Yu-Chen u8 bCistplCFTBLENT7[8]; /* 154 */ 28833842cedSCho, Yu-Chen u8 bCistplNOLINK[3]; /* 162 */ 28933842cedSCho, Yu-Chen } ; 29033842cedSCho, Yu-Chen 29133842cedSCho, Yu-Chen struct ms_bootblock_idi { 29233842cedSCho, Yu-Chen #define MS_IDI_GENERAL_CONF 0x848A 29333842cedSCho, Yu-Chen u16 wIDIgeneralConfiguration; /* 0 */ 29433842cedSCho, Yu-Chen u16 wIDInumberOfCylinder; /* 1 */ 29533842cedSCho, Yu-Chen u16 wIDIreserved0; /* 2 */ 29633842cedSCho, Yu-Chen u16 wIDInumberOfHead; /* 3 */ 29733842cedSCho, Yu-Chen u16 wIDIbytesPerTrack; /* 4 */ 29833842cedSCho, Yu-Chen u16 wIDIbytesPerSector; /* 5 */ 29933842cedSCho, Yu-Chen u16 wIDIsectorsPerTrack; /* 6 */ 30033842cedSCho, Yu-Chen u16 wIDItotalSectors[2]; /* 7-8 high,low */ 30133842cedSCho, Yu-Chen u16 wIDIreserved1[11]; /* 9-19 */ 30233842cedSCho, Yu-Chen u16 wIDIbufferType; /* 20 */ 30333842cedSCho, Yu-Chen u16 wIDIbufferSize; /* 21 */ 30433842cedSCho, Yu-Chen u16 wIDIlongCmdECC; /* 22 */ 30533842cedSCho, Yu-Chen u16 wIDIfirmVersion[4]; /* 23-26 */ 30633842cedSCho, Yu-Chen u16 wIDImodelName[20]; /* 27-46 */ 30733842cedSCho, Yu-Chen u16 wIDIreserved2; /* 47 */ 30833842cedSCho, Yu-Chen u16 wIDIlongWordSupported; /* 48 */ 30933842cedSCho, Yu-Chen u16 wIDIdmaSupported; /* 49 */ 31033842cedSCho, Yu-Chen u16 wIDIreserved3; /* 50 */ 31133842cedSCho, Yu-Chen u16 wIDIpioTiming; /* 51 */ 31233842cedSCho, Yu-Chen u16 wIDIdmaTiming; /* 52 */ 31333842cedSCho, Yu-Chen u16 wIDItransferParameter; /* 53 */ 31433842cedSCho, Yu-Chen u16 wIDIformattedCylinder; /* 54 */ 31533842cedSCho, Yu-Chen u16 wIDIformattedHead; /* 55 */ 31633842cedSCho, Yu-Chen u16 wIDIformattedSectorsPerTrack;/* 56 */ 31733842cedSCho, Yu-Chen u16 wIDIformattedTotalSectors[2];/* 57-58 */ 31833842cedSCho, Yu-Chen u16 wIDImultiSector; /* 59 */ 31933842cedSCho, Yu-Chen u16 wIDIlbaSectors[2]; /* 60-61 */ 32033842cedSCho, Yu-Chen u16 wIDIsingleWordDMA; /* 62 */ 32133842cedSCho, Yu-Chen u16 wIDImultiWordDMA; /* 63 */ 32233842cedSCho, Yu-Chen u16 wIDIreserved4[192]; /* 64-255 */ 32333842cedSCho, Yu-Chen }; 32433842cedSCho, Yu-Chen 32533842cedSCho, Yu-Chen struct ms_bootblock_sysent_rec { 32633842cedSCho, Yu-Chen u32 dwStart; 32733842cedSCho, Yu-Chen u32 dwSize; 32833842cedSCho, Yu-Chen u8 bType; 32933842cedSCho, Yu-Chen u8 bReserved[3]; 33033842cedSCho, Yu-Chen }; 33133842cedSCho, Yu-Chen 33233842cedSCho, Yu-Chen struct ms_bootblock_sysent { 33333842cedSCho, Yu-Chen struct ms_bootblock_sysent_rec entry[MS_NUMBER_OF_SYSTEM_ENTRY]; 33433842cedSCho, Yu-Chen }; 33533842cedSCho, Yu-Chen 33633842cedSCho, Yu-Chen struct ms_bootblock_sysinf { 33733842cedSCho, Yu-Chen u8 bMsClass; /* must be 1 */ 33833842cedSCho, Yu-Chen u8 bCardType; /* see below */ 33933842cedSCho, Yu-Chen u16 wBlockSize; /* n KB */ 34033842cedSCho, Yu-Chen u16 wBlockNumber; /* number of physical block */ 34133842cedSCho, Yu-Chen u16 wTotalBlockNumber; /* number of logical block */ 34233842cedSCho, Yu-Chen u16 wPageSize; /* must be 0x200 */ 34333842cedSCho, Yu-Chen u8 bExtraSize; /* 0x10 */ 34433842cedSCho, Yu-Chen u8 bSecuritySupport; 34533842cedSCho, Yu-Chen u8 bAssemblyDate[8]; 34633842cedSCho, Yu-Chen u8 bFactoryArea[4]; 34733842cedSCho, Yu-Chen u8 bAssemblyMakerCode; 34833842cedSCho, Yu-Chen u8 bAssemblyMachineCode[3]; 34933842cedSCho, Yu-Chen u16 wMemoryMakerCode; 35033842cedSCho, Yu-Chen u16 wMemoryDeviceCode; 35133842cedSCho, Yu-Chen u16 wMemorySize; 35233842cedSCho, Yu-Chen u8 bReserved1; 35333842cedSCho, Yu-Chen u8 bReserved2; 35433842cedSCho, Yu-Chen u8 bVCC; 35533842cedSCho, Yu-Chen u8 bVPP; 35633842cedSCho, Yu-Chen u16 wControllerChipNumber; 35733842cedSCho, Yu-Chen u16 wControllerFunction; /* New MS */ 35833842cedSCho, Yu-Chen u8 bReserved3[9]; /* New MS */ 35933842cedSCho, Yu-Chen u8 bParallelSupport; /* New MS */ 36033842cedSCho, Yu-Chen u16 wFormatValue; /* New MS */ 36133842cedSCho, Yu-Chen u8 bFormatType; 36233842cedSCho, Yu-Chen u8 bUsage; 36333842cedSCho, Yu-Chen u8 bDeviceType; 36433842cedSCho, Yu-Chen u8 bReserved4[22]; 36533842cedSCho, Yu-Chen u8 bFUValue3; 36633842cedSCho, Yu-Chen u8 bFUValue4; 36733842cedSCho, Yu-Chen u8 bReserved5[15]; 36833842cedSCho, Yu-Chen }; 36933842cedSCho, Yu-Chen 37033842cedSCho, Yu-Chen struct ms_bootblock_header { 37133842cedSCho, Yu-Chen u16 wBlockID; 37233842cedSCho, Yu-Chen u16 wFormatVersion; 37333842cedSCho, Yu-Chen u8 bReserved1[184]; 37433842cedSCho, Yu-Chen u8 bNumberOfDataEntry; 37533842cedSCho, Yu-Chen u8 bReserved2[179]; 37633842cedSCho, Yu-Chen }; 37733842cedSCho, Yu-Chen 37833842cedSCho, Yu-Chen struct ms_bootblock_page0 { 37933842cedSCho, Yu-Chen struct ms_bootblock_header header; 38033842cedSCho, Yu-Chen struct ms_bootblock_sysent sysent; 38133842cedSCho, Yu-Chen struct ms_bootblock_sysinf sysinf; 38233842cedSCho, Yu-Chen }; 38333842cedSCho, Yu-Chen 38433842cedSCho, Yu-Chen struct ms_bootblock_cis_idi { 38533842cedSCho, Yu-Chen union { 38633842cedSCho, Yu-Chen struct ms_bootblock_cis cis; 38733842cedSCho, Yu-Chen u8 dmy[256]; 38833842cedSCho, Yu-Chen } cis; 38933842cedSCho, Yu-Chen 39033842cedSCho, Yu-Chen union { 39133842cedSCho, Yu-Chen struct ms_bootblock_idi idi; 39233842cedSCho, Yu-Chen u8 dmy[256]; 39333842cedSCho, Yu-Chen } idi; 39433842cedSCho, Yu-Chen 39533842cedSCho, Yu-Chen }; 39633842cedSCho, Yu-Chen 39733842cedSCho, Yu-Chen /* ENE MS Lib struct */ 39833842cedSCho, Yu-Chen struct ms_lib_type_extdat { 39933842cedSCho, Yu-Chen u8 reserved; 40033842cedSCho, Yu-Chen u8 intr; 40133842cedSCho, Yu-Chen u8 status0; 40233842cedSCho, Yu-Chen u8 status1; 40333842cedSCho, Yu-Chen u8 ovrflg; 40433842cedSCho, Yu-Chen u8 mngflg; 40533842cedSCho, Yu-Chen u16 logadr; 40633842cedSCho, Yu-Chen }; 40733842cedSCho, Yu-Chen 40833842cedSCho, Yu-Chen struct ms_lib_ctrl { 40933842cedSCho, Yu-Chen u32 flags; 41033842cedSCho, Yu-Chen u32 BytesPerSector; 41133842cedSCho, Yu-Chen u32 NumberOfCylinder; 41233842cedSCho, Yu-Chen u32 SectorsPerCylinder; 41333842cedSCho, Yu-Chen u16 cardType; /* R/W, RO, Hybrid */ 41433842cedSCho, Yu-Chen u16 blockSize; 41533842cedSCho, Yu-Chen u16 PagesPerBlock; 41633842cedSCho, Yu-Chen u16 NumberOfPhyBlock; 41733842cedSCho, Yu-Chen u16 NumberOfLogBlock; 41833842cedSCho, Yu-Chen u16 NumberOfSegment; 41933842cedSCho, Yu-Chen u16 *Phy2LogMap; /* phy2log table */ 42033842cedSCho, Yu-Chen u16 *Log2PhyMap; /* log2phy table */ 42133842cedSCho, Yu-Chen u16 wrtblk; 42233842cedSCho, Yu-Chen unsigned char *pagemap[(MS_MAX_PAGES_PER_BLOCK + (MS_LIB_BITS_PER_BYTE-1)) / MS_LIB_BITS_PER_BYTE]; 42333842cedSCho, Yu-Chen unsigned char *blkpag; 42433842cedSCho, Yu-Chen struct ms_lib_type_extdat *blkext; 42533842cedSCho, Yu-Chen unsigned char copybuf[512]; 42633842cedSCho, Yu-Chen }; 42733842cedSCho, Yu-Chen 42841e568d1Shuajun li 42941e568d1Shuajun li /* SD Block Length */ 43041e568d1Shuajun li /* 2^9 = 512 Bytes, The HW maximum read/write data length */ 43141e568d1Shuajun li #define SD_BLOCK_LEN 9 43241e568d1Shuajun li 43341e568d1Shuajun li struct ene_ub6250_info { 434628c2893SAlan Stern 435628c2893SAlan Stern /* I/O bounce buffer */ 436628c2893SAlan Stern u8 *bbuf; 437628c2893SAlan Stern 43841e568d1Shuajun li /* for 6250 code */ 43941e568d1Shuajun li struct SD_STATUS SD_Status; 44041e568d1Shuajun li struct MS_STATUS MS_Status; 44141e568d1Shuajun li struct SM_STATUS SM_Status; 44241e568d1Shuajun li 44341e568d1Shuajun li /* ----- SD Control Data ---------------- */ 44441e568d1Shuajun li /*SD_REGISTER SD_Regs; */ 44541e568d1Shuajun li u16 SD_Block_Mult; 44641e568d1Shuajun li u8 SD_READ_BL_LEN; 44741e568d1Shuajun li u16 SD_C_SIZE; 44841e568d1Shuajun li u8 SD_C_SIZE_MULT; 44941e568d1Shuajun li 45041e568d1Shuajun li /* SD/MMC New spec. */ 45141e568d1Shuajun li u8 SD_SPEC_VER; 45241e568d1Shuajun li u8 SD_CSD_VER; 45341e568d1Shuajun li u8 SD20_HIGH_CAPACITY; 45441e568d1Shuajun li u32 HC_C_SIZE; 45541e568d1Shuajun li u8 MMC_SPEC_VER; 45641e568d1Shuajun li u8 MMC_BusWidth; 45741e568d1Shuajun li u8 MMC_HIGH_CAPACITY; 45841e568d1Shuajun li 45941e568d1Shuajun li /*----- MS Control Data ---------------- */ 46041e568d1Shuajun li bool MS_SWWP; 46141e568d1Shuajun li u32 MSP_TotalBlock; 46233842cedSCho, Yu-Chen struct ms_lib_ctrl MS_Lib; 46341e568d1Shuajun li bool MS_IsRWPage; 46441e568d1Shuajun li u16 MS_Model; 46541e568d1Shuajun li 46641e568d1Shuajun li /*----- SM Control Data ---------------- */ 46741e568d1Shuajun li u8 SM_DeviceID; 46841e568d1Shuajun li u8 SM_CardID; 46941e568d1Shuajun li 47041e568d1Shuajun li unsigned char *testbuf; 47141e568d1Shuajun li u8 BIN_FLAG; 47241e568d1Shuajun li u32 bl_num; 47341e568d1Shuajun li int SrbStatus; 47441e568d1Shuajun li 47541e568d1Shuajun li /*------Power Managerment ---------------*/ 47641e568d1Shuajun li bool Power_IsResum; 47741e568d1Shuajun li }; 47841e568d1Shuajun li 47941e568d1Shuajun li static int ene_sd_init(struct us_data *us); 48033842cedSCho, Yu-Chen static int ene_ms_init(struct us_data *us); 48141e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag); 48241e568d1Shuajun li 48341e568d1Shuajun li static void ene_ub6250_info_destructor(void *extra) 48441e568d1Shuajun li { 485628c2893SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra; 486628c2893SAlan Stern 48741e568d1Shuajun li if (!extra) 48841e568d1Shuajun li return; 489628c2893SAlan Stern kfree(info->bbuf); 49041e568d1Shuajun li } 49141e568d1Shuajun li 49241e568d1Shuajun li static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) 49341e568d1Shuajun li { 49441e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 49541e568d1Shuajun li struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf; 49641e568d1Shuajun li 49741e568d1Shuajun li int result; 49841e568d1Shuajun li unsigned int residue; 49941e568d1Shuajun li unsigned int cswlen = 0, partial = 0; 50041e568d1Shuajun li unsigned int transfer_length = bcb->DataTransferLength; 50141e568d1Shuajun li 502191648d0SJoe Perches /* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */ 50341e568d1Shuajun li /* send cmd to out endpoint */ 50441e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe, 50541e568d1Shuajun li bcb, US_BULK_CB_WRAP_LEN, NULL); 50641e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 507191648d0SJoe Perches usb_stor_dbg(us, "send cmd to out endpoint fail ---\n"); 50841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 50941e568d1Shuajun li } 51041e568d1Shuajun li 51141e568d1Shuajun li if (buf) { 51241e568d1Shuajun li unsigned int pipe = fDir; 51341e568d1Shuajun li 51441e568d1Shuajun li if (fDir == FDIR_READ) 51541e568d1Shuajun li pipe = us->recv_bulk_pipe; 51641e568d1Shuajun li else 51741e568d1Shuajun li pipe = us->send_bulk_pipe; 51841e568d1Shuajun li 51941e568d1Shuajun li /* Bulk */ 52041e568d1Shuajun li if (use_sg) { 52141e568d1Shuajun li result = usb_stor_bulk_srb(us, pipe, us->srb); 52241e568d1Shuajun li } else { 52341e568d1Shuajun li result = usb_stor_bulk_transfer_sg(us, pipe, buf, 52441e568d1Shuajun li transfer_length, 0, &partial); 52541e568d1Shuajun li } 52641e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 527191648d0SJoe Perches usb_stor_dbg(us, "data transfer fail ---\n"); 52841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 52941e568d1Shuajun li } 53041e568d1Shuajun li } 53141e568d1Shuajun li 53241e568d1Shuajun li /* Get CSW for device status */ 53341e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs, 53441e568d1Shuajun li US_BULK_CS_WRAP_LEN, &cswlen); 53541e568d1Shuajun li 53641e568d1Shuajun li if (result == USB_STOR_XFER_SHORT && cswlen == 0) { 537191648d0SJoe Perches usb_stor_dbg(us, "Received 0-length CSW; retrying...\n"); 53841e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 53941e568d1Shuajun li bcs, US_BULK_CS_WRAP_LEN, &cswlen); 54041e568d1Shuajun li } 54141e568d1Shuajun li 54241e568d1Shuajun li if (result == USB_STOR_XFER_STALLED) { 54341e568d1Shuajun li /* get the status again */ 544191648d0SJoe Perches usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n"); 54541e568d1Shuajun li result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, 54641e568d1Shuajun li bcs, US_BULK_CS_WRAP_LEN, NULL); 54741e568d1Shuajun li } 54841e568d1Shuajun li 54941e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) 55041e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 55141e568d1Shuajun li 55241e568d1Shuajun li /* check bulk status */ 55341e568d1Shuajun li residue = le32_to_cpu(bcs->Residue); 55441e568d1Shuajun li 555f0183a33SFelipe Balbi /* 556f0183a33SFelipe Balbi * try to compute the actual residue, based on how much data 557f0183a33SFelipe Balbi * was really transferred and what the device tells us 558f0183a33SFelipe Balbi */ 55941e568d1Shuajun li if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) { 56041e568d1Shuajun li residue = min(residue, transfer_length); 56141e568d1Shuajun li if (us->srb != NULL) 56241e568d1Shuajun li scsi_set_resid(us->srb, max(scsi_get_resid(us->srb), 56341e568d1Shuajun li (int)residue)); 56441e568d1Shuajun li } 56541e568d1Shuajun li 56641e568d1Shuajun li if (bcs->Status != US_BULK_STAT_OK) 56741e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 56841e568d1Shuajun li 56941e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 57041e568d1Shuajun li } 57141e568d1Shuajun li 572ce553bd1SAlan Stern static int do_scsi_request_sense(struct us_data *us, struct scsi_cmnd *srb) 573ce553bd1SAlan Stern { 574ce553bd1SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 575ce553bd1SAlan Stern unsigned char buf[18]; 576ce553bd1SAlan Stern 577ce553bd1SAlan Stern memset(buf, 0, 18); 578ce553bd1SAlan Stern buf[0] = 0x70; /* Current error */ 579ce553bd1SAlan Stern buf[2] = info->SrbStatus >> 16; /* Sense key */ 580ce553bd1SAlan Stern buf[7] = 10; /* Additional length */ 581ce553bd1SAlan Stern buf[12] = info->SrbStatus >> 8; /* ASC */ 582ce553bd1SAlan Stern buf[13] = info->SrbStatus; /* ASCQ */ 583ce553bd1SAlan Stern 584ce553bd1SAlan Stern usb_stor_set_xfer_buf(buf, sizeof(buf), srb); 585ce553bd1SAlan Stern return USB_STOR_TRANSPORT_GOOD; 586ce553bd1SAlan Stern } 587ce553bd1SAlan Stern 588f8efdabdSAlan Stern static int do_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb) 589f8efdabdSAlan Stern { 590f8efdabdSAlan Stern unsigned char data_ptr[36] = { 5915fcf9379SAlan Stern 0x00, 0x00, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55, 592f8efdabdSAlan Stern 0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61, 593f8efdabdSAlan Stern 0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20, 594f8efdabdSAlan Stern 0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 }; 595f8efdabdSAlan Stern 596f8efdabdSAlan Stern usb_stor_set_xfer_buf(data_ptr, 36, srb); 597f8efdabdSAlan Stern return USB_STOR_TRANSPORT_GOOD; 598f8efdabdSAlan Stern } 599f8efdabdSAlan Stern 60041e568d1Shuajun li static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) 60141e568d1Shuajun li { 60241e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 60341e568d1Shuajun li 60441e568d1Shuajun li if (info->SD_Status.Insert && info->SD_Status.Ready) 60541e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 60641e568d1Shuajun li else { 60741e568d1Shuajun li ene_sd_init(us); 60841e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 60941e568d1Shuajun li } 61041e568d1Shuajun li 61141e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 61241e568d1Shuajun li } 61341e568d1Shuajun li 61441e568d1Shuajun li static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) 61541e568d1Shuajun li { 61641e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 61741e568d1Shuajun li unsigned char mediaNoWP[12] = { 61841e568d1Shuajun li 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, 61941e568d1Shuajun li 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; 62041e568d1Shuajun li unsigned char mediaWP[12] = { 62141e568d1Shuajun li 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 62241e568d1Shuajun li 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; 62341e568d1Shuajun li 62441e568d1Shuajun li if (info->SD_Status.WtP) 62541e568d1Shuajun li usb_stor_set_xfer_buf(mediaWP, 12, srb); 62641e568d1Shuajun li else 62741e568d1Shuajun li usb_stor_set_xfer_buf(mediaNoWP, 12, srb); 62841e568d1Shuajun li 62941e568d1Shuajun li 63041e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 63141e568d1Shuajun li } 63241e568d1Shuajun li 63341e568d1Shuajun li static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) 63441e568d1Shuajun li { 63541e568d1Shuajun li u32 bl_num; 63636f3a14dSFelipe Balbi u32 bl_len; 63741e568d1Shuajun li unsigned int offset = 0; 63841e568d1Shuajun li unsigned char buf[8]; 63941e568d1Shuajun li struct scatterlist *sg = NULL; 64041e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 64141e568d1Shuajun li 642191648d0SJoe Perches usb_stor_dbg(us, "sd_scsi_read_capacity\n"); 64341e568d1Shuajun li if (info->SD_Status.HiCapacity) { 64441e568d1Shuajun li bl_len = 0x200; 64541e568d1Shuajun li if (info->SD_Status.IsMMC) 64641e568d1Shuajun li bl_num = info->HC_C_SIZE-1; 64741e568d1Shuajun li else 64841e568d1Shuajun li bl_num = (info->HC_C_SIZE + 1) * 1024 - 1; 64941e568d1Shuajun li } else { 65041e568d1Shuajun li bl_len = 1 << (info->SD_READ_BL_LEN); 65141e568d1Shuajun li bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1) 65241e568d1Shuajun li * (1 << (info->SD_C_SIZE_MULT + 2)) - 1; 65341e568d1Shuajun li } 65441e568d1Shuajun li info->bl_num = bl_num; 655191648d0SJoe Perches usb_stor_dbg(us, "bl_len = %x\n", bl_len); 656191648d0SJoe Perches usb_stor_dbg(us, "bl_num = %x\n", bl_num); 65741e568d1Shuajun li 65841e568d1Shuajun li /*srb->request_bufflen = 8; */ 65941e568d1Shuajun li buf[0] = (bl_num >> 24) & 0xff; 66041e568d1Shuajun li buf[1] = (bl_num >> 16) & 0xff; 66141e568d1Shuajun li buf[2] = (bl_num >> 8) & 0xff; 66241e568d1Shuajun li buf[3] = (bl_num >> 0) & 0xff; 66341e568d1Shuajun li buf[4] = (bl_len >> 24) & 0xff; 66441e568d1Shuajun li buf[5] = (bl_len >> 16) & 0xff; 66541e568d1Shuajun li buf[6] = (bl_len >> 8) & 0xff; 66641e568d1Shuajun li buf[7] = (bl_len >> 0) & 0xff; 66741e568d1Shuajun li 66841e568d1Shuajun li usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF); 66941e568d1Shuajun li 67041e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 67141e568d1Shuajun li } 67241e568d1Shuajun li 67341e568d1Shuajun li static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb) 67441e568d1Shuajun li { 67541e568d1Shuajun li int result; 67641e568d1Shuajun li unsigned char *cdb = srb->cmnd; 67741e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 67841e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 67941e568d1Shuajun li 68041e568d1Shuajun li u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | 68141e568d1Shuajun li ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); 68241e568d1Shuajun li u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); 68341e568d1Shuajun li u32 bnByte = bn * 0x200; 68441e568d1Shuajun li u32 blenByte = blen * 0x200; 68541e568d1Shuajun li 68641e568d1Shuajun li if (bn > info->bl_num) 68741e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 68841e568d1Shuajun li 68941e568d1Shuajun li result = ene_load_bincode(us, SD_RW_PATTERN); 69041e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 691191648d0SJoe Perches usb_stor_dbg(us, "Load SD RW pattern Fail !!\n"); 69241e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 69341e568d1Shuajun li } 69441e568d1Shuajun li 69541e568d1Shuajun li if (info->SD_Status.HiCapacity) 69641e568d1Shuajun li bnByte = bn; 69741e568d1Shuajun li 69841e568d1Shuajun li /* set up the command wrapper */ 69941e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 70041e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 70141e568d1Shuajun li bcb->DataTransferLength = blenByte; 702b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 70341e568d1Shuajun li bcb->CDB[0] = 0xF1; 70441e568d1Shuajun li bcb->CDB[5] = (unsigned char)(bnByte); 70541e568d1Shuajun li bcb->CDB[4] = (unsigned char)(bnByte>>8); 70641e568d1Shuajun li bcb->CDB[3] = (unsigned char)(bnByte>>16); 70741e568d1Shuajun li bcb->CDB[2] = (unsigned char)(bnByte>>24); 70841e568d1Shuajun li 70941e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1); 71041e568d1Shuajun li return result; 71141e568d1Shuajun li } 71241e568d1Shuajun li 71341e568d1Shuajun li static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb) 71441e568d1Shuajun li { 71541e568d1Shuajun li int result; 71641e568d1Shuajun li unsigned char *cdb = srb->cmnd; 71741e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 71841e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 71941e568d1Shuajun li 72041e568d1Shuajun li u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | 72141e568d1Shuajun li ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); 72241e568d1Shuajun li u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); 72341e568d1Shuajun li u32 bnByte = bn * 0x200; 72441e568d1Shuajun li u32 blenByte = blen * 0x200; 72541e568d1Shuajun li 72641e568d1Shuajun li if (bn > info->bl_num) 72741e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 72841e568d1Shuajun li 72941e568d1Shuajun li result = ene_load_bincode(us, SD_RW_PATTERN); 73041e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 731191648d0SJoe Perches usb_stor_dbg(us, "Load SD RW pattern Fail !!\n"); 73241e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 73341e568d1Shuajun li } 73441e568d1Shuajun li 73541e568d1Shuajun li if (info->SD_Status.HiCapacity) 73641e568d1Shuajun li bnByte = bn; 73741e568d1Shuajun li 73841e568d1Shuajun li /* set up the command wrapper */ 73941e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 74041e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 74141e568d1Shuajun li bcb->DataTransferLength = blenByte; 74241e568d1Shuajun li bcb->Flags = 0x00; 74341e568d1Shuajun li bcb->CDB[0] = 0xF0; 74441e568d1Shuajun li bcb->CDB[5] = (unsigned char)(bnByte); 74541e568d1Shuajun li bcb->CDB[4] = (unsigned char)(bnByte>>8); 74641e568d1Shuajun li bcb->CDB[3] = (unsigned char)(bnByte>>16); 74741e568d1Shuajun li bcb->CDB[2] = (unsigned char)(bnByte>>24); 74841e568d1Shuajun li 74941e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1); 75041e568d1Shuajun li return result; 75141e568d1Shuajun li } 75241e568d1Shuajun li 75333842cedSCho, Yu-Chen /* 75433842cedSCho, Yu-Chen * ENE MS Card 75533842cedSCho, Yu-Chen */ 75633842cedSCho, Yu-Chen 75733842cedSCho, Yu-Chen static int ms_lib_set_logicalpair(struct us_data *us, u16 logblk, u16 phyblk) 75833842cedSCho, Yu-Chen { 75933842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 76033842cedSCho, Yu-Chen 76133842cedSCho, Yu-Chen if ((logblk >= info->MS_Lib.NumberOfLogBlock) || (phyblk >= info->MS_Lib.NumberOfPhyBlock)) 76233842cedSCho, Yu-Chen return (u32)-1; 76333842cedSCho, Yu-Chen 76433842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = logblk; 76533842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[logblk] = phyblk; 76633842cedSCho, Yu-Chen 76733842cedSCho, Yu-Chen return 0; 76833842cedSCho, Yu-Chen } 76933842cedSCho, Yu-Chen 77033842cedSCho, Yu-Chen static int ms_lib_set_logicalblockmark(struct us_data *us, u16 phyblk, u16 mark) 77133842cedSCho, Yu-Chen { 77233842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 77333842cedSCho, Yu-Chen 77433842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock) 77533842cedSCho, Yu-Chen return (u32)-1; 77633842cedSCho, Yu-Chen 77733842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = mark; 77833842cedSCho, Yu-Chen 77933842cedSCho, Yu-Chen return 0; 78033842cedSCho, Yu-Chen } 78133842cedSCho, Yu-Chen 78233842cedSCho, Yu-Chen static int ms_lib_set_initialerrorblock(struct us_data *us, u16 phyblk) 78333842cedSCho, Yu-Chen { 78433842cedSCho, Yu-Chen return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_INITIAL_ERROR); 78533842cedSCho, Yu-Chen } 78633842cedSCho, Yu-Chen 78733842cedSCho, Yu-Chen static int ms_lib_set_bootblockmark(struct us_data *us, u16 phyblk) 78833842cedSCho, Yu-Chen { 78933842cedSCho, Yu-Chen return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_BOOT_BLOCK); 79033842cedSCho, Yu-Chen } 79133842cedSCho, Yu-Chen 79233842cedSCho, Yu-Chen static int ms_lib_free_logicalmap(struct us_data *us) 79333842cedSCho, Yu-Chen { 79433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 79533842cedSCho, Yu-Chen 79633842cedSCho, Yu-Chen kfree(info->MS_Lib.Phy2LogMap); 79733842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap = NULL; 79833842cedSCho, Yu-Chen 79933842cedSCho, Yu-Chen kfree(info->MS_Lib.Log2PhyMap); 80033842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap = NULL; 80133842cedSCho, Yu-Chen 80233842cedSCho, Yu-Chen return 0; 80333842cedSCho, Yu-Chen } 80433842cedSCho, Yu-Chen 80536f3a14dSFelipe Balbi static int ms_lib_alloc_logicalmap(struct us_data *us) 80633842cedSCho, Yu-Chen { 80733842cedSCho, Yu-Chen u32 i; 80833842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 80933842cedSCho, Yu-Chen 8106da2ec56SKees Cook info->MS_Lib.Phy2LogMap = kmalloc_array(info->MS_Lib.NumberOfPhyBlock, 8116da2ec56SKees Cook sizeof(u16), 8126da2ec56SKees Cook GFP_KERNEL); 8136da2ec56SKees Cook info->MS_Lib.Log2PhyMap = kmalloc_array(info->MS_Lib.NumberOfLogBlock, 8146da2ec56SKees Cook sizeof(u16), 8156da2ec56SKees Cook GFP_KERNEL); 81633842cedSCho, Yu-Chen 81733842cedSCho, Yu-Chen if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) { 81833842cedSCho, Yu-Chen ms_lib_free_logicalmap(us); 81933842cedSCho, Yu-Chen return (u32)-1; 82033842cedSCho, Yu-Chen } 82133842cedSCho, Yu-Chen 82233842cedSCho, Yu-Chen for (i = 0; i < info->MS_Lib.NumberOfPhyBlock; i++) 82333842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[i] = MS_LB_NOT_USED; 82433842cedSCho, Yu-Chen 82533842cedSCho, Yu-Chen for (i = 0; i < info->MS_Lib.NumberOfLogBlock; i++) 82633842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[i] = MS_LB_NOT_USED; 82733842cedSCho, Yu-Chen 82833842cedSCho, Yu-Chen return 0; 82933842cedSCho, Yu-Chen } 83033842cedSCho, Yu-Chen 83133842cedSCho, Yu-Chen static void ms_lib_clear_writebuf(struct us_data *us) 83233842cedSCho, Yu-Chen { 83333842cedSCho, Yu-Chen int i; 83433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 83533842cedSCho, Yu-Chen 83633842cedSCho, Yu-Chen info->MS_Lib.wrtblk = (u16)-1; 83733842cedSCho, Yu-Chen ms_lib_clear_pagemap(info); 83833842cedSCho, Yu-Chen 83933842cedSCho, Yu-Chen if (info->MS_Lib.blkpag) 84033842cedSCho, Yu-Chen memset(info->MS_Lib.blkpag, 0xff, info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector); 84133842cedSCho, Yu-Chen 84233842cedSCho, Yu-Chen if (info->MS_Lib.blkext) { 84333842cedSCho, Yu-Chen for (i = 0; i < info->MS_Lib.PagesPerBlock; i++) { 84433842cedSCho, Yu-Chen info->MS_Lib.blkext[i].status1 = MS_REG_ST1_DEFAULT; 84533842cedSCho, Yu-Chen info->MS_Lib.blkext[i].ovrflg = MS_REG_OVR_DEFAULT; 84633842cedSCho, Yu-Chen info->MS_Lib.blkext[i].mngflg = MS_REG_MNG_DEFAULT; 84733842cedSCho, Yu-Chen info->MS_Lib.blkext[i].logadr = MS_LB_NOT_USED; 84833842cedSCho, Yu-Chen } 84933842cedSCho, Yu-Chen } 85033842cedSCho, Yu-Chen } 85133842cedSCho, Yu-Chen 85233842cedSCho, Yu-Chen static int ms_count_freeblock(struct us_data *us, u16 PhyBlock) 85333842cedSCho, Yu-Chen { 85433842cedSCho, Yu-Chen u32 Ende, Count; 85533842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 85633842cedSCho, Yu-Chen 85733842cedSCho, Yu-Chen Ende = PhyBlock + MS_PHYSICAL_BLOCKS_PER_SEGMENT; 85833842cedSCho, Yu-Chen for (Count = 0; PhyBlock < Ende; PhyBlock++) { 85933842cedSCho, Yu-Chen switch (info->MS_Lib.Phy2LogMap[PhyBlock]) { 86033842cedSCho, Yu-Chen case MS_LB_NOT_USED: 86133842cedSCho, Yu-Chen case MS_LB_NOT_USED_ERASED: 86233842cedSCho, Yu-Chen Count++; 86333842cedSCho, Yu-Chen default: 86433842cedSCho, Yu-Chen break; 86533842cedSCho, Yu-Chen } 86633842cedSCho, Yu-Chen } 86733842cedSCho, Yu-Chen 86833842cedSCho, Yu-Chen return Count; 86933842cedSCho, Yu-Chen } 87033842cedSCho, Yu-Chen 87133842cedSCho, Yu-Chen static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr, 87233842cedSCho, Yu-Chen u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat) 87333842cedSCho, Yu-Chen { 87433842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 875628c2893SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 876628c2893SAlan Stern u8 *bbuf = info->bbuf; 87733842cedSCho, Yu-Chen int result; 87833842cedSCho, Yu-Chen u32 bn = PhyBlockAddr * 0x20 + PageNum; 87933842cedSCho, Yu-Chen 88033842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN); 88133842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 88233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 88333842cedSCho, Yu-Chen 88433842cedSCho, Yu-Chen /* Read Page Data */ 88533842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 88633842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 88733842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200; 888b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 88933842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 89033842cedSCho, Yu-Chen 89133842cedSCho, Yu-Chen bcb->CDB[1] = 0x02; /* in init.c ENE_MSInit() is 0x01 */ 89233842cedSCho, Yu-Chen 89333842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(bn); 89433842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn>>8); 89533842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>16); 89633842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>24); 89733842cedSCho, Yu-Chen 89833842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, PageBuf, 0); 89933842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 90033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 90133842cedSCho, Yu-Chen 90233842cedSCho, Yu-Chen 90333842cedSCho, Yu-Chen /* Read Extra Data */ 90433842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 90533842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 90633842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4; 907b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 90833842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 90933842cedSCho, Yu-Chen bcb->CDB[1] = 0x03; 91033842cedSCho, Yu-Chen 91133842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum); 91233842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlockAddr); 91333842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8); 91433842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16); 91533842cedSCho, Yu-Chen bcb->CDB[6] = 0x01; 91633842cedSCho, Yu-Chen 917628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0); 91833842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 91933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 92033842cedSCho, Yu-Chen 92133842cedSCho, Yu-Chen ExtraDat->reserved = 0; 92233842cedSCho, Yu-Chen ExtraDat->intr = 0x80; /* Not yet,fireware support */ 92333842cedSCho, Yu-Chen ExtraDat->status0 = 0x10; /* Not yet,fireware support */ 92433842cedSCho, Yu-Chen 92533842cedSCho, Yu-Chen ExtraDat->status1 = 0x00; /* Not yet,fireware support */ 926628c2893SAlan Stern ExtraDat->ovrflg = bbuf[0]; 927628c2893SAlan Stern ExtraDat->mngflg = bbuf[1]; 928628c2893SAlan Stern ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]); 92933842cedSCho, Yu-Chen 93033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 93133842cedSCho, Yu-Chen } 93233842cedSCho, Yu-Chen 93333842cedSCho, Yu-Chen static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageData) 93433842cedSCho, Yu-Chen { 93533842cedSCho, Yu-Chen struct ms_bootblock_sysent *SysEntry; 93633842cedSCho, Yu-Chen struct ms_bootblock_sysinf *SysInfo; 93733842cedSCho, Yu-Chen u32 i, result; 93833842cedSCho, Yu-Chen u8 PageNumber; 93933842cedSCho, Yu-Chen u8 *PageBuffer; 94033842cedSCho, Yu-Chen struct ms_lib_type_extdat ExtraData; 94133842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 94233842cedSCho, Yu-Chen 94333842cedSCho, Yu-Chen PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); 94433842cedSCho, Yu-Chen if (PageBuffer == NULL) 94533842cedSCho, Yu-Chen return (u32)-1; 94633842cedSCho, Yu-Chen 94733842cedSCho, Yu-Chen result = (u32)-1; 94833842cedSCho, Yu-Chen 94933842cedSCho, Yu-Chen SysInfo = &(((struct ms_bootblock_page0 *)PageData)->sysinf); 95033842cedSCho, Yu-Chen 95133842cedSCho, Yu-Chen if ((SysInfo->bMsClass != MS_SYSINF_MSCLASS_TYPE_1) || 95233842cedSCho, Yu-Chen (be16_to_cpu(SysInfo->wPageSize) != MS_SYSINF_PAGE_SIZE) || 95333842cedSCho, Yu-Chen ((SysInfo->bSecuritySupport & MS_SYSINF_SECURITY) == MS_SYSINF_SECURITY_SUPPORT) || 95433842cedSCho, Yu-Chen (SysInfo->bReserved1 != MS_SYSINF_RESERVED1) || 95533842cedSCho, Yu-Chen (SysInfo->bReserved2 != MS_SYSINF_RESERVED2) || 95633842cedSCho, Yu-Chen (SysInfo->bFormatType != MS_SYSINF_FORMAT_FAT) || 95733842cedSCho, Yu-Chen (SysInfo->bUsage != MS_SYSINF_USAGE_GENERAL)) 95833842cedSCho, Yu-Chen goto exit; 95933842cedSCho, Yu-Chen /* */ 96033842cedSCho, Yu-Chen switch (info->MS_Lib.cardType = SysInfo->bCardType) { 96133842cedSCho, Yu-Chen case MS_SYSINF_CARDTYPE_RDONLY: 96233842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); 96333842cedSCho, Yu-Chen break; 96433842cedSCho, Yu-Chen case MS_SYSINF_CARDTYPE_RDWR: 96533842cedSCho, Yu-Chen ms_lib_ctrl_reset(info, MS_LIB_CTRL_RDONLY); 96633842cedSCho, Yu-Chen break; 96733842cedSCho, Yu-Chen case MS_SYSINF_CARDTYPE_HYBRID: 96833842cedSCho, Yu-Chen default: 96933842cedSCho, Yu-Chen goto exit; 97033842cedSCho, Yu-Chen } 97133842cedSCho, Yu-Chen 97233842cedSCho, Yu-Chen info->MS_Lib.blockSize = be16_to_cpu(SysInfo->wBlockSize); 97333842cedSCho, Yu-Chen info->MS_Lib.NumberOfPhyBlock = be16_to_cpu(SysInfo->wBlockNumber); 97433842cedSCho, Yu-Chen info->MS_Lib.NumberOfLogBlock = be16_to_cpu(SysInfo->wTotalBlockNumber)-2; 97533842cedSCho, Yu-Chen info->MS_Lib.PagesPerBlock = info->MS_Lib.blockSize * SIZE_OF_KIRO / MS_BYTES_PER_PAGE; 97633842cedSCho, Yu-Chen info->MS_Lib.NumberOfSegment = info->MS_Lib.NumberOfPhyBlock / MS_PHYSICAL_BLOCKS_PER_SEGMENT; 97733842cedSCho, Yu-Chen info->MS_Model = be16_to_cpu(SysInfo->wMemorySize); 97833842cedSCho, Yu-Chen 97933842cedSCho, Yu-Chen /*Allocate to all number of logicalblock and physicalblock */ 98033842cedSCho, Yu-Chen if (ms_lib_alloc_logicalmap(us)) 98133842cedSCho, Yu-Chen goto exit; 98233842cedSCho, Yu-Chen 98333842cedSCho, Yu-Chen /* Mark the book block */ 98433842cedSCho, Yu-Chen ms_lib_set_bootblockmark(us, PhyBlock); 98533842cedSCho, Yu-Chen 98633842cedSCho, Yu-Chen SysEntry = &(((struct ms_bootblock_page0 *)PageData)->sysent); 98733842cedSCho, Yu-Chen 98833842cedSCho, Yu-Chen for (i = 0; i < MS_NUMBER_OF_SYSTEM_ENTRY; i++) { 98933842cedSCho, Yu-Chen u32 EntryOffset, EntrySize; 99033842cedSCho, Yu-Chen 99133842cedSCho, Yu-Chen EntryOffset = be32_to_cpu(SysEntry->entry[i].dwStart); 99233842cedSCho, Yu-Chen 99333842cedSCho, Yu-Chen if (EntryOffset == 0xffffff) 99433842cedSCho, Yu-Chen continue; 99533842cedSCho, Yu-Chen EntrySize = be32_to_cpu(SysEntry->entry[i].dwSize); 99633842cedSCho, Yu-Chen 99733842cedSCho, Yu-Chen if (EntrySize == 0) 99833842cedSCho, Yu-Chen continue; 99933842cedSCho, Yu-Chen 100033842cedSCho, Yu-Chen if (EntryOffset + MS_BYTES_PER_PAGE + EntrySize > info->MS_Lib.blockSize * (u32)SIZE_OF_KIRO) 100133842cedSCho, Yu-Chen continue; 100233842cedSCho, Yu-Chen 100333842cedSCho, Yu-Chen if (i == 0) { 100433842cedSCho, Yu-Chen u8 PrevPageNumber = 0; 100533842cedSCho, Yu-Chen u16 phyblk; 100633842cedSCho, Yu-Chen 100733842cedSCho, Yu-Chen if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_INVALID_BLOCK) 100833842cedSCho, Yu-Chen goto exit; 100933842cedSCho, Yu-Chen 101033842cedSCho, Yu-Chen while (EntrySize > 0) { 101133842cedSCho, Yu-Chen 101233842cedSCho, Yu-Chen PageNumber = (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1); 101333842cedSCho, Yu-Chen if (PageNumber != PrevPageNumber) { 101433842cedSCho, Yu-Chen switch (ms_read_readpage(us, PhyBlock, PageNumber, (u32 *)PageBuffer, &ExtraData)) { 101533842cedSCho, Yu-Chen case MS_STATUS_SUCCESS: 101633842cedSCho, Yu-Chen break; 101733842cedSCho, Yu-Chen case MS_STATUS_WRITE_PROTECT: 101833842cedSCho, Yu-Chen case MS_ERROR_FLASH_READ: 101933842cedSCho, Yu-Chen case MS_STATUS_ERROR: 102033842cedSCho, Yu-Chen default: 102133842cedSCho, Yu-Chen goto exit; 102233842cedSCho, Yu-Chen } 102333842cedSCho, Yu-Chen 102433842cedSCho, Yu-Chen PrevPageNumber = PageNumber; 102533842cedSCho, Yu-Chen } 102633842cedSCho, Yu-Chen 102733842cedSCho, Yu-Chen phyblk = be16_to_cpu(*(u16 *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE))); 102833842cedSCho, Yu-Chen if (phyblk < 0x0fff) 102933842cedSCho, Yu-Chen ms_lib_set_initialerrorblock(us, phyblk); 103033842cedSCho, Yu-Chen 103133842cedSCho, Yu-Chen EntryOffset += 2; 103233842cedSCho, Yu-Chen EntrySize -= 2; 103333842cedSCho, Yu-Chen } 103433842cedSCho, Yu-Chen } else if (i == 1) { /* CIS/IDI */ 103533842cedSCho, Yu-Chen struct ms_bootblock_idi *idi; 103633842cedSCho, Yu-Chen 103733842cedSCho, Yu-Chen if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_CIS_IDI) 103833842cedSCho, Yu-Chen goto exit; 103933842cedSCho, Yu-Chen 104033842cedSCho, Yu-Chen switch (ms_read_readpage(us, PhyBlock, (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1), (u32 *)PageBuffer, &ExtraData)) { 104133842cedSCho, Yu-Chen case MS_STATUS_SUCCESS: 104233842cedSCho, Yu-Chen break; 104333842cedSCho, Yu-Chen case MS_STATUS_WRITE_PROTECT: 104433842cedSCho, Yu-Chen case MS_ERROR_FLASH_READ: 104533842cedSCho, Yu-Chen case MS_STATUS_ERROR: 104633842cedSCho, Yu-Chen default: 104733842cedSCho, Yu-Chen goto exit; 104833842cedSCho, Yu-Chen } 104933842cedSCho, Yu-Chen 105033842cedSCho, Yu-Chen idi = &((struct ms_bootblock_cis_idi *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)))->idi.idi; 105133842cedSCho, Yu-Chen if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF) 105233842cedSCho, Yu-Chen goto exit; 105333842cedSCho, Yu-Chen 105433842cedSCho, Yu-Chen info->MS_Lib.BytesPerSector = le16_to_cpu(idi->wIDIbytesPerSector); 105533842cedSCho, Yu-Chen if (info->MS_Lib.BytesPerSector != MS_BYTES_PER_PAGE) 105633842cedSCho, Yu-Chen goto exit; 105733842cedSCho, Yu-Chen } 105833842cedSCho, Yu-Chen } /* End for .. */ 105933842cedSCho, Yu-Chen 106033842cedSCho, Yu-Chen result = 0; 106133842cedSCho, Yu-Chen 106233842cedSCho, Yu-Chen exit: 106333842cedSCho, Yu-Chen if (result) 106433842cedSCho, Yu-Chen ms_lib_free_logicalmap(us); 106533842cedSCho, Yu-Chen 106633842cedSCho, Yu-Chen kfree(PageBuffer); 106733842cedSCho, Yu-Chen 106833842cedSCho, Yu-Chen result = 0; 106933842cedSCho, Yu-Chen return result; 107033842cedSCho, Yu-Chen } 107133842cedSCho, Yu-Chen 107233842cedSCho, Yu-Chen static void ms_lib_free_writebuf(struct us_data *us) 107333842cedSCho, Yu-Chen { 107433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 107533842cedSCho, Yu-Chen info->MS_Lib.wrtblk = (u16)-1; /* set to -1 */ 107633842cedSCho, Yu-Chen 107733842cedSCho, Yu-Chen /* memset((fdoExt)->MS_Lib.pagemap, 0, sizeof((fdoExt)->MS_Lib.pagemap)) */ 107833842cedSCho, Yu-Chen 107933842cedSCho, Yu-Chen ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */ 108033842cedSCho, Yu-Chen 108133842cedSCho, Yu-Chen if (info->MS_Lib.blkpag) { 1082e6533e87SAmitoj Kaur Chawla kfree(info->MS_Lib.blkpag); /* Arnold test ... */ 108333842cedSCho, Yu-Chen info->MS_Lib.blkpag = NULL; 108433842cedSCho, Yu-Chen } 108533842cedSCho, Yu-Chen 108633842cedSCho, Yu-Chen if (info->MS_Lib.blkext) { 1087e6533e87SAmitoj Kaur Chawla kfree(info->MS_Lib.blkext); /* Arnold test ... */ 108833842cedSCho, Yu-Chen info->MS_Lib.blkext = NULL; 108933842cedSCho, Yu-Chen } 109033842cedSCho, Yu-Chen } 109133842cedSCho, Yu-Chen 109233842cedSCho, Yu-Chen 109333842cedSCho, Yu-Chen static void ms_lib_free_allocatedarea(struct us_data *us) 109433842cedSCho, Yu-Chen { 109533842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 109633842cedSCho, Yu-Chen 109733842cedSCho, Yu-Chen ms_lib_free_writebuf(us); /* Free MS_Lib.pagemap */ 109833842cedSCho, Yu-Chen ms_lib_free_logicalmap(us); /* kfree MS_Lib.Phy2LogMap and MS_Lib.Log2PhyMap */ 109933842cedSCho, Yu-Chen 110033842cedSCho, Yu-Chen /* set struct us point flag to 0 */ 110133842cedSCho, Yu-Chen info->MS_Lib.flags = 0; 110233842cedSCho, Yu-Chen info->MS_Lib.BytesPerSector = 0; 110333842cedSCho, Yu-Chen info->MS_Lib.SectorsPerCylinder = 0; 110433842cedSCho, Yu-Chen 110533842cedSCho, Yu-Chen info->MS_Lib.cardType = 0; 110633842cedSCho, Yu-Chen info->MS_Lib.blockSize = 0; 110733842cedSCho, Yu-Chen info->MS_Lib.PagesPerBlock = 0; 110833842cedSCho, Yu-Chen 110933842cedSCho, Yu-Chen info->MS_Lib.NumberOfPhyBlock = 0; 111033842cedSCho, Yu-Chen info->MS_Lib.NumberOfLogBlock = 0; 111133842cedSCho, Yu-Chen } 111233842cedSCho, Yu-Chen 111333842cedSCho, Yu-Chen 111433842cedSCho, Yu-Chen static int ms_lib_alloc_writebuf(struct us_data *us) 111533842cedSCho, Yu-Chen { 111633842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 111733842cedSCho, Yu-Chen 111833842cedSCho, Yu-Chen info->MS_Lib.wrtblk = (u16)-1; 111933842cedSCho, Yu-Chen 11206da2ec56SKees Cook info->MS_Lib.blkpag = kmalloc_array(info->MS_Lib.PagesPerBlock, 11216da2ec56SKees Cook info->MS_Lib.BytesPerSector, 11226da2ec56SKees Cook GFP_KERNEL); 11236da2ec56SKees Cook info->MS_Lib.blkext = kmalloc_array(info->MS_Lib.PagesPerBlock, 11246da2ec56SKees Cook sizeof(struct ms_lib_type_extdat), 11256da2ec56SKees Cook GFP_KERNEL); 112633842cedSCho, Yu-Chen 112733842cedSCho, Yu-Chen if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) { 112833842cedSCho, Yu-Chen ms_lib_free_writebuf(us); 112933842cedSCho, Yu-Chen return (u32)-1; 113033842cedSCho, Yu-Chen } 113133842cedSCho, Yu-Chen 113233842cedSCho, Yu-Chen ms_lib_clear_writebuf(us); 113333842cedSCho, Yu-Chen 113433842cedSCho, Yu-Chen return 0; 113533842cedSCho, Yu-Chen } 113633842cedSCho, Yu-Chen 113733842cedSCho, Yu-Chen static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk) 113833842cedSCho, Yu-Chen { 113933842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 114033842cedSCho, Yu-Chen 114133842cedSCho, Yu-Chen if (logblk == MS_LB_NOT_USED) 114233842cedSCho, Yu-Chen return 0; 114333842cedSCho, Yu-Chen 114433842cedSCho, Yu-Chen if ((logblk >= info->MS_Lib.NumberOfLogBlock) || 114533842cedSCho, Yu-Chen (phyblk >= info->MS_Lib.NumberOfPhyBlock)) 114633842cedSCho, Yu-Chen return (u32)-1; 114733842cedSCho, Yu-Chen 114833842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = logblk; 114933842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[logblk] = phyblk; 115033842cedSCho, Yu-Chen 115133842cedSCho, Yu-Chen return 0; 115233842cedSCho, Yu-Chen } 115333842cedSCho, Yu-Chen 115433842cedSCho, Yu-Chen static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy, 115533842cedSCho, Yu-Chen u16 PhyBlockAddr, u8 PageNum, unsigned char *buf, u16 len) 115633842cedSCho, Yu-Chen { 115733842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 115833842cedSCho, Yu-Chen int result; 115933842cedSCho, Yu-Chen 116033842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN); 116133842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 116233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 116333842cedSCho, Yu-Chen 116433842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 116533842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 116633842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200*len; 116733842cedSCho, Yu-Chen bcb->Flags = 0x00; 116833842cedSCho, Yu-Chen bcb->CDB[0] = 0xF0; 116933842cedSCho, Yu-Chen bcb->CDB[1] = 0x08; 117033842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(oldphy); 117133842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(oldphy>>8); 117233842cedSCho, Yu-Chen bcb->CDB[2] = 0; /* (BYTE)(oldphy>>16) */ 117333842cedSCho, Yu-Chen bcb->CDB[7] = (unsigned char)(newphy); 117433842cedSCho, Yu-Chen bcb->CDB[6] = (unsigned char)(newphy>>8); 117533842cedSCho, Yu-Chen bcb->CDB[5] = 0; /* (BYTE)(newphy>>16) */ 117633842cedSCho, Yu-Chen bcb->CDB[9] = (unsigned char)(PhyBlockAddr); 117733842cedSCho, Yu-Chen bcb->CDB[8] = (unsigned char)(PhyBlockAddr>>8); 117833842cedSCho, Yu-Chen bcb->CDB[10] = PageNum; 117933842cedSCho, Yu-Chen 118033842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); 118133842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 118233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 118333842cedSCho, Yu-Chen 118433842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 118533842cedSCho, Yu-Chen } 118633842cedSCho, Yu-Chen 118733842cedSCho, Yu-Chen static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr) 118833842cedSCho, Yu-Chen { 118933842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 119033842cedSCho, Yu-Chen int result; 119133842cedSCho, Yu-Chen u32 bn = PhyBlockAddr; 119233842cedSCho, Yu-Chen 119333842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN); 119433842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 119533842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 119633842cedSCho, Yu-Chen 119733842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 119833842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 119933842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200; 1200b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 120133842cedSCho, Yu-Chen bcb->CDB[0] = 0xF2; 120233842cedSCho, Yu-Chen bcb->CDB[1] = 0x06; 120333842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn); 120433842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>8); 120533842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>16); 120633842cedSCho, Yu-Chen 120733842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); 120833842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 120933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 121033842cedSCho, Yu-Chen 121133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 121233842cedSCho, Yu-Chen } 121333842cedSCho, Yu-Chen 121433842cedSCho, Yu-Chen static int ms_lib_check_disableblock(struct us_data *us, u16 PhyBlock) 121533842cedSCho, Yu-Chen { 121633842cedSCho, Yu-Chen unsigned char *PageBuf = NULL; 121733842cedSCho, Yu-Chen u16 result = MS_STATUS_SUCCESS; 121833842cedSCho, Yu-Chen u16 blk, index = 0; 121933842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat; 122033842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 122133842cedSCho, Yu-Chen 122233842cedSCho, Yu-Chen PageBuf = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); 122333842cedSCho, Yu-Chen if (PageBuf == NULL) { 122433842cedSCho, Yu-Chen result = MS_NO_MEMORY_ERROR; 122533842cedSCho, Yu-Chen goto exit; 122633842cedSCho, Yu-Chen } 122733842cedSCho, Yu-Chen 122833842cedSCho, Yu-Chen ms_read_readpage(us, PhyBlock, 1, (u32 *)PageBuf, &extdat); 122933842cedSCho, Yu-Chen do { 123033842cedSCho, Yu-Chen blk = be16_to_cpu(PageBuf[index]); 123133842cedSCho, Yu-Chen if (blk == MS_LB_NOT_USED) 123233842cedSCho, Yu-Chen break; 123333842cedSCho, Yu-Chen if (blk == info->MS_Lib.Log2PhyMap[0]) { 123433842cedSCho, Yu-Chen result = MS_ERROR_FLASH_READ; 123533842cedSCho, Yu-Chen break; 123633842cedSCho, Yu-Chen } 123733842cedSCho, Yu-Chen index++; 123833842cedSCho, Yu-Chen } while (1); 123933842cedSCho, Yu-Chen 124033842cedSCho, Yu-Chen exit: 124133842cedSCho, Yu-Chen kfree(PageBuf); 124233842cedSCho, Yu-Chen return result; 124333842cedSCho, Yu-Chen } 124433842cedSCho, Yu-Chen 124533842cedSCho, Yu-Chen static int ms_lib_setacquired_errorblock(struct us_data *us, u16 phyblk) 124633842cedSCho, Yu-Chen { 124733842cedSCho, Yu-Chen u16 log; 124833842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 124933842cedSCho, Yu-Chen 125033842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock) 125133842cedSCho, Yu-Chen return (u32)-1; 125233842cedSCho, Yu-Chen 125333842cedSCho, Yu-Chen log = info->MS_Lib.Phy2LogMap[phyblk]; 125433842cedSCho, Yu-Chen 125533842cedSCho, Yu-Chen if (log < info->MS_Lib.NumberOfLogBlock) 125633842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED; 125733842cedSCho, Yu-Chen 125833842cedSCho, Yu-Chen if (info->MS_Lib.Phy2LogMap[phyblk] != MS_LB_INITIAL_ERROR) 125933842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_ACQUIRED_ERROR; 126033842cedSCho, Yu-Chen 126133842cedSCho, Yu-Chen return 0; 126233842cedSCho, Yu-Chen } 126333842cedSCho, Yu-Chen 126433842cedSCho, Yu-Chen static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr, 126533842cedSCho, Yu-Chen u8 PageNum, u8 OverwriteFlag) 126633842cedSCho, Yu-Chen { 126733842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 126833842cedSCho, Yu-Chen int result; 126933842cedSCho, Yu-Chen 127033842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN); 127133842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 127233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 127333842cedSCho, Yu-Chen 127433842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 127533842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 127633842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4; 1277b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 127833842cedSCho, Yu-Chen bcb->CDB[0] = 0xF2; 127933842cedSCho, Yu-Chen bcb->CDB[1] = 0x05; 128033842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum); 128133842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlockAddr); 128233842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8); 128333842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16); 128433842cedSCho, Yu-Chen bcb->CDB[6] = OverwriteFlag; 128533842cedSCho, Yu-Chen bcb->CDB[7] = 0xFF; 128633842cedSCho, Yu-Chen bcb->CDB[8] = 0xFF; 128733842cedSCho, Yu-Chen bcb->CDB[9] = 0xFF; 128833842cedSCho, Yu-Chen 128933842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); 129033842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 129133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 129233842cedSCho, Yu-Chen 129333842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 129433842cedSCho, Yu-Chen } 129533842cedSCho, Yu-Chen 129633842cedSCho, Yu-Chen static int ms_lib_error_phyblock(struct us_data *us, u16 phyblk) 129733842cedSCho, Yu-Chen { 129833842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 129933842cedSCho, Yu-Chen 130033842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock) 130133842cedSCho, Yu-Chen return MS_STATUS_ERROR; 130233842cedSCho, Yu-Chen 130333842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, phyblk); 130433842cedSCho, Yu-Chen 130533842cedSCho, Yu-Chen if (ms_lib_iswritable(info)) 130633842cedSCho, Yu-Chen return ms_lib_overwrite_extra(us, phyblk, 0, (u8)(~MS_REG_OVR_BKST & BYTE_MASK)); 130733842cedSCho, Yu-Chen 130833842cedSCho, Yu-Chen return MS_STATUS_SUCCESS; 130933842cedSCho, Yu-Chen } 131033842cedSCho, Yu-Chen 131133842cedSCho, Yu-Chen static int ms_lib_erase_phyblock(struct us_data *us, u16 phyblk) 131233842cedSCho, Yu-Chen { 131333842cedSCho, Yu-Chen u16 log; 131433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 131533842cedSCho, Yu-Chen 131633842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock) 131733842cedSCho, Yu-Chen return MS_STATUS_ERROR; 131833842cedSCho, Yu-Chen 131933842cedSCho, Yu-Chen log = info->MS_Lib.Phy2LogMap[phyblk]; 132033842cedSCho, Yu-Chen 132133842cedSCho, Yu-Chen if (log < info->MS_Lib.NumberOfLogBlock) 132233842cedSCho, Yu-Chen info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED; 132333842cedSCho, Yu-Chen 132433842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED; 132533842cedSCho, Yu-Chen 132633842cedSCho, Yu-Chen if (ms_lib_iswritable(info)) { 132733842cedSCho, Yu-Chen switch (ms_read_eraseblock(us, phyblk)) { 132833842cedSCho, Yu-Chen case MS_STATUS_SUCCESS: 132933842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED_ERASED; 133033842cedSCho, Yu-Chen return MS_STATUS_SUCCESS; 133133842cedSCho, Yu-Chen case MS_ERROR_FLASH_ERASE: 133233842cedSCho, Yu-Chen case MS_STATUS_INT_ERROR: 133333842cedSCho, Yu-Chen ms_lib_error_phyblock(us, phyblk); 133433842cedSCho, Yu-Chen return MS_ERROR_FLASH_ERASE; 133533842cedSCho, Yu-Chen case MS_STATUS_ERROR: 133633842cedSCho, Yu-Chen default: 133733842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY); /* MS_LibCtrlSet will used by ENE_MSInit ,need check, and why us to info*/ 133833842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, phyblk); 133933842cedSCho, Yu-Chen return MS_STATUS_ERROR; 134033842cedSCho, Yu-Chen } 134133842cedSCho, Yu-Chen } 134233842cedSCho, Yu-Chen 134333842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, phyblk); 134433842cedSCho, Yu-Chen 134533842cedSCho, Yu-Chen return MS_STATUS_SUCCESS; 134633842cedSCho, Yu-Chen } 134733842cedSCho, Yu-Chen 134833842cedSCho, Yu-Chen static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, 134933842cedSCho, Yu-Chen u8 PageNum, struct ms_lib_type_extdat *ExtraDat) 135033842cedSCho, Yu-Chen { 135133842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 1352628c2893SAlan Stern struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 1353628c2893SAlan Stern u8 *bbuf = info->bbuf; 135433842cedSCho, Yu-Chen int result; 135533842cedSCho, Yu-Chen 135633842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 135733842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 135833842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4; 1359b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 136033842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 136133842cedSCho, Yu-Chen bcb->CDB[1] = 0x03; 136233842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum); 136333842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlock); 136433842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlock>>8); 136533842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlock>>16); 136633842cedSCho, Yu-Chen bcb->CDB[6] = 0x01; 136733842cedSCho, Yu-Chen 1368628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0); 136933842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 137033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 137133842cedSCho, Yu-Chen 137233842cedSCho, Yu-Chen ExtraDat->reserved = 0; 137333842cedSCho, Yu-Chen ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */ 137433842cedSCho, Yu-Chen ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */ 137533842cedSCho, Yu-Chen ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */ 1376628c2893SAlan Stern ExtraDat->ovrflg = bbuf[0]; 1377628c2893SAlan Stern ExtraDat->mngflg = bbuf[1]; 1378628c2893SAlan Stern ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]); 137933842cedSCho, Yu-Chen 138033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 138133842cedSCho, Yu-Chen } 138233842cedSCho, Yu-Chen 138333842cedSCho, Yu-Chen static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk) 138433842cedSCho, Yu-Chen { 138533842cedSCho, Yu-Chen u16 blk; 138633842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat; /* need check */ 138733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 138833842cedSCho, Yu-Chen 138933842cedSCho, Yu-Chen 139033842cedSCho, Yu-Chen if (phyblk >= info->MS_Lib.NumberOfPhyBlock) 139133842cedSCho, Yu-Chen return MS_LB_ERROR; 139233842cedSCho, Yu-Chen 139333842cedSCho, Yu-Chen for (blk = phyblk + 1; blk != phyblk; blk++) { 139433842cedSCho, Yu-Chen if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0) 139533842cedSCho, Yu-Chen blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT; 139633842cedSCho, Yu-Chen 139733842cedSCho, Yu-Chen if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) { 139833842cedSCho, Yu-Chen return blk; 139933842cedSCho, Yu-Chen } else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) { 140033842cedSCho, Yu-Chen switch (ms_lib_read_extra(us, blk, 0, &extdat)) { 140133842cedSCho, Yu-Chen case MS_STATUS_SUCCESS: 140233842cedSCho, Yu-Chen case MS_STATUS_SUCCESS_WITH_ECC: 140333842cedSCho, Yu-Chen break; 140433842cedSCho, Yu-Chen case MS_NOCARD_ERROR: 140533842cedSCho, Yu-Chen return MS_NOCARD_ERROR; 140633842cedSCho, Yu-Chen case MS_STATUS_INT_ERROR: 140733842cedSCho, Yu-Chen return MS_LB_ERROR; 140833842cedSCho, Yu-Chen case MS_ERROR_FLASH_READ: 140933842cedSCho, Yu-Chen default: 141033842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, blk); 141133842cedSCho, Yu-Chen continue; 141233842cedSCho, Yu-Chen } /* End switch */ 141333842cedSCho, Yu-Chen 141433842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) { 141533842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, blk); 141633842cedSCho, Yu-Chen continue; 141733842cedSCho, Yu-Chen } 141833842cedSCho, Yu-Chen 141933842cedSCho, Yu-Chen switch (ms_lib_erase_phyblock(us, blk)) { 142033842cedSCho, Yu-Chen case MS_STATUS_SUCCESS: 142133842cedSCho, Yu-Chen return blk; 142233842cedSCho, Yu-Chen case MS_STATUS_ERROR: 142333842cedSCho, Yu-Chen return MS_LB_ERROR; 142433842cedSCho, Yu-Chen case MS_ERROR_FLASH_ERASE: 142533842cedSCho, Yu-Chen default: 142633842cedSCho, Yu-Chen ms_lib_error_phyblock(us, blk); 142733842cedSCho, Yu-Chen break; 142833842cedSCho, Yu-Chen } 142933842cedSCho, Yu-Chen } 143033842cedSCho, Yu-Chen } /* End for */ 143133842cedSCho, Yu-Chen 143233842cedSCho, Yu-Chen return MS_LB_ERROR; 143333842cedSCho, Yu-Chen } 143433842cedSCho, Yu-Chen static int ms_libsearch_block_from_logical(struct us_data *us, u16 logblk) 143533842cedSCho, Yu-Chen { 143633842cedSCho, Yu-Chen u16 phyblk; 143733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 143833842cedSCho, Yu-Chen 143933842cedSCho, Yu-Chen phyblk = ms_libconv_to_physical(info, logblk); 144033842cedSCho, Yu-Chen if (phyblk >= MS_LB_ERROR) { 144133842cedSCho, Yu-Chen if (logblk >= info->MS_Lib.NumberOfLogBlock) 144233842cedSCho, Yu-Chen return MS_LB_ERROR; 144333842cedSCho, Yu-Chen 144433842cedSCho, Yu-Chen phyblk = (logblk + MS_NUMBER_OF_BOOT_BLOCK) / MS_LOGICAL_BLOCKS_PER_SEGMENT; 144533842cedSCho, Yu-Chen phyblk *= MS_PHYSICAL_BLOCKS_PER_SEGMENT; 144633842cedSCho, Yu-Chen phyblk += MS_PHYSICAL_BLOCKS_PER_SEGMENT - 1; 144733842cedSCho, Yu-Chen } 144833842cedSCho, Yu-Chen 144933842cedSCho, Yu-Chen return ms_libsearch_block_from_physical(us, phyblk); 145033842cedSCho, Yu-Chen } 145133842cedSCho, Yu-Chen 145233842cedSCho, Yu-Chen static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb) 145333842cedSCho, Yu-Chen { 145433842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); 145533842cedSCho, Yu-Chen 145633842cedSCho, Yu-Chen /* pr_info("MS_SCSI_Test_Unit_Ready\n"); */ 145733842cedSCho, Yu-Chen if (info->MS_Status.Insert && info->MS_Status.Ready) { 145833842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 145933842cedSCho, Yu-Chen } else { 146033842cedSCho, Yu-Chen ene_ms_init(us); 146133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 146233842cedSCho, Yu-Chen } 146333842cedSCho, Yu-Chen 146433842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 146533842cedSCho, Yu-Chen } 146633842cedSCho, Yu-Chen 146733842cedSCho, Yu-Chen static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb) 146833842cedSCho, Yu-Chen { 146933842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 147033842cedSCho, Yu-Chen unsigned char mediaNoWP[12] = { 147133842cedSCho, Yu-Chen 0x0b, 0x00, 0x00, 0x08, 0x00, 0x00, 147233842cedSCho, Yu-Chen 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; 147333842cedSCho, Yu-Chen unsigned char mediaWP[12] = { 147433842cedSCho, Yu-Chen 0x0b, 0x00, 0x80, 0x08, 0x00, 0x00, 147533842cedSCho, Yu-Chen 0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 }; 147633842cedSCho, Yu-Chen 147733842cedSCho, Yu-Chen if (info->MS_Status.WtP) 147833842cedSCho, Yu-Chen usb_stor_set_xfer_buf(mediaWP, 12, srb); 147933842cedSCho, Yu-Chen else 148033842cedSCho, Yu-Chen usb_stor_set_xfer_buf(mediaNoWP, 12, srb); 148133842cedSCho, Yu-Chen 148233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 148333842cedSCho, Yu-Chen } 148433842cedSCho, Yu-Chen 148533842cedSCho, Yu-Chen static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb) 148633842cedSCho, Yu-Chen { 148733842cedSCho, Yu-Chen u32 bl_num; 148833842cedSCho, Yu-Chen u16 bl_len; 148933842cedSCho, Yu-Chen unsigned int offset = 0; 149033842cedSCho, Yu-Chen unsigned char buf[8]; 149133842cedSCho, Yu-Chen struct scatterlist *sg = NULL; 149233842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 149333842cedSCho, Yu-Chen 1494191648d0SJoe Perches usb_stor_dbg(us, "ms_scsi_read_capacity\n"); 149533842cedSCho, Yu-Chen bl_len = 0x200; 149633842cedSCho, Yu-Chen if (info->MS_Status.IsMSPro) 149733842cedSCho, Yu-Chen bl_num = info->MSP_TotalBlock - 1; 149833842cedSCho, Yu-Chen else 149933842cedSCho, Yu-Chen bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1; 150033842cedSCho, Yu-Chen 150133842cedSCho, Yu-Chen info->bl_num = bl_num; 1502191648d0SJoe Perches usb_stor_dbg(us, "bl_len = %x\n", bl_len); 1503191648d0SJoe Perches usb_stor_dbg(us, "bl_num = %x\n", bl_num); 150433842cedSCho, Yu-Chen 150533842cedSCho, Yu-Chen /*srb->request_bufflen = 8; */ 150633842cedSCho, Yu-Chen buf[0] = (bl_num >> 24) & 0xff; 150733842cedSCho, Yu-Chen buf[1] = (bl_num >> 16) & 0xff; 150833842cedSCho, Yu-Chen buf[2] = (bl_num >> 8) & 0xff; 150933842cedSCho, Yu-Chen buf[3] = (bl_num >> 0) & 0xff; 151033842cedSCho, Yu-Chen buf[4] = (bl_len >> 24) & 0xff; 151133842cedSCho, Yu-Chen buf[5] = (bl_len >> 16) & 0xff; 151233842cedSCho, Yu-Chen buf[6] = (bl_len >> 8) & 0xff; 151333842cedSCho, Yu-Chen buf[7] = (bl_len >> 0) & 0xff; 151433842cedSCho, Yu-Chen 151533842cedSCho, Yu-Chen usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF); 151633842cedSCho, Yu-Chen 151733842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 151833842cedSCho, Yu-Chen } 151933842cedSCho, Yu-Chen 152033842cedSCho, Yu-Chen static void ms_lib_phy_to_log_range(u16 PhyBlock, u16 *LogStart, u16 *LogEnde) 152133842cedSCho, Yu-Chen { 152233842cedSCho, Yu-Chen PhyBlock /= MS_PHYSICAL_BLOCKS_PER_SEGMENT; 152333842cedSCho, Yu-Chen 152433842cedSCho, Yu-Chen if (PhyBlock) { 152533842cedSCho, Yu-Chen *LogStart = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT + (PhyBlock - 1) * MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/ 152633842cedSCho, Yu-Chen *LogEnde = *LogStart + MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/ 152733842cedSCho, Yu-Chen } else { 152833842cedSCho, Yu-Chen *LogStart = 0; 152933842cedSCho, Yu-Chen *LogEnde = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT;/*494*/ 153033842cedSCho, Yu-Chen } 153133842cedSCho, Yu-Chen } 153233842cedSCho, Yu-Chen 153333842cedSCho, Yu-Chen static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock, 153433842cedSCho, Yu-Chen u8 PageNum, u8 blen, void *buf) 153533842cedSCho, Yu-Chen { 153633842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 153733842cedSCho, Yu-Chen int result; 153833842cedSCho, Yu-Chen 153933842cedSCho, Yu-Chen /* Read Extra Data */ 154033842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 154133842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 154233842cedSCho, Yu-Chen bcb->DataTransferLength = 0x4 * blen; 1543b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 154433842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 154533842cedSCho, Yu-Chen bcb->CDB[1] = 0x03; 154633842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(PageNum); 154733842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(PhyBlock); 154833842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(PhyBlock>>8); 154933842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(PhyBlock>>16); 155033842cedSCho, Yu-Chen bcb->CDB[6] = blen; 155133842cedSCho, Yu-Chen 155233842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0); 155333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 155433842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 155533842cedSCho, Yu-Chen 155633842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 155733842cedSCho, Yu-Chen } 155833842cedSCho, Yu-Chen 155933842cedSCho, Yu-Chen static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st) 156033842cedSCho, Yu-Chen { 156133842cedSCho, Yu-Chen u16 PhyBlock, newblk, i; 156233842cedSCho, Yu-Chen u16 LogStart, LogEnde; 156333842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat; 156433842cedSCho, Yu-Chen u32 count = 0, index = 0; 156533842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 1566628c2893SAlan Stern u8 *bbuf = info->bbuf; 156733842cedSCho, Yu-Chen 156833842cedSCho, Yu-Chen for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) { 156933842cedSCho, Yu-Chen ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde); 157033842cedSCho, Yu-Chen 157133842cedSCho, Yu-Chen for (i = 0; i < MS_PHYSICAL_BLOCKS_PER_SEGMENT; i++, PhyBlock++) { 157233842cedSCho, Yu-Chen switch (ms_libconv_to_logical(info, PhyBlock)) { 157333842cedSCho, Yu-Chen case MS_STATUS_ERROR: 157433842cedSCho, Yu-Chen continue; 157533842cedSCho, Yu-Chen default: 157633842cedSCho, Yu-Chen break; 157733842cedSCho, Yu-Chen } 157833842cedSCho, Yu-Chen 157933842cedSCho, Yu-Chen if (count == PhyBlock) { 1580628c2893SAlan Stern ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, 1581628c2893SAlan Stern bbuf); 158233842cedSCho, Yu-Chen count += 0x80; 158333842cedSCho, Yu-Chen } 158433842cedSCho, Yu-Chen index = (PhyBlock % 0x80) * 4; 158533842cedSCho, Yu-Chen 1586628c2893SAlan Stern extdat.ovrflg = bbuf[index]; 1587628c2893SAlan Stern extdat.mngflg = bbuf[index+1]; 1588628c2893SAlan Stern extdat.logadr = memstick_logaddr(bbuf[index+2], 1589628c2893SAlan Stern bbuf[index+3]); 159033842cedSCho, Yu-Chen 159133842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) { 159233842cedSCho, Yu-Chen ms_lib_setacquired_errorblock(us, PhyBlock); 159333842cedSCho, Yu-Chen continue; 159433842cedSCho, Yu-Chen } 159533842cedSCho, Yu-Chen 159633842cedSCho, Yu-Chen if ((extdat.mngflg & MS_REG_MNG_ATFLG) == MS_REG_MNG_ATFLG_ATTBL) { 159733842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, PhyBlock); 159833842cedSCho, Yu-Chen continue; 159933842cedSCho, Yu-Chen } 160033842cedSCho, Yu-Chen 160133842cedSCho, Yu-Chen if (extdat.logadr != MS_LB_NOT_USED) { 160233842cedSCho, Yu-Chen if ((extdat.logadr < LogStart) || (LogEnde <= extdat.logadr)) { 160333842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, PhyBlock); 160433842cedSCho, Yu-Chen continue; 160533842cedSCho, Yu-Chen } 160633842cedSCho, Yu-Chen 160733842cedSCho, Yu-Chen newblk = ms_libconv_to_physical(info, extdat.logadr); 160833842cedSCho, Yu-Chen 160933842cedSCho, Yu-Chen if (newblk != MS_LB_NOT_USED) { 161033842cedSCho, Yu-Chen if (extdat.logadr == 0) { 161133842cedSCho, Yu-Chen ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock); 161233842cedSCho, Yu-Chen if (ms_lib_check_disableblock(us, btBlk1st)) { 161333842cedSCho, Yu-Chen ms_lib_set_logicalpair(us, extdat.logadr, newblk); 161433842cedSCho, Yu-Chen continue; 161533842cedSCho, Yu-Chen } 161633842cedSCho, Yu-Chen } 161733842cedSCho, Yu-Chen 161833842cedSCho, Yu-Chen ms_lib_read_extra(us, newblk, 0, &extdat); 161933842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_UDST) == MS_REG_OVR_UDST_UPDATING) { 162033842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, PhyBlock); 162133842cedSCho, Yu-Chen continue; 162233842cedSCho, Yu-Chen } else { 162333842cedSCho, Yu-Chen ms_lib_erase_phyblock(us, newblk); 162433842cedSCho, Yu-Chen } 162533842cedSCho, Yu-Chen } 162633842cedSCho, Yu-Chen 162733842cedSCho, Yu-Chen ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock); 162833842cedSCho, Yu-Chen } 162933842cedSCho, Yu-Chen } 163033842cedSCho, Yu-Chen } /* End for ... */ 163133842cedSCho, Yu-Chen 163233842cedSCho, Yu-Chen return MS_STATUS_SUCCESS; 163333842cedSCho, Yu-Chen } 163433842cedSCho, Yu-Chen 163533842cedSCho, Yu-Chen 163633842cedSCho, Yu-Chen static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb) 163733842cedSCho, Yu-Chen { 163833842cedSCho, Yu-Chen int result; 163933842cedSCho, Yu-Chen unsigned char *cdb = srb->cmnd; 164033842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 164133842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 164233842cedSCho, Yu-Chen 164333842cedSCho, Yu-Chen u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) | 164433842cedSCho, Yu-Chen ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff); 164533842cedSCho, Yu-Chen u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); 164633842cedSCho, Yu-Chen u32 blenByte = blen * 0x200; 164733842cedSCho, Yu-Chen 164833842cedSCho, Yu-Chen if (bn > info->bl_num) 164933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 165033842cedSCho, Yu-Chen 165133842cedSCho, Yu-Chen if (info->MS_Status.IsMSPro) { 165233842cedSCho, Yu-Chen result = ene_load_bincode(us, MSP_RW_PATTERN); 165333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 1654191648d0SJoe Perches usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n"); 165533842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 165633842cedSCho, Yu-Chen } 165733842cedSCho, Yu-Chen 165833842cedSCho, Yu-Chen /* set up the command wrapper */ 165933842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 166033842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 166133842cedSCho, Yu-Chen bcb->DataTransferLength = blenByte; 1662b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 166333842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 166433842cedSCho, Yu-Chen bcb->CDB[1] = 0x02; 166533842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(bn); 166633842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn>>8); 166733842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>16); 166833842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>24); 166933842cedSCho, Yu-Chen 167033842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1); 167133842cedSCho, Yu-Chen } else { 167233842cedSCho, Yu-Chen void *buf; 167333842cedSCho, Yu-Chen int offset = 0; 167433842cedSCho, Yu-Chen u16 phyblk, logblk; 167533842cedSCho, Yu-Chen u8 PageNum; 167633842cedSCho, Yu-Chen u16 len; 167733842cedSCho, Yu-Chen u32 blkno; 167833842cedSCho, Yu-Chen 167933842cedSCho, Yu-Chen buf = kmalloc(blenByte, GFP_KERNEL); 168033842cedSCho, Yu-Chen if (buf == NULL) 168133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 168233842cedSCho, Yu-Chen 168333842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN); 168433842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 168533842cedSCho, Yu-Chen pr_info("Load MS RW pattern Fail !!\n"); 168633842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR; 168733842cedSCho, Yu-Chen goto exit; 168833842cedSCho, Yu-Chen } 168933842cedSCho, Yu-Chen 169033842cedSCho, Yu-Chen logblk = (u16)(bn / info->MS_Lib.PagesPerBlock); 169133842cedSCho, Yu-Chen PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock); 169233842cedSCho, Yu-Chen 169333842cedSCho, Yu-Chen while (1) { 169433842cedSCho, Yu-Chen if (blen > (info->MS_Lib.PagesPerBlock-PageNum)) 169533842cedSCho, Yu-Chen len = info->MS_Lib.PagesPerBlock-PageNum; 169633842cedSCho, Yu-Chen else 169733842cedSCho, Yu-Chen len = blen; 169833842cedSCho, Yu-Chen 169933842cedSCho, Yu-Chen phyblk = ms_libconv_to_physical(info, logblk); 170033842cedSCho, Yu-Chen blkno = phyblk * 0x20 + PageNum; 170133842cedSCho, Yu-Chen 170233842cedSCho, Yu-Chen /* set up the command wrapper */ 170333842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 170433842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 170533842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200 * len; 1706b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 170733842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 170833842cedSCho, Yu-Chen bcb->CDB[1] = 0x02; 170933842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(blkno); 171033842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(blkno>>8); 171133842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(blkno>>16); 171233842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(blkno>>24); 171333842cedSCho, Yu-Chen 171433842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_READ, buf+offset, 0); 171533842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 171633842cedSCho, Yu-Chen pr_info("MS_SCSI_Read --- result = %x\n", result); 171733842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR; 171833842cedSCho, Yu-Chen goto exit; 171933842cedSCho, Yu-Chen } 172033842cedSCho, Yu-Chen 172133842cedSCho, Yu-Chen blen -= len; 172233842cedSCho, Yu-Chen if (blen <= 0) 172333842cedSCho, Yu-Chen break; 172433842cedSCho, Yu-Chen logblk++; 172533842cedSCho, Yu-Chen PageNum = 0; 172633842cedSCho, Yu-Chen offset += MS_BYTES_PER_PAGE*len; 172733842cedSCho, Yu-Chen } 172833842cedSCho, Yu-Chen usb_stor_set_xfer_buf(buf, blenByte, srb); 172933842cedSCho, Yu-Chen exit: 173033842cedSCho, Yu-Chen kfree(buf); 173133842cedSCho, Yu-Chen } 173233842cedSCho, Yu-Chen return result; 173333842cedSCho, Yu-Chen } 173433842cedSCho, Yu-Chen 173533842cedSCho, Yu-Chen static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb) 173633842cedSCho, Yu-Chen { 173733842cedSCho, Yu-Chen int result; 173833842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 173933842cedSCho, Yu-Chen unsigned char *cdb = srb->cmnd; 174033842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 174133842cedSCho, Yu-Chen 174233842cedSCho, Yu-Chen u32 bn = ((cdb[2] << 24) & 0xff000000) | 174333842cedSCho, Yu-Chen ((cdb[3] << 16) & 0x00ff0000) | 174433842cedSCho, Yu-Chen ((cdb[4] << 8) & 0x0000ff00) | 174533842cedSCho, Yu-Chen ((cdb[5] << 0) & 0x000000ff); 174633842cedSCho, Yu-Chen u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff); 174733842cedSCho, Yu-Chen u32 blenByte = blen * 0x200; 174833842cedSCho, Yu-Chen 174933842cedSCho, Yu-Chen if (bn > info->bl_num) 175033842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 175133842cedSCho, Yu-Chen 175233842cedSCho, Yu-Chen if (info->MS_Status.IsMSPro) { 175333842cedSCho, Yu-Chen result = ene_load_bincode(us, MSP_RW_PATTERN); 175433842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 175533842cedSCho, Yu-Chen pr_info("Load MSP RW pattern Fail !!\n"); 175633842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 175733842cedSCho, Yu-Chen } 175833842cedSCho, Yu-Chen 175933842cedSCho, Yu-Chen /* set up the command wrapper */ 176033842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 176133842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 176233842cedSCho, Yu-Chen bcb->DataTransferLength = blenByte; 176333842cedSCho, Yu-Chen bcb->Flags = 0x00; 176433842cedSCho, Yu-Chen bcb->CDB[0] = 0xF0; 176533842cedSCho, Yu-Chen bcb->CDB[1] = 0x04; 176633842cedSCho, Yu-Chen bcb->CDB[5] = (unsigned char)(bn); 176733842cedSCho, Yu-Chen bcb->CDB[4] = (unsigned char)(bn>>8); 176833842cedSCho, Yu-Chen bcb->CDB[3] = (unsigned char)(bn>>16); 176933842cedSCho, Yu-Chen bcb->CDB[2] = (unsigned char)(bn>>24); 177033842cedSCho, Yu-Chen 177133842cedSCho, Yu-Chen result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1); 177233842cedSCho, Yu-Chen } else { 177333842cedSCho, Yu-Chen void *buf; 1774bc985c10SFelipe Balbi int offset = 0; 177533842cedSCho, Yu-Chen u16 PhyBlockAddr; 177633842cedSCho, Yu-Chen u8 PageNum; 177733842cedSCho, Yu-Chen u16 len, oldphy, newphy; 177833842cedSCho, Yu-Chen 177933842cedSCho, Yu-Chen buf = kmalloc(blenByte, GFP_KERNEL); 178033842cedSCho, Yu-Chen if (buf == NULL) 178133842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 178233842cedSCho, Yu-Chen usb_stor_set_xfer_buf(buf, blenByte, srb); 178333842cedSCho, Yu-Chen 178433842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_RW_PATTERN); 178533842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 178633842cedSCho, Yu-Chen pr_info("Load MS RW pattern Fail !!\n"); 178733842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR; 178833842cedSCho, Yu-Chen goto exit; 178933842cedSCho, Yu-Chen } 179033842cedSCho, Yu-Chen 179133842cedSCho, Yu-Chen PhyBlockAddr = (u16)(bn / info->MS_Lib.PagesPerBlock); 179233842cedSCho, Yu-Chen PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock); 179333842cedSCho, Yu-Chen 179433842cedSCho, Yu-Chen while (1) { 179533842cedSCho, Yu-Chen if (blen > (info->MS_Lib.PagesPerBlock-PageNum)) 179633842cedSCho, Yu-Chen len = info->MS_Lib.PagesPerBlock-PageNum; 179733842cedSCho, Yu-Chen else 179833842cedSCho, Yu-Chen len = blen; 179933842cedSCho, Yu-Chen 180033842cedSCho, Yu-Chen oldphy = ms_libconv_to_physical(info, PhyBlockAddr); /* need check us <-> info */ 180133842cedSCho, Yu-Chen newphy = ms_libsearch_block_from_logical(us, PhyBlockAddr); 180233842cedSCho, Yu-Chen 180333842cedSCho, Yu-Chen result = ms_read_copyblock(us, oldphy, newphy, PhyBlockAddr, PageNum, buf+offset, len); 180433842cedSCho, Yu-Chen 180533842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 180633842cedSCho, Yu-Chen pr_info("MS_SCSI_Write --- result = %x\n", result); 180733842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_ERROR; 180833842cedSCho, Yu-Chen goto exit; 180933842cedSCho, Yu-Chen } 181033842cedSCho, Yu-Chen 181133842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[oldphy] = MS_LB_NOT_USED_ERASED; 181233842cedSCho, Yu-Chen ms_lib_force_setlogical_pair(us, PhyBlockAddr, newphy); 181333842cedSCho, Yu-Chen 181433842cedSCho, Yu-Chen blen -= len; 181533842cedSCho, Yu-Chen if (blen <= 0) 181633842cedSCho, Yu-Chen break; 181733842cedSCho, Yu-Chen PhyBlockAddr++; 181833842cedSCho, Yu-Chen PageNum = 0; 181933842cedSCho, Yu-Chen offset += MS_BYTES_PER_PAGE*len; 182033842cedSCho, Yu-Chen } 182133842cedSCho, Yu-Chen exit: 182233842cedSCho, Yu-Chen kfree(buf); 182333842cedSCho, Yu-Chen } 182433842cedSCho, Yu-Chen return result; 182533842cedSCho, Yu-Chen } 182633842cedSCho, Yu-Chen 182733842cedSCho, Yu-Chen /* 182833842cedSCho, Yu-Chen * ENE MS Card 182933842cedSCho, Yu-Chen */ 183033842cedSCho, Yu-Chen 183141e568d1Shuajun li static int ene_get_card_type(struct us_data *us, u16 index, void *buf) 183241e568d1Shuajun li { 183341e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 183441e568d1Shuajun li int result; 183541e568d1Shuajun li 183641e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 183741e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 183841e568d1Shuajun li bcb->DataTransferLength = 0x01; 1839b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 184041e568d1Shuajun li bcb->CDB[0] = 0xED; 184141e568d1Shuajun li bcb->CDB[2] = (unsigned char)(index>>8); 184241e568d1Shuajun li bcb->CDB[3] = (unsigned char)index; 184341e568d1Shuajun li 184441e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0); 184541e568d1Shuajun li return result; 184641e568d1Shuajun li } 184741e568d1Shuajun li 184841e568d1Shuajun li static int ene_get_card_status(struct us_data *us, u8 *buf) 184941e568d1Shuajun li { 185041e568d1Shuajun li u16 tmpreg; 185141e568d1Shuajun li u32 reg4b; 185241e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 185341e568d1Shuajun li 1854191648d0SJoe Perches /*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/ 185541e568d1Shuajun li reg4b = *(u32 *)&buf[0x18]; 185641e568d1Shuajun li info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f); 185741e568d1Shuajun li 185841e568d1Shuajun li tmpreg = (u16) reg4b; 185941e568d1Shuajun li reg4b = *(u32 *)(&buf[0x14]); 186041e568d1Shuajun li if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC) 186141e568d1Shuajun li info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff; 186241e568d1Shuajun li 186341e568d1Shuajun li info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22); 186441e568d1Shuajun li info->SD_C_SIZE_MULT = (u8)(reg4b >> 7) & 0x07; 186541e568d1Shuajun li if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC) 186641e568d1Shuajun li info->HC_C_SIZE = *(u32 *)(&buf[0x100]); 186741e568d1Shuajun li 186841e568d1Shuajun li if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) { 186941e568d1Shuajun li info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN); 187041e568d1Shuajun li info->SD_READ_BL_LEN = SD_BLOCK_LEN; 187141e568d1Shuajun li } else { 187241e568d1Shuajun li info->SD_Block_Mult = 1; 187341e568d1Shuajun li } 187441e568d1Shuajun li 187541e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 187641e568d1Shuajun li } 187741e568d1Shuajun li 187841e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag) 187941e568d1Shuajun li { 188041e568d1Shuajun li int err; 188141e568d1Shuajun li char *fw_name = NULL; 188241e568d1Shuajun li unsigned char *buf = NULL; 188341e568d1Shuajun li const struct firmware *sd_fw = NULL; 188441e568d1Shuajun li int result = USB_STOR_TRANSPORT_ERROR; 188541e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 188641e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 188741e568d1Shuajun li 188841e568d1Shuajun li if (info->BIN_FLAG == flag) 188941e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 189041e568d1Shuajun li 189141e568d1Shuajun li switch (flag) { 189241e568d1Shuajun li /* For SD */ 189341e568d1Shuajun li case SD_INIT1_PATTERN: 1894191648d0SJoe Perches usb_stor_dbg(us, "SD_INIT1_PATTERN\n"); 1895595c8970STim Gardner fw_name = SD_INIT1_FIRMWARE; 189641e568d1Shuajun li break; 189741e568d1Shuajun li case SD_INIT2_PATTERN: 1898191648d0SJoe Perches usb_stor_dbg(us, "SD_INIT2_PATTERN\n"); 1899595c8970STim Gardner fw_name = SD_INIT2_FIRMWARE; 190041e568d1Shuajun li break; 190141e568d1Shuajun li case SD_RW_PATTERN: 1902191648d0SJoe Perches usb_stor_dbg(us, "SD_RW_PATTERN\n"); 1903595c8970STim Gardner fw_name = SD_RW_FIRMWARE; 190441e568d1Shuajun li break; 190533842cedSCho, Yu-Chen /* For MS */ 190633842cedSCho, Yu-Chen case MS_INIT_PATTERN: 1907191648d0SJoe Perches usb_stor_dbg(us, "MS_INIT_PATTERN\n"); 1908595c8970STim Gardner fw_name = MS_INIT_FIRMWARE; 190933842cedSCho, Yu-Chen break; 191033842cedSCho, Yu-Chen case MSP_RW_PATTERN: 1911191648d0SJoe Perches usb_stor_dbg(us, "MSP_RW_PATTERN\n"); 1912595c8970STim Gardner fw_name = MSP_RW_FIRMWARE; 191333842cedSCho, Yu-Chen break; 191433842cedSCho, Yu-Chen case MS_RW_PATTERN: 1915191648d0SJoe Perches usb_stor_dbg(us, "MS_RW_PATTERN\n"); 1916595c8970STim Gardner fw_name = MS_RW_FIRMWARE; 191733842cedSCho, Yu-Chen break; 191841e568d1Shuajun li default: 1919191648d0SJoe Perches usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n"); 192041e568d1Shuajun li goto nofw; 192141e568d1Shuajun li } 192241e568d1Shuajun li 192341e568d1Shuajun li err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev); 192441e568d1Shuajun li if (err) { 1925191648d0SJoe Perches usb_stor_dbg(us, "load firmware %s failed\n", fw_name); 192641e568d1Shuajun li goto nofw; 192741e568d1Shuajun li } 1928a328512dSBenoit Taine buf = kmemdup(sd_fw->data, sd_fw->size, GFP_KERNEL); 1929191648d0SJoe Perches if (buf == NULL) 193041e568d1Shuajun li goto nofw; 1931191648d0SJoe Perches 193241e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 193341e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 193441e568d1Shuajun li bcb->DataTransferLength = sd_fw->size; 193541e568d1Shuajun li bcb->Flags = 0x00; 193641e568d1Shuajun li bcb->CDB[0] = 0xEF; 193741e568d1Shuajun li 193841e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0); 1939aa18c4b6SAlan Stern if (us->srb != NULL) 1940aa18c4b6SAlan Stern scsi_set_resid(us->srb, 0); 194141e568d1Shuajun li info->BIN_FLAG = flag; 194241e568d1Shuajun li kfree(buf); 194341e568d1Shuajun li 194441e568d1Shuajun li nofw: 194541e568d1Shuajun li release_firmware(sd_fw); 194641e568d1Shuajun li return result; 194741e568d1Shuajun li } 194841e568d1Shuajun li 194933842cedSCho, Yu-Chen static int ms_card_init(struct us_data *us) 195033842cedSCho, Yu-Chen { 195133842cedSCho, Yu-Chen u32 result; 195233842cedSCho, Yu-Chen u16 TmpBlock; 195333842cedSCho, Yu-Chen unsigned char *PageBuffer0 = NULL, *PageBuffer1 = NULL; 195433842cedSCho, Yu-Chen struct ms_lib_type_extdat extdat; 195533842cedSCho, Yu-Chen u16 btBlk1st, btBlk2nd; 195633842cedSCho, Yu-Chen u32 btBlk1stErred; 195733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 195833842cedSCho, Yu-Chen 195933842cedSCho, Yu-Chen printk(KERN_INFO "MS_CardInit start\n"); 196033842cedSCho, Yu-Chen 196133842cedSCho, Yu-Chen ms_lib_free_allocatedarea(us); /* Clean buffer and set struct us_data flag to 0 */ 196233842cedSCho, Yu-Chen 196333842cedSCho, Yu-Chen /* get two PageBuffer */ 196433842cedSCho, Yu-Chen PageBuffer0 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); 196533842cedSCho, Yu-Chen PageBuffer1 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL); 196633842cedSCho, Yu-Chen if ((PageBuffer0 == NULL) || (PageBuffer1 == NULL)) { 196733842cedSCho, Yu-Chen result = MS_NO_MEMORY_ERROR; 196833842cedSCho, Yu-Chen goto exit; 196933842cedSCho, Yu-Chen } 197033842cedSCho, Yu-Chen 197133842cedSCho, Yu-Chen btBlk1st = btBlk2nd = MS_LB_NOT_USED; 197233842cedSCho, Yu-Chen btBlk1stErred = 0; 197333842cedSCho, Yu-Chen 197433842cedSCho, Yu-Chen for (TmpBlock = 0; TmpBlock < MS_MAX_INITIAL_ERROR_BLOCKS+2; TmpBlock++) { 197533842cedSCho, Yu-Chen 197633842cedSCho, Yu-Chen switch (ms_read_readpage(us, TmpBlock, 0, (u32 *)PageBuffer0, &extdat)) { 197733842cedSCho, Yu-Chen case MS_STATUS_SUCCESS: 197833842cedSCho, Yu-Chen break; 197933842cedSCho, Yu-Chen case MS_STATUS_INT_ERROR: 198033842cedSCho, Yu-Chen break; 198133842cedSCho, Yu-Chen case MS_STATUS_ERROR: 198233842cedSCho, Yu-Chen default: 198333842cedSCho, Yu-Chen continue; 198433842cedSCho, Yu-Chen } 198533842cedSCho, Yu-Chen 198633842cedSCho, Yu-Chen if ((extdat.ovrflg & MS_REG_OVR_BKST) == MS_REG_OVR_BKST_NG) 198733842cedSCho, Yu-Chen continue; 198833842cedSCho, Yu-Chen 198933842cedSCho, Yu-Chen if (((extdat.mngflg & MS_REG_MNG_SYSFLG) == MS_REG_MNG_SYSFLG_USER) || 199033842cedSCho, Yu-Chen (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wBlockID) != MS_BOOT_BLOCK_ID) || 199133842cedSCho, Yu-Chen (be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wFormatVersion) != MS_BOOT_BLOCK_FORMAT_VERSION) || 199233842cedSCho, Yu-Chen (((struct ms_bootblock_page0 *)PageBuffer0)->header.bNumberOfDataEntry != MS_BOOT_BLOCK_DATA_ENTRIES)) 199333842cedSCho, Yu-Chen continue; 199433842cedSCho, Yu-Chen 199533842cedSCho, Yu-Chen if (btBlk1st != MS_LB_NOT_USED) { 199633842cedSCho, Yu-Chen btBlk2nd = TmpBlock; 199733842cedSCho, Yu-Chen break; 199833842cedSCho, Yu-Chen } 199933842cedSCho, Yu-Chen 200033842cedSCho, Yu-Chen btBlk1st = TmpBlock; 200133842cedSCho, Yu-Chen memcpy(PageBuffer1, PageBuffer0, MS_BYTES_PER_PAGE); 200233842cedSCho, Yu-Chen if (extdat.status1 & (MS_REG_ST1_DTER | MS_REG_ST1_EXER | MS_REG_ST1_FGER)) 200333842cedSCho, Yu-Chen btBlk1stErred = 1; 200433842cedSCho, Yu-Chen } 200533842cedSCho, Yu-Chen 200633842cedSCho, Yu-Chen if (btBlk1st == MS_LB_NOT_USED) { 200733842cedSCho, Yu-Chen result = MS_STATUS_ERROR; 200833842cedSCho, Yu-Chen goto exit; 200933842cedSCho, Yu-Chen } 201033842cedSCho, Yu-Chen 201133842cedSCho, Yu-Chen /* write protect */ 201233842cedSCho, Yu-Chen if ((extdat.status0 & MS_REG_ST0_WP) == MS_REG_ST0_WP_ON) 201333842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT); 201433842cedSCho, Yu-Chen 201533842cedSCho, Yu-Chen result = MS_STATUS_ERROR; 201633842cedSCho, Yu-Chen /* 1st Boot Block */ 201733842cedSCho, Yu-Chen if (btBlk1stErred == 0) 201833842cedSCho, Yu-Chen result = ms_lib_process_bootblock(us, btBlk1st, PageBuffer1); 201933842cedSCho, Yu-Chen /* 1st */ 202033842cedSCho, Yu-Chen /* 2nd Boot Block */ 202133842cedSCho, Yu-Chen if (result && (btBlk2nd != MS_LB_NOT_USED)) 202233842cedSCho, Yu-Chen result = ms_lib_process_bootblock(us, btBlk2nd, PageBuffer0); 202333842cedSCho, Yu-Chen 202433842cedSCho, Yu-Chen if (result) { 202533842cedSCho, Yu-Chen result = MS_STATUS_ERROR; 202633842cedSCho, Yu-Chen goto exit; 202733842cedSCho, Yu-Chen } 202833842cedSCho, Yu-Chen 202933842cedSCho, Yu-Chen for (TmpBlock = 0; TmpBlock < btBlk1st; TmpBlock++) 203033842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR; 203133842cedSCho, Yu-Chen 203233842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[btBlk1st] = MS_LB_BOOT_BLOCK; 203333842cedSCho, Yu-Chen 203433842cedSCho, Yu-Chen if (btBlk2nd != MS_LB_NOT_USED) { 203533842cedSCho, Yu-Chen for (TmpBlock = btBlk1st + 1; TmpBlock < btBlk2nd; TmpBlock++) 203633842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR; 203733842cedSCho, Yu-Chen 203833842cedSCho, Yu-Chen info->MS_Lib.Phy2LogMap[btBlk2nd] = MS_LB_BOOT_BLOCK; 203933842cedSCho, Yu-Chen } 204033842cedSCho, Yu-Chen 204133842cedSCho, Yu-Chen result = ms_lib_scan_logicalblocknumber(us, btBlk1st); 204233842cedSCho, Yu-Chen if (result) 204333842cedSCho, Yu-Chen goto exit; 204433842cedSCho, Yu-Chen 204533842cedSCho, Yu-Chen for (TmpBlock = MS_PHYSICAL_BLOCKS_PER_SEGMENT; 204633842cedSCho, Yu-Chen TmpBlock < info->MS_Lib.NumberOfPhyBlock; 204733842cedSCho, Yu-Chen TmpBlock += MS_PHYSICAL_BLOCKS_PER_SEGMENT) { 204833842cedSCho, Yu-Chen if (ms_count_freeblock(us, TmpBlock) == 0) { 204933842cedSCho, Yu-Chen ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT); 205033842cedSCho, Yu-Chen break; 205133842cedSCho, Yu-Chen } 205233842cedSCho, Yu-Chen } 205333842cedSCho, Yu-Chen 205433842cedSCho, Yu-Chen /* write */ 205533842cedSCho, Yu-Chen if (ms_lib_alloc_writebuf(us)) { 205633842cedSCho, Yu-Chen result = MS_NO_MEMORY_ERROR; 205733842cedSCho, Yu-Chen goto exit; 205833842cedSCho, Yu-Chen } 205933842cedSCho, Yu-Chen 206033842cedSCho, Yu-Chen result = MS_STATUS_SUCCESS; 206133842cedSCho, Yu-Chen 206233842cedSCho, Yu-Chen exit: 206333842cedSCho, Yu-Chen kfree(PageBuffer1); 206433842cedSCho, Yu-Chen kfree(PageBuffer0); 206533842cedSCho, Yu-Chen 206633842cedSCho, Yu-Chen printk(KERN_INFO "MS_CardInit end\n"); 206733842cedSCho, Yu-Chen return result; 206833842cedSCho, Yu-Chen } 206933842cedSCho, Yu-Chen 207033842cedSCho, Yu-Chen static int ene_ms_init(struct us_data *us) 207133842cedSCho, Yu-Chen { 207233842cedSCho, Yu-Chen struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 207333842cedSCho, Yu-Chen int result; 207433842cedSCho, Yu-Chen u16 MSP_BlockSize, MSP_UserAreaBlocks; 207533842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 2076628c2893SAlan Stern u8 *bbuf = info->bbuf; 207733842cedSCho, Yu-Chen 207833842cedSCho, Yu-Chen printk(KERN_INFO "transport --- ENE_MSInit\n"); 207933842cedSCho, Yu-Chen 208033842cedSCho, Yu-Chen /* the same part to test ENE */ 208133842cedSCho, Yu-Chen 208233842cedSCho, Yu-Chen result = ene_load_bincode(us, MS_INIT_PATTERN); 208333842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 208433842cedSCho, Yu-Chen printk(KERN_ERR "Load MS Init Code Fail !!\n"); 208533842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 208633842cedSCho, Yu-Chen } 208733842cedSCho, Yu-Chen 208833842cedSCho, Yu-Chen memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 208933842cedSCho, Yu-Chen bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 209033842cedSCho, Yu-Chen bcb->DataTransferLength = 0x200; 2091b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 209233842cedSCho, Yu-Chen bcb->CDB[0] = 0xF1; 209333842cedSCho, Yu-Chen bcb->CDB[1] = 0x01; 209433842cedSCho, Yu-Chen 2095628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0); 209633842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) { 209733842cedSCho, Yu-Chen printk(KERN_ERR "Execution MS Init Code Fail !!\n"); 209833842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 209933842cedSCho, Yu-Chen } 210033842cedSCho, Yu-Chen /* the same part to test ENE */ 2101628c2893SAlan Stern info->MS_Status = *(struct MS_STATUS *) bbuf; 210233842cedSCho, Yu-Chen 210333842cedSCho, Yu-Chen if (info->MS_Status.Insert && info->MS_Status.Ready) { 210433842cedSCho, Yu-Chen printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert); 210533842cedSCho, Yu-Chen printk(KERN_INFO "Ready = %x\n", info->MS_Status.Ready); 210633842cedSCho, Yu-Chen printk(KERN_INFO "IsMSPro = %x\n", info->MS_Status.IsMSPro); 210733842cedSCho, Yu-Chen printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG); 210833842cedSCho, Yu-Chen printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP); 210933842cedSCho, Yu-Chen if (info->MS_Status.IsMSPro) { 2110628c2893SAlan Stern MSP_BlockSize = (bbuf[6] << 8) | bbuf[7]; 2111628c2893SAlan Stern MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11]; 211233842cedSCho, Yu-Chen info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; 211333842cedSCho, Yu-Chen } else { 211433842cedSCho, Yu-Chen ms_card_init(us); /* Card is MS (to ms.c)*/ 211533842cedSCho, Yu-Chen } 2116191648d0SJoe Perches usb_stor_dbg(us, "MS Init Code OK !!\n"); 211733842cedSCho, Yu-Chen } else { 2118628c2893SAlan Stern usb_stor_dbg(us, "MS Card Not Ready --- %x\n", bbuf[0]); 211933842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 212033842cedSCho, Yu-Chen } 212133842cedSCho, Yu-Chen 212233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_GOOD; 212333842cedSCho, Yu-Chen } 212433842cedSCho, Yu-Chen 212541e568d1Shuajun li static int ene_sd_init(struct us_data *us) 212641e568d1Shuajun li { 212741e568d1Shuajun li int result; 212841e568d1Shuajun li struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; 212941e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; 2130628c2893SAlan Stern u8 *bbuf = info->bbuf; 213141e568d1Shuajun li 2132191648d0SJoe Perches usb_stor_dbg(us, "transport --- ENE_SDInit\n"); 213341e568d1Shuajun li /* SD Init Part-1 */ 213441e568d1Shuajun li result = ene_load_bincode(us, SD_INIT1_PATTERN); 213541e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 2136191648d0SJoe Perches usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n"); 213741e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 213841e568d1Shuajun li } 213941e568d1Shuajun li 214041e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 214141e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 2142b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 214341e568d1Shuajun li bcb->CDB[0] = 0xF2; 214441e568d1Shuajun li 214541e568d1Shuajun li result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0); 214641e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 2147191648d0SJoe Perches usb_stor_dbg(us, "Execution SD Init Code Fail !!\n"); 214841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 214941e568d1Shuajun li } 215041e568d1Shuajun li 215141e568d1Shuajun li /* SD Init Part-2 */ 215241e568d1Shuajun li result = ene_load_bincode(us, SD_INIT2_PATTERN); 215341e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 2154191648d0SJoe Perches usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n"); 215541e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 215641e568d1Shuajun li } 215741e568d1Shuajun li 215841e568d1Shuajun li memset(bcb, 0, sizeof(struct bulk_cb_wrap)); 215941e568d1Shuajun li bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); 216041e568d1Shuajun li bcb->DataTransferLength = 0x200; 2161b8db6d64SSebastian Andrzej Siewior bcb->Flags = US_BULK_FLAG_IN; 216241e568d1Shuajun li bcb->CDB[0] = 0xF1; 216341e568d1Shuajun li 2164628c2893SAlan Stern result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0); 216541e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 2166191648d0SJoe Perches usb_stor_dbg(us, "Execution SD Init Code Fail !!\n"); 216741e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 216841e568d1Shuajun li } 216941e568d1Shuajun li 2170628c2893SAlan Stern info->SD_Status = *(struct SD_STATUS *) bbuf; 217141e568d1Shuajun li if (info->SD_Status.Insert && info->SD_Status.Ready) { 2172191648d0SJoe Perches struct SD_STATUS *s = &info->SD_Status; 2173191648d0SJoe Perches 2174628c2893SAlan Stern ene_get_card_status(us, bbuf); 2175191648d0SJoe Perches usb_stor_dbg(us, "Insert = %x\n", s->Insert); 2176191648d0SJoe Perches usb_stor_dbg(us, "Ready = %x\n", s->Ready); 2177191648d0SJoe Perches usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC); 2178191648d0SJoe Perches usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity); 2179191648d0SJoe Perches usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed); 2180191648d0SJoe Perches usb_stor_dbg(us, "WtP = %x\n", s->WtP); 218141e568d1Shuajun li } else { 2182628c2893SAlan Stern usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]); 218341e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 218441e568d1Shuajun li } 218541e568d1Shuajun li return USB_STOR_TRANSPORT_GOOD; 218641e568d1Shuajun li } 218741e568d1Shuajun li 218841e568d1Shuajun li 218941e568d1Shuajun li static int ene_init(struct us_data *us) 219041e568d1Shuajun li { 219141e568d1Shuajun li int result; 2192628c2893SAlan Stern u8 misc_reg03; 219341e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); 2194628c2893SAlan Stern u8 *bbuf = info->bbuf; 219541e568d1Shuajun li 2196628c2893SAlan Stern result = ene_get_card_type(us, REG_CARD_STATUS, bbuf); 219741e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) 219841e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 219941e568d1Shuajun li 2200628c2893SAlan Stern misc_reg03 = bbuf[0]; 220141e568d1Shuajun li if (misc_reg03 & 0x01) { 220241e568d1Shuajun li if (!info->SD_Status.Ready) { 220341e568d1Shuajun li result = ene_sd_init(us); 220441e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) 220541e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 220641e568d1Shuajun li } 220741e568d1Shuajun li } 220833842cedSCho, Yu-Chen if (misc_reg03 & 0x02) { 220933842cedSCho, Yu-Chen if (!info->MS_Status.Ready) { 221033842cedSCho, Yu-Chen result = ene_ms_init(us); 221133842cedSCho, Yu-Chen if (result != USB_STOR_XFER_GOOD) 221233842cedSCho, Yu-Chen return USB_STOR_TRANSPORT_ERROR; 221333842cedSCho, Yu-Chen } 221433842cedSCho, Yu-Chen } 221541e568d1Shuajun li return result; 221641e568d1Shuajun li } 221741e568d1Shuajun li 221841e568d1Shuajun li /*----- sd_scsi_irp() ---------*/ 221941e568d1Shuajun li static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) 222041e568d1Shuajun li { 222141e568d1Shuajun li int result; 222241e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra; 222341e568d1Shuajun li 222441e568d1Shuajun li switch (srb->cmnd[0]) { 222541e568d1Shuajun li case TEST_UNIT_READY: 222641e568d1Shuajun li result = sd_scsi_test_unit_ready(us, srb); 222741e568d1Shuajun li break; /* 0x00 */ 2228ce553bd1SAlan Stern case REQUEST_SENSE: 2229ce553bd1SAlan Stern result = do_scsi_request_sense(us, srb); 2230ce553bd1SAlan Stern break; /* 0x03 */ 223141e568d1Shuajun li case INQUIRY: 2232f8efdabdSAlan Stern result = do_scsi_inquiry(us, srb); 223341e568d1Shuajun li break; /* 0x12 */ 223441e568d1Shuajun li case MODE_SENSE: 223541e568d1Shuajun li result = sd_scsi_mode_sense(us, srb); 223641e568d1Shuajun li break; /* 0x1A */ 223741e568d1Shuajun li /* 223841e568d1Shuajun li case START_STOP: 223941e568d1Shuajun li result = SD_SCSI_Start_Stop(us, srb); 224041e568d1Shuajun li break; //0x1B 224141e568d1Shuajun li */ 224241e568d1Shuajun li case READ_CAPACITY: 224341e568d1Shuajun li result = sd_scsi_read_capacity(us, srb); 224441e568d1Shuajun li break; /* 0x25 */ 224541e568d1Shuajun li case READ_10: 224641e568d1Shuajun li result = sd_scsi_read(us, srb); 224741e568d1Shuajun li break; /* 0x28 */ 224841e568d1Shuajun li case WRITE_10: 224941e568d1Shuajun li result = sd_scsi_write(us, srb); 225041e568d1Shuajun li break; /* 0x2A */ 225141e568d1Shuajun li default: 225241e568d1Shuajun li info->SrbStatus = SS_ILLEGAL_REQUEST; 225341e568d1Shuajun li result = USB_STOR_TRANSPORT_FAILED; 225441e568d1Shuajun li break; 225541e568d1Shuajun li } 2256ce553bd1SAlan Stern if (result == USB_STOR_TRANSPORT_GOOD) 2257ce553bd1SAlan Stern info->SrbStatus = SS_SUCCESS; 225841e568d1Shuajun li return result; 225941e568d1Shuajun li } 226041e568d1Shuajun li 226133842cedSCho, Yu-Chen /* 226233842cedSCho, Yu-Chen * ms_scsi_irp() 226333842cedSCho, Yu-Chen */ 226436f3a14dSFelipe Balbi static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb) 226533842cedSCho, Yu-Chen { 226633842cedSCho, Yu-Chen int result; 226733842cedSCho, Yu-Chen struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra; 2268ce553bd1SAlan Stern 226933842cedSCho, Yu-Chen switch (srb->cmnd[0]) { 227033842cedSCho, Yu-Chen case TEST_UNIT_READY: 227133842cedSCho, Yu-Chen result = ms_scsi_test_unit_ready(us, srb); 227233842cedSCho, Yu-Chen break; /* 0x00 */ 2273ce553bd1SAlan Stern case REQUEST_SENSE: 2274ce553bd1SAlan Stern result = do_scsi_request_sense(us, srb); 2275ce553bd1SAlan Stern break; /* 0x03 */ 227633842cedSCho, Yu-Chen case INQUIRY: 2277f8efdabdSAlan Stern result = do_scsi_inquiry(us, srb); 227833842cedSCho, Yu-Chen break; /* 0x12 */ 227933842cedSCho, Yu-Chen case MODE_SENSE: 228033842cedSCho, Yu-Chen result = ms_scsi_mode_sense(us, srb); 228133842cedSCho, Yu-Chen break; /* 0x1A */ 228233842cedSCho, Yu-Chen case READ_CAPACITY: 228333842cedSCho, Yu-Chen result = ms_scsi_read_capacity(us, srb); 228433842cedSCho, Yu-Chen break; /* 0x25 */ 228533842cedSCho, Yu-Chen case READ_10: 228633842cedSCho, Yu-Chen result = ms_scsi_read(us, srb); 228733842cedSCho, Yu-Chen break; /* 0x28 */ 228833842cedSCho, Yu-Chen case WRITE_10: 228933842cedSCho, Yu-Chen result = ms_scsi_write(us, srb); 229033842cedSCho, Yu-Chen break; /* 0x2A */ 229133842cedSCho, Yu-Chen default: 229233842cedSCho, Yu-Chen info->SrbStatus = SS_ILLEGAL_REQUEST; 229333842cedSCho, Yu-Chen result = USB_STOR_TRANSPORT_FAILED; 229433842cedSCho, Yu-Chen break; 229533842cedSCho, Yu-Chen } 2296ce553bd1SAlan Stern if (result == USB_STOR_TRANSPORT_GOOD) 2297ce553bd1SAlan Stern info->SrbStatus = SS_SUCCESS; 229833842cedSCho, Yu-Chen return result; 229933842cedSCho, Yu-Chen } 230033842cedSCho, Yu-Chen 230141e568d1Shuajun li static int ene_transport(struct scsi_cmnd *srb, struct us_data *us) 230241e568d1Shuajun li { 23034b309f1cSAlan Stern int result = USB_STOR_XFER_GOOD; 230441e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); 230541e568d1Shuajun li 2306191648d0SJoe Perches /*US_DEBUG(usb_stor_show_command(us, srb)); */ 230741e568d1Shuajun li scsi_set_resid(srb, 0); 23084b309f1cSAlan Stern if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready))) 230941e568d1Shuajun li result = ene_init(us); 23104b309f1cSAlan Stern if (result == USB_STOR_XFER_GOOD) { 23114b309f1cSAlan Stern result = USB_STOR_TRANSPORT_ERROR; 231233842cedSCho, Yu-Chen if (info->SD_Status.Ready) 231341e568d1Shuajun li result = sd_scsi_irp(us, srb); 231441e568d1Shuajun li 231533842cedSCho, Yu-Chen if (info->MS_Status.Ready) 231633842cedSCho, Yu-Chen result = ms_scsi_irp(us, srb); 231733842cedSCho, Yu-Chen } 23184b309f1cSAlan Stern return result; 231941e568d1Shuajun li } 232041e568d1Shuajun li 2321aa519be3SAkinobu Mita static struct scsi_host_template ene_ub6250_host_template; 232241e568d1Shuajun li 232341e568d1Shuajun li static int ene_ub6250_probe(struct usb_interface *intf, 232441e568d1Shuajun li const struct usb_device_id *id) 232541e568d1Shuajun li { 232641e568d1Shuajun li int result; 2327628c2893SAlan Stern u8 misc_reg03; 232841e568d1Shuajun li struct us_data *us; 2329628c2893SAlan Stern struct ene_ub6250_info *info; 233041e568d1Shuajun li 233141e568d1Shuajun li result = usb_stor_probe1(&us, intf, id, 2332aa519be3SAkinobu Mita (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list, 2333aa519be3SAkinobu Mita &ene_ub6250_host_template); 233441e568d1Shuajun li if (result) 233541e568d1Shuajun li return result; 233641e568d1Shuajun li 233741e568d1Shuajun li /* FIXME: where should the code alloc extra buf ? */ 233841e568d1Shuajun li us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL); 233941e568d1Shuajun li if (!us->extra) 234041e568d1Shuajun li return -ENOMEM; 234141e568d1Shuajun li us->extra_destructor = ene_ub6250_info_destructor; 2342628c2893SAlan Stern 2343628c2893SAlan Stern info = (struct ene_ub6250_info *)(us->extra); 2344628c2893SAlan Stern info->bbuf = kmalloc(512, GFP_KERNEL); 2345628c2893SAlan Stern if (!info->bbuf) { 2346628c2893SAlan Stern kfree(us->extra); 2347628c2893SAlan Stern return -ENOMEM; 234841e568d1Shuajun li } 234941e568d1Shuajun li 235041e568d1Shuajun li us->transport_name = "ene_ub6250"; 235141e568d1Shuajun li us->transport = ene_transport; 235241e568d1Shuajun li us->max_lun = 0; 235341e568d1Shuajun li 235441e568d1Shuajun li result = usb_stor_probe2(us); 235541e568d1Shuajun li if (result) 235641e568d1Shuajun li return result; 235741e568d1Shuajun li 235841e568d1Shuajun li /* probe card type */ 2359628c2893SAlan Stern result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf); 236041e568d1Shuajun li if (result != USB_STOR_XFER_GOOD) { 236141e568d1Shuajun li usb_stor_disconnect(intf); 236241e568d1Shuajun li return USB_STOR_TRANSPORT_ERROR; 236341e568d1Shuajun li } 236441e568d1Shuajun li 2365628c2893SAlan Stern misc_reg03 = info->bbuf[0]; 236641e568d1Shuajun li if (!(misc_reg03 & 0x01)) { 236716fae052SKristina Martšenko pr_info("ums_eneub6250: This driver only supports SD/MS cards. " 236816fae052SKristina Martšenko "It does not support SM cards.\n"); 236941e568d1Shuajun li } 237041e568d1Shuajun li 237141e568d1Shuajun li return result; 237241e568d1Shuajun li } 237341e568d1Shuajun li 237441e568d1Shuajun li 237541e568d1Shuajun li #ifdef CONFIG_PM 237641e568d1Shuajun li 237741e568d1Shuajun li static int ene_ub6250_resume(struct usb_interface *iface) 237841e568d1Shuajun li { 237941e568d1Shuajun li u8 tmp = 0; 238041e568d1Shuajun li struct us_data *us = usb_get_intfdata(iface); 238141e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); 238241e568d1Shuajun li 238341e568d1Shuajun li mutex_lock(&us->dev_mutex); 238441e568d1Shuajun li 238541e568d1Shuajun li if (us->suspend_resume_hook) 238641e568d1Shuajun li (us->suspend_resume_hook)(us, US_RESUME); 238741e568d1Shuajun li 238841e568d1Shuajun li mutex_unlock(&us->dev_mutex); 238941e568d1Shuajun li 239041e568d1Shuajun li info->Power_IsResum = true; 239141e568d1Shuajun li /*info->SD_Status.Ready = 0; */ 239241e568d1Shuajun li info->SD_Status = *(struct SD_STATUS *)&tmp; 239341e568d1Shuajun li info->MS_Status = *(struct MS_STATUS *)&tmp; 239441e568d1Shuajun li info->SM_Status = *(struct SM_STATUS *)&tmp; 239541e568d1Shuajun li 239641e568d1Shuajun li return 0; 239741e568d1Shuajun li } 239841e568d1Shuajun li 239941e568d1Shuajun li static int ene_ub6250_reset_resume(struct usb_interface *iface) 240041e568d1Shuajun li { 240141e568d1Shuajun li u8 tmp = 0; 240241e568d1Shuajun li struct us_data *us = usb_get_intfdata(iface); 240341e568d1Shuajun li struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); 2404191648d0SJoe Perches 240541e568d1Shuajun li /* Report the reset to the SCSI core */ 240641e568d1Shuajun li usb_stor_reset_resume(iface); 240741e568d1Shuajun li 2408f0183a33SFelipe Balbi /* 2409f0183a33SFelipe Balbi * FIXME: Notify the subdrivers that they need to reinitialize 2410f0183a33SFelipe Balbi * the device 2411f0183a33SFelipe Balbi */ 241241e568d1Shuajun li info->Power_IsResum = true; 241341e568d1Shuajun li /*info->SD_Status.Ready = 0; */ 241441e568d1Shuajun li info->SD_Status = *(struct SD_STATUS *)&tmp; 241541e568d1Shuajun li info->MS_Status = *(struct MS_STATUS *)&tmp; 241641e568d1Shuajun li info->SM_Status = *(struct SM_STATUS *)&tmp; 241741e568d1Shuajun li 241841e568d1Shuajun li return 0; 241941e568d1Shuajun li } 242041e568d1Shuajun li 242141e568d1Shuajun li #else 242241e568d1Shuajun li 242341e568d1Shuajun li #define ene_ub6250_resume NULL 242441e568d1Shuajun li #define ene_ub6250_reset_resume NULL 242541e568d1Shuajun li 242641e568d1Shuajun li #endif 242741e568d1Shuajun li 242841e568d1Shuajun li static struct usb_driver ene_ub6250_driver = { 2429aa519be3SAkinobu Mita .name = DRV_NAME, 243041e568d1Shuajun li .probe = ene_ub6250_probe, 243141e568d1Shuajun li .disconnect = usb_stor_disconnect, 243241e568d1Shuajun li .suspend = usb_stor_suspend, 243341e568d1Shuajun li .resume = ene_ub6250_resume, 243441e568d1Shuajun li .reset_resume = ene_ub6250_reset_resume, 243541e568d1Shuajun li .pre_reset = usb_stor_pre_reset, 243641e568d1Shuajun li .post_reset = usb_stor_post_reset, 243741e568d1Shuajun li .id_table = ene_ub6250_usb_ids, 243841e568d1Shuajun li .soft_unbind = 1, 2439e73b2db6SHuajun Li .no_dynamic_id = 1, 244041e568d1Shuajun li }; 244141e568d1Shuajun li 2442aa519be3SAkinobu Mita module_usb_stor_driver(ene_ub6250_driver, ene_ub6250_host_template, DRV_NAME); 2443