xref: /openbmc/linux/drivers/usb/storage/ene_ub6250.c (revision aa18c4b6)
141e568d1Shuajun li /*
241e568d1Shuajun li  *
341e568d1Shuajun li  * This program is free software; you can redistribute it and/or modify it
441e568d1Shuajun li  * under the terms of the GNU General Public License as published by the
541e568d1Shuajun li  * Free Software Foundation; either version 2, or (at your option) any
641e568d1Shuajun li  * later version.
741e568d1Shuajun li  *
841e568d1Shuajun li  * This program is distributed in the hope that it will be useful, but
941e568d1Shuajun li  * WITHOUT ANY WARRANTY; without even the implied warranty of
1041e568d1Shuajun li  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
1141e568d1Shuajun li  * General Public License for more details.
1241e568d1Shuajun li  *
1341e568d1Shuajun li  * You should have received a copy of the GNU General Public License along
1441e568d1Shuajun li  * with this program; if not, write to the Free Software Foundation, Inc.,
1541e568d1Shuajun li  * 675 Mass Ave, Cambridge, MA 02139, USA.
1641e568d1Shuajun li  */
1741e568d1Shuajun li #include <linux/jiffies.h>
1841e568d1Shuajun li #include <linux/errno.h>
1941e568d1Shuajun li #include <linux/module.h>
2041e568d1Shuajun li #include <linux/slab.h>
2141e568d1Shuajun li 
2241e568d1Shuajun li #include <scsi/scsi.h>
2341e568d1Shuajun li #include <scsi/scsi_cmnd.h>
2441e568d1Shuajun li 
2541e568d1Shuajun li #include <linux/firmware.h>
2641e568d1Shuajun li 
2741e568d1Shuajun li #include "usb.h"
2841e568d1Shuajun li #include "transport.h"
2941e568d1Shuajun li #include "protocol.h"
3041e568d1Shuajun li #include "debug.h"
31aa519be3SAkinobu Mita #include "scsiglue.h"
3241e568d1Shuajun li 
33595c8970STim Gardner #define SD_INIT1_FIRMWARE "ene-ub6250/sd_init1.bin"
34595c8970STim Gardner #define SD_INIT2_FIRMWARE "ene-ub6250/sd_init2.bin"
35595c8970STim Gardner #define SD_RW_FIRMWARE "ene-ub6250/sd_rdwr.bin"
36595c8970STim Gardner #define MS_INIT_FIRMWARE "ene-ub6250/ms_init.bin"
37595c8970STim Gardner #define MSP_RW_FIRMWARE "ene-ub6250/msp_rdwr.bin"
38595c8970STim Gardner #define MS_RW_FIRMWARE "ene-ub6250/ms_rdwr.bin"
39595c8970STim Gardner 
40aa519be3SAkinobu Mita #define DRV_NAME "ums_eneub6250"
41aa519be3SAkinobu Mita 
4241e568d1Shuajun li MODULE_DESCRIPTION("Driver for ENE UB6250 reader");
4341e568d1Shuajun li MODULE_LICENSE("GPL");
44595c8970STim Gardner MODULE_FIRMWARE(SD_INIT1_FIRMWARE);
45595c8970STim Gardner MODULE_FIRMWARE(SD_INIT2_FIRMWARE);
46595c8970STim Gardner MODULE_FIRMWARE(SD_RW_FIRMWARE);
47595c8970STim Gardner MODULE_FIRMWARE(MS_INIT_FIRMWARE);
48595c8970STim Gardner MODULE_FIRMWARE(MSP_RW_FIRMWARE);
49595c8970STim Gardner MODULE_FIRMWARE(MS_RW_FIRMWARE);
5041e568d1Shuajun li 
5141e568d1Shuajun li /*
5241e568d1Shuajun li  * The table of devices
5341e568d1Shuajun li  */
5441e568d1Shuajun li #define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
5541e568d1Shuajun li 		    vendorName, productName, useProtocol, useTransport, \
5641e568d1Shuajun li 		    initFunction, flags) \
5741e568d1Shuajun li { USB_DEVICE_VER(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax), \
58f61870eeSSebastian Andrzej Siewior 	.driver_info = (flags)}
5941e568d1Shuajun li 
6036f3a14dSFelipe Balbi static struct usb_device_id ene_ub6250_usb_ids[] = {
6141e568d1Shuajun li #	include "unusual_ene_ub6250.h"
6241e568d1Shuajun li 	{ }		/* Terminating entry */
6341e568d1Shuajun li };
6441e568d1Shuajun li MODULE_DEVICE_TABLE(usb, ene_ub6250_usb_ids);
6541e568d1Shuajun li 
6641e568d1Shuajun li #undef UNUSUAL_DEV
6741e568d1Shuajun li 
6841e568d1Shuajun li /*
6941e568d1Shuajun li  * The flags table
7041e568d1Shuajun li  */
7141e568d1Shuajun li #define UNUSUAL_DEV(idVendor, idProduct, bcdDeviceMin, bcdDeviceMax, \
7241e568d1Shuajun li 		    vendor_name, product_name, use_protocol, use_transport, \
7341e568d1Shuajun li 		    init_function, Flags) \
7441e568d1Shuajun li { \
7541e568d1Shuajun li 	.vendorName = vendor_name,	\
7641e568d1Shuajun li 	.productName = product_name,	\
7741e568d1Shuajun li 	.useProtocol = use_protocol,	\
7841e568d1Shuajun li 	.useTransport = use_transport,	\
7941e568d1Shuajun li 	.initFunction = init_function,	\
8041e568d1Shuajun li }
8141e568d1Shuajun li 
8241e568d1Shuajun li static struct us_unusual_dev ene_ub6250_unusual_dev_list[] = {
8341e568d1Shuajun li #	include "unusual_ene_ub6250.h"
8441e568d1Shuajun li 	{ }		/* Terminating entry */
8541e568d1Shuajun li };
8641e568d1Shuajun li 
8741e568d1Shuajun li #undef UNUSUAL_DEV
8841e568d1Shuajun li 
8941e568d1Shuajun li 
9041e568d1Shuajun li 
9141e568d1Shuajun li /* ENE bin code len */
9241e568d1Shuajun li #define ENE_BIN_CODE_LEN    0x800
9341e568d1Shuajun li /* EnE HW Register */
9441e568d1Shuajun li #define REG_CARD_STATUS     0xFF83
9541e568d1Shuajun li #define REG_HW_TRAP1        0xFF89
9641e568d1Shuajun li 
9741e568d1Shuajun li /* SRB Status */
9841e568d1Shuajun li #define SS_SUCCESS                  0x00      /* No Sense */
9941e568d1Shuajun li #define SS_NOT_READY                0x02
10041e568d1Shuajun li #define SS_MEDIUM_ERR               0x03
10141e568d1Shuajun li #define SS_HW_ERR                   0x04
10241e568d1Shuajun li #define SS_ILLEGAL_REQUEST          0x05
10341e568d1Shuajun li #define SS_UNIT_ATTENTION           0x06
10441e568d1Shuajun li 
10541e568d1Shuajun li /* ENE Load FW Pattern */
10641e568d1Shuajun li #define SD_INIT1_PATTERN   1
10741e568d1Shuajun li #define SD_INIT2_PATTERN   2
10841e568d1Shuajun li #define SD_RW_PATTERN      3
10941e568d1Shuajun li #define MS_INIT_PATTERN    4
11041e568d1Shuajun li #define MSP_RW_PATTERN     5
11141e568d1Shuajun li #define MS_RW_PATTERN      6
11241e568d1Shuajun li #define SM_INIT_PATTERN    7
11341e568d1Shuajun li #define SM_RW_PATTERN      8
11441e568d1Shuajun li 
11541e568d1Shuajun li #define FDIR_WRITE         0
11641e568d1Shuajun li #define FDIR_READ          1
11741e568d1Shuajun li 
11833842cedSCho, Yu-Chen /* For MS Card */
11933842cedSCho, Yu-Chen 
12033842cedSCho, Yu-Chen /* Status Register 1 */
12133842cedSCho, Yu-Chen #define MS_REG_ST1_MB           0x80    /* media busy */
12233842cedSCho, Yu-Chen #define MS_REG_ST1_FB1          0x40    /* flush busy 1 */
12333842cedSCho, Yu-Chen #define MS_REG_ST1_DTER         0x20    /* error on data(corrected) */
12433842cedSCho, Yu-Chen #define MS_REG_ST1_UCDT         0x10    /* unable to correct data */
12533842cedSCho, Yu-Chen #define MS_REG_ST1_EXER         0x08    /* error on extra(corrected) */
12633842cedSCho, Yu-Chen #define MS_REG_ST1_UCEX         0x04    /* unable to correct extra */
12733842cedSCho, Yu-Chen #define MS_REG_ST1_FGER         0x02    /* error on overwrite flag(corrected) */
12833842cedSCho, Yu-Chen #define MS_REG_ST1_UCFG         0x01    /* unable to correct overwrite flag */
12933842cedSCho, 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)
13033842cedSCho, Yu-Chen 
13133842cedSCho, Yu-Chen /* Overwrite Area */
13233842cedSCho, Yu-Chen #define MS_REG_OVR_BKST		0x80            /* block status */
13333842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_OK	MS_REG_OVR_BKST     /* OK */
13433842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_NG	0x00            /* NG */
13533842cedSCho, Yu-Chen #define MS_REG_OVR_PGST0	0x40            /* page status */
13633842cedSCho, Yu-Chen #define MS_REG_OVR_PGST1	0x20
13733842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_MASK	(MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1)
13833842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_OK	(MS_REG_OVR_PGST0 | MS_REG_OVR_PGST1) /* OK */
13933842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_NG	MS_REG_OVR_PGST1                      /* NG */
14033842cedSCho, Yu-Chen #define MS_REG_OVR_PGST_DATA_ERROR	0x00        /* data error */
14133842cedSCho, Yu-Chen #define MS_REG_OVR_UDST			0x10        /* update status */
14233842cedSCho, Yu-Chen #define MS_REG_OVR_UDST_UPDATING	0x00        /* updating */
14333842cedSCho, Yu-Chen #define MS_REG_OVR_UDST_NO_UPDATE	MS_REG_OVR_UDST
14433842cedSCho, Yu-Chen #define MS_REG_OVR_RESERVED	0x08
14533842cedSCho, 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)
14633842cedSCho, Yu-Chen 
14733842cedSCho, Yu-Chen /* Management Flag */
14833842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS0	0x20    /* serial copy management system */
14933842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS1	0x10
15033842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_MASK		(MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
15133842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_COPY_OK		(MS_REG_MNG_SCMS0 | MS_REG_MNG_SCMS1)
15233842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_ONE_COPY	MS_REG_MNG_SCMS1
15333842cedSCho, Yu-Chen #define MS_REG_MNG_SCMS_NO_COPY	0x00
15433842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG	0x08    /* address transfer table flag */
15533842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG_OTHER	MS_REG_MNG_ATFLG    /* other */
15633842cedSCho, Yu-Chen #define MS_REG_MNG_ATFLG_ATTBL	0x00	/* address transfer table */
15733842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG	0x04	/* system flag */
15833842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_USER	MS_REG_MNG_SYSFLG   /* user block */
15933842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_BOOT	0x00	/* system block */
16033842cedSCho, Yu-Chen #define MS_REG_MNG_RESERVED	0xc3
16133842cedSCho, 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)
16233842cedSCho, Yu-Chen 
16333842cedSCho, Yu-Chen 
16433842cedSCho, Yu-Chen #define MS_MAX_PAGES_PER_BLOCK		32
16533842cedSCho, Yu-Chen #define MS_MAX_INITIAL_ERROR_BLOCKS 	10
16633842cedSCho, Yu-Chen #define MS_LIB_BITS_PER_BYTE		8
16733842cedSCho, Yu-Chen 
16833842cedSCho, Yu-Chen #define MS_SYSINF_FORMAT_FAT		1
16933842cedSCho, Yu-Chen #define MS_SYSINF_USAGE_GENERAL		0
17033842cedSCho, Yu-Chen 
17133842cedSCho, Yu-Chen #define MS_SYSINF_MSCLASS_TYPE_1	1
17233842cedSCho, Yu-Chen #define MS_SYSINF_PAGE_SIZE		MS_BYTES_PER_PAGE /* fixed */
17333842cedSCho, Yu-Chen 
17433842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_RDONLY	1
17533842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_RDWR		2
17633842cedSCho, Yu-Chen #define MS_SYSINF_CARDTYPE_HYBRID	3
17733842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY		0x01
17833842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY_NO_SUPPORT	MS_SYSINF_SECURITY
17933842cedSCho, Yu-Chen #define MS_SYSINF_SECURITY_SUPPORT	0
18033842cedSCho, Yu-Chen 
18133842cedSCho, Yu-Chen #define MS_SYSINF_RESERVED1		1
18233842cedSCho, Yu-Chen #define MS_SYSINF_RESERVED2		1
18333842cedSCho, Yu-Chen 
18433842cedSCho, Yu-Chen #define MS_SYSENT_TYPE_INVALID_BLOCK	0x01
18533842cedSCho, Yu-Chen #define MS_SYSENT_TYPE_CIS_IDI		0x0a    /* CIS/IDI */
18633842cedSCho, Yu-Chen 
18733842cedSCho, Yu-Chen #define SIZE_OF_KIRO		1024
18833842cedSCho, Yu-Chen #define BYTE_MASK		0xff
18933842cedSCho, Yu-Chen 
19033842cedSCho, Yu-Chen /* ms error code */
19133842cedSCho, Yu-Chen #define MS_STATUS_WRITE_PROTECT	0x0106
19233842cedSCho, Yu-Chen #define MS_STATUS_SUCCESS	0x0000
19333842cedSCho, Yu-Chen #define MS_ERROR_FLASH_READ	0x8003
19433842cedSCho, Yu-Chen #define MS_ERROR_FLASH_ERASE	0x8005
19533842cedSCho, Yu-Chen #define MS_LB_ERROR		0xfff0
19633842cedSCho, Yu-Chen #define MS_LB_BOOT_BLOCK	0xfff1
19733842cedSCho, Yu-Chen #define MS_LB_INITIAL_ERROR	0xfff2
19833842cedSCho, Yu-Chen #define MS_STATUS_SUCCESS_WITH_ECC 0xfff3
19933842cedSCho, Yu-Chen #define MS_LB_ACQUIRED_ERROR	0xfff4
20033842cedSCho, Yu-Chen #define MS_LB_NOT_USED_ERASED	0xfff5
20133842cedSCho, Yu-Chen #define MS_NOCARD_ERROR		0xfff8
20233842cedSCho, Yu-Chen #define MS_NO_MEMORY_ERROR	0xfff9
20333842cedSCho, Yu-Chen #define MS_STATUS_INT_ERROR	0xfffa
20433842cedSCho, Yu-Chen #define MS_STATUS_ERROR		0xfffe
20533842cedSCho, Yu-Chen #define MS_LB_NOT_USED		0xffff
20633842cedSCho, Yu-Chen 
20733842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG	0x04    /* system flag */
20833842cedSCho, Yu-Chen #define MS_REG_MNG_SYSFLG_USER	MS_REG_MNG_SYSFLG   /* user block */
20933842cedSCho, Yu-Chen 
21033842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_ID                        0x0001
21133842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_FORMAT_VERSION            0x0100
21233842cedSCho, Yu-Chen #define MS_BOOT_BLOCK_DATA_ENTRIES              2
21333842cedSCho, Yu-Chen 
21433842cedSCho, Yu-Chen #define MS_NUMBER_OF_SYSTEM_ENTRY       	4
21533842cedSCho, Yu-Chen #define MS_NUMBER_OF_BOOT_BLOCK			2
21633842cedSCho, Yu-Chen #define MS_BYTES_PER_PAGE			512
21733842cedSCho, Yu-Chen #define MS_LOGICAL_BLOCKS_PER_SEGMENT		496
21833842cedSCho, Yu-Chen #define MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT        494
21933842cedSCho, Yu-Chen 
22033842cedSCho, Yu-Chen #define MS_PHYSICAL_BLOCKS_PER_SEGMENT		0x200 /* 512 */
22133842cedSCho, Yu-Chen #define MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK     0x1ff
22233842cedSCho, Yu-Chen 
22333842cedSCho, Yu-Chen /* overwrite area */
22433842cedSCho, Yu-Chen #define MS_REG_OVR_BKST		0x80		/* block status */
22533842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_OK	MS_REG_OVR_BKST	/* OK */
22633842cedSCho, Yu-Chen #define MS_REG_OVR_BKST_NG	0x00            /* NG */
22733842cedSCho, Yu-Chen 
22833842cedSCho, Yu-Chen /* Status Register 1 */
22933842cedSCho, Yu-Chen #define MS_REG_ST1_DTER		0x20	/* error on data(corrected) */
23033842cedSCho, Yu-Chen #define MS_REG_ST1_EXER		0x08	/* error on extra(corrected) */
23133842cedSCho, Yu-Chen #define MS_REG_ST1_FGER		0x02	/* error on overwrite flag(corrected) */
23233842cedSCho, Yu-Chen 
23333842cedSCho, Yu-Chen /* MemoryStick Register */
23433842cedSCho, Yu-Chen /* Status Register 0 */
23533842cedSCho, Yu-Chen #define MS_REG_ST0_WP		0x01	/* write protected */
23633842cedSCho, Yu-Chen #define MS_REG_ST0_WP_ON	MS_REG_ST0_WP
23733842cedSCho, Yu-Chen 
23833842cedSCho, Yu-Chen #define MS_LIB_CTRL_RDONLY      0
23933842cedSCho, Yu-Chen #define MS_LIB_CTRL_WRPROTECT   1
24033842cedSCho, Yu-Chen 
24133842cedSCho, Yu-Chen /*dphy->log table */
24233842cedSCho, Yu-Chen #define ms_libconv_to_logical(pdx, PhyBlock) (((PhyBlock) >= (pdx)->MS_Lib.NumberOfPhyBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Phy2LogMap[PhyBlock])
24333842cedSCho, Yu-Chen #define ms_libconv_to_physical(pdx, LogBlock) (((LogBlock) >= (pdx)->MS_Lib.NumberOfLogBlock) ? MS_STATUS_ERROR : (pdx)->MS_Lib.Log2PhyMap[LogBlock])
24433842cedSCho, Yu-Chen 
24533842cedSCho, Yu-Chen #define ms_lib_ctrl_set(pdx, Flag)	((pdx)->MS_Lib.flags |= (1 << (Flag)))
24633842cedSCho, Yu-Chen #define ms_lib_ctrl_reset(pdx, Flag)	((pdx)->MS_Lib.flags &= ~(1 << (Flag)))
24733842cedSCho, Yu-Chen #define ms_lib_ctrl_check(pdx, Flag)	((pdx)->MS_Lib.flags & (1 << (Flag)))
24833842cedSCho, Yu-Chen 
24933842cedSCho, 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))
25033842cedSCho, Yu-Chen #define ms_lib_clear_pagemap(pdx) memset((pdx)->MS_Lib.pagemap, 0, sizeof((pdx)->MS_Lib.pagemap))
25133842cedSCho, Yu-Chen #define memstick_logaddr(logadr1, logadr0) ((((u16)(logadr1)) << 8) | (logadr0))
25233842cedSCho, Yu-Chen 
25341e568d1Shuajun li 
25441e568d1Shuajun li struct SD_STATUS {
25541e568d1Shuajun li 	u8    Insert:1;
25641e568d1Shuajun li 	u8    Ready:1;
25741e568d1Shuajun li 	u8    MediaChange:1;
25841e568d1Shuajun li 	u8    IsMMC:1;
25941e568d1Shuajun li 	u8    HiCapacity:1;
26041e568d1Shuajun li 	u8    HiSpeed:1;
26141e568d1Shuajun li 	u8    WtP:1;
26241e568d1Shuajun li 	u8    Reserved:1;
26341e568d1Shuajun li };
26441e568d1Shuajun li 
26541e568d1Shuajun li struct MS_STATUS {
26641e568d1Shuajun li 	u8    Insert:1;
26741e568d1Shuajun li 	u8    Ready:1;
26841e568d1Shuajun li 	u8    MediaChange:1;
26941e568d1Shuajun li 	u8    IsMSPro:1;
27041e568d1Shuajun li 	u8    IsMSPHG:1;
27141e568d1Shuajun li 	u8    Reserved1:1;
27241e568d1Shuajun li 	u8    WtP:1;
27341e568d1Shuajun li 	u8    Reserved2:1;
27441e568d1Shuajun li };
27541e568d1Shuajun li 
27641e568d1Shuajun li struct SM_STATUS {
27741e568d1Shuajun li 	u8    Insert:1;
27841e568d1Shuajun li 	u8    Ready:1;
27941e568d1Shuajun li 	u8    MediaChange:1;
28041e568d1Shuajun li 	u8    Reserved:3;
28141e568d1Shuajun li 	u8    WtP:1;
28241e568d1Shuajun li 	u8    IsMS:1;
28341e568d1Shuajun li };
28441e568d1Shuajun li 
28533842cedSCho, Yu-Chen struct ms_bootblock_cis {
28633842cedSCho, Yu-Chen 	u8 bCistplDEVICE[6];    /* 0 */
28733842cedSCho, Yu-Chen 	u8 bCistplDEVICE0C[6];  /* 6 */
28833842cedSCho, Yu-Chen 	u8 bCistplJEDECC[4];    /* 12 */
28933842cedSCho, Yu-Chen 	u8 bCistplMANFID[6];    /* 16 */
29033842cedSCho, Yu-Chen 	u8 bCistplVER1[32];     /* 22 */
29133842cedSCho, Yu-Chen 	u8 bCistplFUNCID[4];    /* 54 */
29233842cedSCho, Yu-Chen 	u8 bCistplFUNCE0[4];    /* 58 */
29333842cedSCho, Yu-Chen 	u8 bCistplFUNCE1[5];    /* 62 */
29433842cedSCho, Yu-Chen 	u8 bCistplCONF[7];      /* 67 */
29533842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT0[10];/* 74 */
29633842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT1[8]; /* 84 */
29733842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT2[12];/* 92 */
29833842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT3[8]; /* 104 */
29933842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT4[17];/* 112 */
30033842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT5[8]; /* 129 */
30133842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT6[17];/* 137 */
30233842cedSCho, Yu-Chen 	u8 bCistplCFTBLENT7[8]; /* 154 */
30333842cedSCho, Yu-Chen 	u8 bCistplNOLINK[3];    /* 162 */
30433842cedSCho, Yu-Chen } ;
30533842cedSCho, Yu-Chen 
30633842cedSCho, Yu-Chen struct ms_bootblock_idi {
30733842cedSCho, Yu-Chen #define MS_IDI_GENERAL_CONF 0x848A
30833842cedSCho, Yu-Chen 	u16 wIDIgeneralConfiguration;	/* 0 */
30933842cedSCho, Yu-Chen 	u16 wIDInumberOfCylinder;	/* 1 */
31033842cedSCho, Yu-Chen 	u16 wIDIreserved0;		/* 2 */
31133842cedSCho, Yu-Chen 	u16 wIDInumberOfHead;		/* 3 */
31233842cedSCho, Yu-Chen 	u16 wIDIbytesPerTrack;		/* 4 */
31333842cedSCho, Yu-Chen 	u16 wIDIbytesPerSector;		/* 5 */
31433842cedSCho, Yu-Chen 	u16 wIDIsectorsPerTrack;	/* 6 */
31533842cedSCho, Yu-Chen 	u16 wIDItotalSectors[2];	/* 7-8  high,low */
31633842cedSCho, Yu-Chen 	u16 wIDIreserved1[11];		/* 9-19 */
31733842cedSCho, Yu-Chen 	u16 wIDIbufferType;		/* 20 */
31833842cedSCho, Yu-Chen 	u16 wIDIbufferSize;		/* 21 */
31933842cedSCho, Yu-Chen 	u16 wIDIlongCmdECC;		/* 22 */
32033842cedSCho, Yu-Chen 	u16 wIDIfirmVersion[4];		/* 23-26 */
32133842cedSCho, Yu-Chen 	u16 wIDImodelName[20];		/* 27-46 */
32233842cedSCho, Yu-Chen 	u16 wIDIreserved2;		/* 47 */
32333842cedSCho, Yu-Chen 	u16 wIDIlongWordSupported;	/* 48 */
32433842cedSCho, Yu-Chen 	u16 wIDIdmaSupported;		/* 49 */
32533842cedSCho, Yu-Chen 	u16 wIDIreserved3;		/* 50 */
32633842cedSCho, Yu-Chen 	u16 wIDIpioTiming;		/* 51 */
32733842cedSCho, Yu-Chen 	u16 wIDIdmaTiming;		/* 52 */
32833842cedSCho, Yu-Chen 	u16 wIDItransferParameter;	/* 53 */
32933842cedSCho, Yu-Chen 	u16 wIDIformattedCylinder;	/* 54 */
33033842cedSCho, Yu-Chen 	u16 wIDIformattedHead;		/* 55 */
33133842cedSCho, Yu-Chen 	u16 wIDIformattedSectorsPerTrack;/* 56 */
33233842cedSCho, Yu-Chen 	u16 wIDIformattedTotalSectors[2];/* 57-58 */
33333842cedSCho, Yu-Chen 	u16 wIDImultiSector;		/* 59 */
33433842cedSCho, Yu-Chen 	u16 wIDIlbaSectors[2];		/* 60-61 */
33533842cedSCho, Yu-Chen 	u16 wIDIsingleWordDMA;		/* 62 */
33633842cedSCho, Yu-Chen 	u16 wIDImultiWordDMA;		/* 63 */
33733842cedSCho, Yu-Chen 	u16 wIDIreserved4[192];		/* 64-255 */
33833842cedSCho, Yu-Chen };
33933842cedSCho, Yu-Chen 
34033842cedSCho, Yu-Chen struct ms_bootblock_sysent_rec {
34133842cedSCho, Yu-Chen 	u32 dwStart;
34233842cedSCho, Yu-Chen 	u32 dwSize;
34333842cedSCho, Yu-Chen 	u8 bType;
34433842cedSCho, Yu-Chen 	u8 bReserved[3];
34533842cedSCho, Yu-Chen };
34633842cedSCho, Yu-Chen 
34733842cedSCho, Yu-Chen struct ms_bootblock_sysent {
34833842cedSCho, Yu-Chen 	struct ms_bootblock_sysent_rec entry[MS_NUMBER_OF_SYSTEM_ENTRY];
34933842cedSCho, Yu-Chen };
35033842cedSCho, Yu-Chen 
35133842cedSCho, Yu-Chen struct ms_bootblock_sysinf {
35233842cedSCho, Yu-Chen 	u8 bMsClass;			/* must be 1 */
35333842cedSCho, Yu-Chen 	u8 bCardType;			/* see below */
35433842cedSCho, Yu-Chen 	u16 wBlockSize;			/* n KB */
35533842cedSCho, Yu-Chen 	u16 wBlockNumber;		/* number of physical block */
35633842cedSCho, Yu-Chen 	u16 wTotalBlockNumber;		/* number of logical block */
35733842cedSCho, Yu-Chen 	u16 wPageSize;			/* must be 0x200 */
35833842cedSCho, Yu-Chen 	u8 bExtraSize;			/* 0x10 */
35933842cedSCho, Yu-Chen 	u8 bSecuritySupport;
36033842cedSCho, Yu-Chen 	u8 bAssemblyDate[8];
36133842cedSCho, Yu-Chen 	u8 bFactoryArea[4];
36233842cedSCho, Yu-Chen 	u8 bAssemblyMakerCode;
36333842cedSCho, Yu-Chen 	u8 bAssemblyMachineCode[3];
36433842cedSCho, Yu-Chen 	u16 wMemoryMakerCode;
36533842cedSCho, Yu-Chen 	u16 wMemoryDeviceCode;
36633842cedSCho, Yu-Chen 	u16 wMemorySize;
36733842cedSCho, Yu-Chen 	u8 bReserved1;
36833842cedSCho, Yu-Chen 	u8 bReserved2;
36933842cedSCho, Yu-Chen 	u8 bVCC;
37033842cedSCho, Yu-Chen 	u8 bVPP;
37133842cedSCho, Yu-Chen 	u16 wControllerChipNumber;
37233842cedSCho, Yu-Chen 	u16 wControllerFunction;	/* New MS */
37333842cedSCho, Yu-Chen 	u8 bReserved3[9];		/* New MS */
37433842cedSCho, Yu-Chen 	u8 bParallelSupport;		/* New MS */
37533842cedSCho, Yu-Chen 	u16 wFormatValue;		/* New MS */
37633842cedSCho, Yu-Chen 	u8 bFormatType;
37733842cedSCho, Yu-Chen 	u8 bUsage;
37833842cedSCho, Yu-Chen 	u8 bDeviceType;
37933842cedSCho, Yu-Chen 	u8 bReserved4[22];
38033842cedSCho, Yu-Chen 	u8 bFUValue3;
38133842cedSCho, Yu-Chen 	u8 bFUValue4;
38233842cedSCho, Yu-Chen 	u8 bReserved5[15];
38333842cedSCho, Yu-Chen };
38433842cedSCho, Yu-Chen 
38533842cedSCho, Yu-Chen struct ms_bootblock_header {
38633842cedSCho, Yu-Chen 	u16 wBlockID;
38733842cedSCho, Yu-Chen 	u16 wFormatVersion;
38833842cedSCho, Yu-Chen 	u8 bReserved1[184];
38933842cedSCho, Yu-Chen 	u8 bNumberOfDataEntry;
39033842cedSCho, Yu-Chen 	u8 bReserved2[179];
39133842cedSCho, Yu-Chen };
39233842cedSCho, Yu-Chen 
39333842cedSCho, Yu-Chen struct ms_bootblock_page0 {
39433842cedSCho, Yu-Chen 	struct ms_bootblock_header header;
39533842cedSCho, Yu-Chen 	struct ms_bootblock_sysent sysent;
39633842cedSCho, Yu-Chen 	struct ms_bootblock_sysinf sysinf;
39733842cedSCho, Yu-Chen };
39833842cedSCho, Yu-Chen 
39933842cedSCho, Yu-Chen struct ms_bootblock_cis_idi {
40033842cedSCho, Yu-Chen 	union {
40133842cedSCho, Yu-Chen 		struct ms_bootblock_cis cis;
40233842cedSCho, Yu-Chen 		u8 dmy[256];
40333842cedSCho, Yu-Chen 	} cis;
40433842cedSCho, Yu-Chen 
40533842cedSCho, Yu-Chen 	union {
40633842cedSCho, Yu-Chen 		struct ms_bootblock_idi idi;
40733842cedSCho, Yu-Chen 		u8 dmy[256];
40833842cedSCho, Yu-Chen 	} idi;
40933842cedSCho, Yu-Chen 
41033842cedSCho, Yu-Chen };
41133842cedSCho, Yu-Chen 
41233842cedSCho, Yu-Chen /* ENE MS Lib struct */
41333842cedSCho, Yu-Chen struct ms_lib_type_extdat {
41433842cedSCho, Yu-Chen 	u8 reserved;
41533842cedSCho, Yu-Chen 	u8 intr;
41633842cedSCho, Yu-Chen 	u8 status0;
41733842cedSCho, Yu-Chen 	u8 status1;
41833842cedSCho, Yu-Chen 	u8 ovrflg;
41933842cedSCho, Yu-Chen 	u8 mngflg;
42033842cedSCho, Yu-Chen 	u16 logadr;
42133842cedSCho, Yu-Chen };
42233842cedSCho, Yu-Chen 
42333842cedSCho, Yu-Chen struct ms_lib_ctrl {
42433842cedSCho, Yu-Chen 	u32 flags;
42533842cedSCho, Yu-Chen 	u32 BytesPerSector;
42633842cedSCho, Yu-Chen 	u32 NumberOfCylinder;
42733842cedSCho, Yu-Chen 	u32 SectorsPerCylinder;
42833842cedSCho, Yu-Chen 	u16 cardType;			/* R/W, RO, Hybrid */
42933842cedSCho, Yu-Chen 	u16 blockSize;
43033842cedSCho, Yu-Chen 	u16 PagesPerBlock;
43133842cedSCho, Yu-Chen 	u16 NumberOfPhyBlock;
43233842cedSCho, Yu-Chen 	u16 NumberOfLogBlock;
43333842cedSCho, Yu-Chen 	u16 NumberOfSegment;
43433842cedSCho, Yu-Chen 	u16 *Phy2LogMap;		/* phy2log table */
43533842cedSCho, Yu-Chen 	u16 *Log2PhyMap;		/* log2phy table */
43633842cedSCho, Yu-Chen 	u16 wrtblk;
43733842cedSCho, Yu-Chen 	unsigned char *pagemap[(MS_MAX_PAGES_PER_BLOCK + (MS_LIB_BITS_PER_BYTE-1)) / MS_LIB_BITS_PER_BYTE];
43833842cedSCho, Yu-Chen 	unsigned char *blkpag;
43933842cedSCho, Yu-Chen 	struct ms_lib_type_extdat *blkext;
44033842cedSCho, Yu-Chen 	unsigned char copybuf[512];
44133842cedSCho, Yu-Chen };
44233842cedSCho, Yu-Chen 
44341e568d1Shuajun li 
44441e568d1Shuajun li /* SD Block Length */
44541e568d1Shuajun li /* 2^9 = 512 Bytes, The HW maximum read/write data length */
44641e568d1Shuajun li #define SD_BLOCK_LEN  9
44741e568d1Shuajun li 
44841e568d1Shuajun li struct ene_ub6250_info {
44941e568d1Shuajun li 	/* for 6250 code */
45041e568d1Shuajun li 	struct SD_STATUS	SD_Status;
45141e568d1Shuajun li 	struct MS_STATUS	MS_Status;
45241e568d1Shuajun li 	struct SM_STATUS	SM_Status;
45341e568d1Shuajun li 
45441e568d1Shuajun li 	/* ----- SD Control Data ---------------- */
45541e568d1Shuajun li 	/*SD_REGISTER SD_Regs; */
45641e568d1Shuajun li 	u16		SD_Block_Mult;
45741e568d1Shuajun li 	u8		SD_READ_BL_LEN;
45841e568d1Shuajun li 	u16		SD_C_SIZE;
45941e568d1Shuajun li 	u8		SD_C_SIZE_MULT;
46041e568d1Shuajun li 
46141e568d1Shuajun li 	/* SD/MMC New spec. */
46241e568d1Shuajun li 	u8		SD_SPEC_VER;
46341e568d1Shuajun li 	u8		SD_CSD_VER;
46441e568d1Shuajun li 	u8		SD20_HIGH_CAPACITY;
46541e568d1Shuajun li 	u32		HC_C_SIZE;
46641e568d1Shuajun li 	u8		MMC_SPEC_VER;
46741e568d1Shuajun li 	u8		MMC_BusWidth;
46841e568d1Shuajun li 	u8		MMC_HIGH_CAPACITY;
46941e568d1Shuajun li 
47041e568d1Shuajun li 	/*----- MS Control Data ---------------- */
47141e568d1Shuajun li 	bool		MS_SWWP;
47241e568d1Shuajun li 	u32		MSP_TotalBlock;
47333842cedSCho, Yu-Chen 	struct ms_lib_ctrl MS_Lib;
47441e568d1Shuajun li 	bool		MS_IsRWPage;
47541e568d1Shuajun li 	u16		MS_Model;
47641e568d1Shuajun li 
47741e568d1Shuajun li 	/*----- SM Control Data ---------------- */
47841e568d1Shuajun li 	u8		SM_DeviceID;
47941e568d1Shuajun li 	u8		SM_CardID;
48041e568d1Shuajun li 
48141e568d1Shuajun li 	unsigned char	*testbuf;
48241e568d1Shuajun li 	u8		BIN_FLAG;
48341e568d1Shuajun li 	u32		bl_num;
48441e568d1Shuajun li 	int		SrbStatus;
48541e568d1Shuajun li 
48641e568d1Shuajun li 	/*------Power Managerment ---------------*/
48741e568d1Shuajun li 	bool		Power_IsResum;
48841e568d1Shuajun li };
48941e568d1Shuajun li 
49041e568d1Shuajun li static int ene_sd_init(struct us_data *us);
49133842cedSCho, Yu-Chen static int ene_ms_init(struct us_data *us);
49241e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag);
49341e568d1Shuajun li 
49441e568d1Shuajun li static void ene_ub6250_info_destructor(void *extra)
49541e568d1Shuajun li {
49641e568d1Shuajun li 	if (!extra)
49741e568d1Shuajun li 		return;
49841e568d1Shuajun li }
49941e568d1Shuajun li 
50041e568d1Shuajun li static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
50141e568d1Shuajun li {
50241e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
50341e568d1Shuajun li 	struct bulk_cs_wrap *bcs = (struct bulk_cs_wrap *) us->iobuf;
50441e568d1Shuajun li 
50541e568d1Shuajun li 	int result;
50641e568d1Shuajun li 	unsigned int residue;
50741e568d1Shuajun li 	unsigned int cswlen = 0, partial = 0;
50841e568d1Shuajun li 	unsigned int transfer_length = bcb->DataTransferLength;
50941e568d1Shuajun li 
510191648d0SJoe Perches 	/* usb_stor_dbg(us, "transport --- ene_send_scsi_cmd\n"); */
51141e568d1Shuajun li 	/* send cmd to out endpoint */
51241e568d1Shuajun li 	result = usb_stor_bulk_transfer_buf(us, us->send_bulk_pipe,
51341e568d1Shuajun li 					    bcb, US_BULK_CB_WRAP_LEN, NULL);
51441e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
515191648d0SJoe Perches 		usb_stor_dbg(us, "send cmd to out endpoint fail ---\n");
51641e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
51741e568d1Shuajun li 	}
51841e568d1Shuajun li 
51941e568d1Shuajun li 	if (buf) {
52041e568d1Shuajun li 		unsigned int pipe = fDir;
52141e568d1Shuajun li 
52241e568d1Shuajun li 		if (fDir  == FDIR_READ)
52341e568d1Shuajun li 			pipe = us->recv_bulk_pipe;
52441e568d1Shuajun li 		else
52541e568d1Shuajun li 			pipe = us->send_bulk_pipe;
52641e568d1Shuajun li 
52741e568d1Shuajun li 		/* Bulk */
52841e568d1Shuajun li 		if (use_sg) {
52941e568d1Shuajun li 			result = usb_stor_bulk_srb(us, pipe, us->srb);
53041e568d1Shuajun li 		} else {
53141e568d1Shuajun li 			result = usb_stor_bulk_transfer_sg(us, pipe, buf,
53241e568d1Shuajun li 						transfer_length, 0, &partial);
53341e568d1Shuajun li 		}
53441e568d1Shuajun li 		if (result != USB_STOR_XFER_GOOD) {
535191648d0SJoe Perches 			usb_stor_dbg(us, "data transfer fail ---\n");
53641e568d1Shuajun li 			return USB_STOR_TRANSPORT_ERROR;
53741e568d1Shuajun li 		}
53841e568d1Shuajun li 	}
53941e568d1Shuajun li 
54041e568d1Shuajun li 	/* Get CSW for device status */
54141e568d1Shuajun li 	result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe, bcs,
54241e568d1Shuajun li 					    US_BULK_CS_WRAP_LEN, &cswlen);
54341e568d1Shuajun li 
54441e568d1Shuajun li 	if (result == USB_STOR_XFER_SHORT && cswlen == 0) {
545191648d0SJoe Perches 		usb_stor_dbg(us, "Received 0-length CSW; retrying...\n");
54641e568d1Shuajun li 		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
54741e568d1Shuajun li 					    bcs, US_BULK_CS_WRAP_LEN, &cswlen);
54841e568d1Shuajun li 	}
54941e568d1Shuajun li 
55041e568d1Shuajun li 	if (result == USB_STOR_XFER_STALLED) {
55141e568d1Shuajun li 		/* get the status again */
552191648d0SJoe Perches 		usb_stor_dbg(us, "Attempting to get CSW (2nd try)...\n");
55341e568d1Shuajun li 		result = usb_stor_bulk_transfer_buf(us, us->recv_bulk_pipe,
55441e568d1Shuajun li 						bcs, US_BULK_CS_WRAP_LEN, NULL);
55541e568d1Shuajun li 	}
55641e568d1Shuajun li 
55741e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD)
55841e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
55941e568d1Shuajun li 
56041e568d1Shuajun li 	/* check bulk status */
56141e568d1Shuajun li 	residue = le32_to_cpu(bcs->Residue);
56241e568d1Shuajun li 
563f0183a33SFelipe Balbi 	/*
564f0183a33SFelipe Balbi 	 * try to compute the actual residue, based on how much data
565f0183a33SFelipe Balbi 	 * was really transferred and what the device tells us
566f0183a33SFelipe Balbi 	 */
56741e568d1Shuajun li 	if (residue && !(us->fflags & US_FL_IGNORE_RESIDUE)) {
56841e568d1Shuajun li 		residue = min(residue, transfer_length);
56941e568d1Shuajun li 		if (us->srb != NULL)
57041e568d1Shuajun li 			scsi_set_resid(us->srb, max(scsi_get_resid(us->srb),
57141e568d1Shuajun li 								(int)residue));
57241e568d1Shuajun li 	}
57341e568d1Shuajun li 
57441e568d1Shuajun li 	if (bcs->Status != US_BULK_STAT_OK)
57541e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
57641e568d1Shuajun li 
57741e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
57841e568d1Shuajun li }
57941e568d1Shuajun li 
58041e568d1Shuajun li static int sd_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
58141e568d1Shuajun li {
58241e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
58341e568d1Shuajun li 
58441e568d1Shuajun li 	if (info->SD_Status.Insert && info->SD_Status.Ready)
58541e568d1Shuajun li 		return USB_STOR_TRANSPORT_GOOD;
58641e568d1Shuajun li 	else {
58741e568d1Shuajun li 		ene_sd_init(us);
58841e568d1Shuajun li 		return USB_STOR_TRANSPORT_GOOD;
58941e568d1Shuajun li 	}
59041e568d1Shuajun li 
59141e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
59241e568d1Shuajun li }
59341e568d1Shuajun li 
59441e568d1Shuajun li static int sd_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
59541e568d1Shuajun li {
59641e568d1Shuajun li 	unsigned char data_ptr[36] = {
59741e568d1Shuajun li 		0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
59841e568d1Shuajun li 		0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
59941e568d1Shuajun li 		0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
60041e568d1Shuajun li 		0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30 };
60141e568d1Shuajun li 
60241e568d1Shuajun li 	usb_stor_set_xfer_buf(data_ptr, 36, srb);
60341e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
60441e568d1Shuajun li }
60541e568d1Shuajun li 
60641e568d1Shuajun li static int sd_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
60741e568d1Shuajun li {
60841e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
60941e568d1Shuajun li 	unsigned char mediaNoWP[12] = {
61041e568d1Shuajun li 		0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
61141e568d1Shuajun li 		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
61241e568d1Shuajun li 	unsigned char mediaWP[12]   = {
61341e568d1Shuajun li 		0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
61441e568d1Shuajun li 		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
61541e568d1Shuajun li 
61641e568d1Shuajun li 	if (info->SD_Status.WtP)
61741e568d1Shuajun li 		usb_stor_set_xfer_buf(mediaWP, 12, srb);
61841e568d1Shuajun li 	else
61941e568d1Shuajun li 		usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
62041e568d1Shuajun li 
62141e568d1Shuajun li 
62241e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
62341e568d1Shuajun li }
62441e568d1Shuajun li 
62541e568d1Shuajun li static int sd_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
62641e568d1Shuajun li {
62741e568d1Shuajun li 	u32	bl_num;
62836f3a14dSFelipe Balbi 	u32	bl_len;
62941e568d1Shuajun li 	unsigned int offset = 0;
63041e568d1Shuajun li 	unsigned char    buf[8];
63141e568d1Shuajun li 	struct scatterlist *sg = NULL;
63241e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
63341e568d1Shuajun li 
634191648d0SJoe Perches 	usb_stor_dbg(us, "sd_scsi_read_capacity\n");
63541e568d1Shuajun li 	if (info->SD_Status.HiCapacity) {
63641e568d1Shuajun li 		bl_len = 0x200;
63741e568d1Shuajun li 		if (info->SD_Status.IsMMC)
63841e568d1Shuajun li 			bl_num = info->HC_C_SIZE-1;
63941e568d1Shuajun li 		else
64041e568d1Shuajun li 			bl_num = (info->HC_C_SIZE + 1) * 1024 - 1;
64141e568d1Shuajun li 	} else {
64241e568d1Shuajun li 		bl_len = 1 << (info->SD_READ_BL_LEN);
64341e568d1Shuajun li 		bl_num = info->SD_Block_Mult * (info->SD_C_SIZE + 1)
64441e568d1Shuajun li 				* (1 << (info->SD_C_SIZE_MULT + 2)) - 1;
64541e568d1Shuajun li 	}
64641e568d1Shuajun li 	info->bl_num = bl_num;
647191648d0SJoe Perches 	usb_stor_dbg(us, "bl_len = %x\n", bl_len);
648191648d0SJoe Perches 	usb_stor_dbg(us, "bl_num = %x\n", bl_num);
64941e568d1Shuajun li 
65041e568d1Shuajun li 	/*srb->request_bufflen = 8; */
65141e568d1Shuajun li 	buf[0] = (bl_num >> 24) & 0xff;
65241e568d1Shuajun li 	buf[1] = (bl_num >> 16) & 0xff;
65341e568d1Shuajun li 	buf[2] = (bl_num >> 8) & 0xff;
65441e568d1Shuajun li 	buf[3] = (bl_num >> 0) & 0xff;
65541e568d1Shuajun li 	buf[4] = (bl_len >> 24) & 0xff;
65641e568d1Shuajun li 	buf[5] = (bl_len >> 16) & 0xff;
65741e568d1Shuajun li 	buf[6] = (bl_len >> 8) & 0xff;
65841e568d1Shuajun li 	buf[7] = (bl_len >> 0) & 0xff;
65941e568d1Shuajun li 
66041e568d1Shuajun li 	usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
66141e568d1Shuajun li 
66241e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
66341e568d1Shuajun li }
66441e568d1Shuajun li 
66541e568d1Shuajun li static int sd_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
66641e568d1Shuajun li {
66741e568d1Shuajun li 	int result;
66841e568d1Shuajun li 	unsigned char *cdb = srb->cmnd;
66941e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
67041e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
67141e568d1Shuajun li 
67241e568d1Shuajun li 	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
67341e568d1Shuajun li 		 ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
67441e568d1Shuajun li 	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
67541e568d1Shuajun li 	u32 bnByte = bn * 0x200;
67641e568d1Shuajun li 	u32 blenByte = blen * 0x200;
67741e568d1Shuajun li 
67841e568d1Shuajun li 	if (bn > info->bl_num)
67941e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
68041e568d1Shuajun li 
68141e568d1Shuajun li 	result = ene_load_bincode(us, SD_RW_PATTERN);
68241e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
683191648d0SJoe Perches 		usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
68441e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
68541e568d1Shuajun li 	}
68641e568d1Shuajun li 
68741e568d1Shuajun li 	if (info->SD_Status.HiCapacity)
68841e568d1Shuajun li 		bnByte = bn;
68941e568d1Shuajun li 
69041e568d1Shuajun li 	/* set up the command wrapper */
69141e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
69241e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
69341e568d1Shuajun li 	bcb->DataTransferLength = blenByte;
694b8db6d64SSebastian Andrzej Siewior 	bcb->Flags  = US_BULK_FLAG_IN;
69541e568d1Shuajun li 	bcb->CDB[0] = 0xF1;
69641e568d1Shuajun li 	bcb->CDB[5] = (unsigned char)(bnByte);
69741e568d1Shuajun li 	bcb->CDB[4] = (unsigned char)(bnByte>>8);
69841e568d1Shuajun li 	bcb->CDB[3] = (unsigned char)(bnByte>>16);
69941e568d1Shuajun li 	bcb->CDB[2] = (unsigned char)(bnByte>>24);
70041e568d1Shuajun li 
70141e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
70241e568d1Shuajun li 	return result;
70341e568d1Shuajun li }
70441e568d1Shuajun li 
70541e568d1Shuajun li static int sd_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
70641e568d1Shuajun li {
70741e568d1Shuajun li 	int result;
70841e568d1Shuajun li 	unsigned char *cdb = srb->cmnd;
70941e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
71041e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
71141e568d1Shuajun li 
71241e568d1Shuajun li 	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
71341e568d1Shuajun li 		 ((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
71441e568d1Shuajun li 	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
71541e568d1Shuajun li 	u32 bnByte = bn * 0x200;
71641e568d1Shuajun li 	u32 blenByte = blen * 0x200;
71741e568d1Shuajun li 
71841e568d1Shuajun li 	if (bn > info->bl_num)
71941e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
72041e568d1Shuajun li 
72141e568d1Shuajun li 	result = ene_load_bincode(us, SD_RW_PATTERN);
72241e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
723191648d0SJoe Perches 		usb_stor_dbg(us, "Load SD RW pattern Fail !!\n");
72441e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
72541e568d1Shuajun li 	}
72641e568d1Shuajun li 
72741e568d1Shuajun li 	if (info->SD_Status.HiCapacity)
72841e568d1Shuajun li 		bnByte = bn;
72941e568d1Shuajun li 
73041e568d1Shuajun li 	/* set up the command wrapper */
73141e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
73241e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
73341e568d1Shuajun li 	bcb->DataTransferLength = blenByte;
73441e568d1Shuajun li 	bcb->Flags  = 0x00;
73541e568d1Shuajun li 	bcb->CDB[0] = 0xF0;
73641e568d1Shuajun li 	bcb->CDB[5] = (unsigned char)(bnByte);
73741e568d1Shuajun li 	bcb->CDB[4] = (unsigned char)(bnByte>>8);
73841e568d1Shuajun li 	bcb->CDB[3] = (unsigned char)(bnByte>>16);
73941e568d1Shuajun li 	bcb->CDB[2] = (unsigned char)(bnByte>>24);
74041e568d1Shuajun li 
74141e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
74241e568d1Shuajun li 	return result;
74341e568d1Shuajun li }
74441e568d1Shuajun li 
74533842cedSCho, Yu-Chen /*
74633842cedSCho, Yu-Chen  * ENE MS Card
74733842cedSCho, Yu-Chen  */
74833842cedSCho, Yu-Chen 
74933842cedSCho, Yu-Chen static int ms_lib_set_logicalpair(struct us_data *us, u16 logblk, u16 phyblk)
75033842cedSCho, Yu-Chen {
75133842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
75233842cedSCho, Yu-Chen 
75333842cedSCho, Yu-Chen 	if ((logblk >= info->MS_Lib.NumberOfLogBlock) || (phyblk >= info->MS_Lib.NumberOfPhyBlock))
75433842cedSCho, Yu-Chen 		return (u32)-1;
75533842cedSCho, Yu-Chen 
75633842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap[phyblk] = logblk;
75733842cedSCho, Yu-Chen 	info->MS_Lib.Log2PhyMap[logblk] = phyblk;
75833842cedSCho, Yu-Chen 
75933842cedSCho, Yu-Chen 	return 0;
76033842cedSCho, Yu-Chen }
76133842cedSCho, Yu-Chen 
76233842cedSCho, Yu-Chen static int ms_lib_set_logicalblockmark(struct us_data *us, u16 phyblk, u16 mark)
76333842cedSCho, Yu-Chen {
76433842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
76533842cedSCho, Yu-Chen 
76633842cedSCho, Yu-Chen 	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
76733842cedSCho, Yu-Chen 		return (u32)-1;
76833842cedSCho, Yu-Chen 
76933842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap[phyblk] = mark;
77033842cedSCho, Yu-Chen 
77133842cedSCho, Yu-Chen 	return 0;
77233842cedSCho, Yu-Chen }
77333842cedSCho, Yu-Chen 
77433842cedSCho, Yu-Chen static int ms_lib_set_initialerrorblock(struct us_data *us, u16 phyblk)
77533842cedSCho, Yu-Chen {
77633842cedSCho, Yu-Chen 	return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_INITIAL_ERROR);
77733842cedSCho, Yu-Chen }
77833842cedSCho, Yu-Chen 
77933842cedSCho, Yu-Chen static int ms_lib_set_bootblockmark(struct us_data *us, u16 phyblk)
78033842cedSCho, Yu-Chen {
78133842cedSCho, Yu-Chen 	return ms_lib_set_logicalblockmark(us, phyblk, MS_LB_BOOT_BLOCK);
78233842cedSCho, Yu-Chen }
78333842cedSCho, Yu-Chen 
78433842cedSCho, Yu-Chen static int ms_lib_free_logicalmap(struct us_data *us)
78533842cedSCho, Yu-Chen {
78633842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
78733842cedSCho, Yu-Chen 
78833842cedSCho, Yu-Chen 	kfree(info->MS_Lib.Phy2LogMap);
78933842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap = NULL;
79033842cedSCho, Yu-Chen 
79133842cedSCho, Yu-Chen 	kfree(info->MS_Lib.Log2PhyMap);
79233842cedSCho, Yu-Chen 	info->MS_Lib.Log2PhyMap = NULL;
79333842cedSCho, Yu-Chen 
79433842cedSCho, Yu-Chen 	return 0;
79533842cedSCho, Yu-Chen }
79633842cedSCho, Yu-Chen 
79736f3a14dSFelipe Balbi static int ms_lib_alloc_logicalmap(struct us_data *us)
79833842cedSCho, Yu-Chen {
79933842cedSCho, Yu-Chen 	u32  i;
80033842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
80133842cedSCho, Yu-Chen 
80233842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap = kmalloc(info->MS_Lib.NumberOfPhyBlock * sizeof(u16), GFP_KERNEL);
80333842cedSCho, Yu-Chen 	info->MS_Lib.Log2PhyMap = kmalloc(info->MS_Lib.NumberOfLogBlock * sizeof(u16), GFP_KERNEL);
80433842cedSCho, Yu-Chen 
80533842cedSCho, Yu-Chen 	if ((info->MS_Lib.Phy2LogMap == NULL) || (info->MS_Lib.Log2PhyMap == NULL)) {
80633842cedSCho, Yu-Chen 		ms_lib_free_logicalmap(us);
80733842cedSCho, Yu-Chen 		return (u32)-1;
80833842cedSCho, Yu-Chen 	}
80933842cedSCho, Yu-Chen 
81033842cedSCho, Yu-Chen 	for (i = 0; i < info->MS_Lib.NumberOfPhyBlock; i++)
81133842cedSCho, Yu-Chen 		info->MS_Lib.Phy2LogMap[i] = MS_LB_NOT_USED;
81233842cedSCho, Yu-Chen 
81333842cedSCho, Yu-Chen 	for (i = 0; i < info->MS_Lib.NumberOfLogBlock; i++)
81433842cedSCho, Yu-Chen 		info->MS_Lib.Log2PhyMap[i] = MS_LB_NOT_USED;
81533842cedSCho, Yu-Chen 
81633842cedSCho, Yu-Chen 	return 0;
81733842cedSCho, Yu-Chen }
81833842cedSCho, Yu-Chen 
81933842cedSCho, Yu-Chen static void ms_lib_clear_writebuf(struct us_data *us)
82033842cedSCho, Yu-Chen {
82133842cedSCho, Yu-Chen 	int i;
82233842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
82333842cedSCho, Yu-Chen 
82433842cedSCho, Yu-Chen 	info->MS_Lib.wrtblk = (u16)-1;
82533842cedSCho, Yu-Chen 	ms_lib_clear_pagemap(info);
82633842cedSCho, Yu-Chen 
82733842cedSCho, Yu-Chen 	if (info->MS_Lib.blkpag)
82833842cedSCho, Yu-Chen 		memset(info->MS_Lib.blkpag, 0xff, info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector);
82933842cedSCho, Yu-Chen 
83033842cedSCho, Yu-Chen 	if (info->MS_Lib.blkext) {
83133842cedSCho, Yu-Chen 		for (i = 0; i < info->MS_Lib.PagesPerBlock; i++) {
83233842cedSCho, Yu-Chen 			info->MS_Lib.blkext[i].status1 = MS_REG_ST1_DEFAULT;
83333842cedSCho, Yu-Chen 			info->MS_Lib.blkext[i].ovrflg = MS_REG_OVR_DEFAULT;
83433842cedSCho, Yu-Chen 			info->MS_Lib.blkext[i].mngflg = MS_REG_MNG_DEFAULT;
83533842cedSCho, Yu-Chen 			info->MS_Lib.blkext[i].logadr = MS_LB_NOT_USED;
83633842cedSCho, Yu-Chen 		}
83733842cedSCho, Yu-Chen 	}
83833842cedSCho, Yu-Chen }
83933842cedSCho, Yu-Chen 
84033842cedSCho, Yu-Chen static int ms_count_freeblock(struct us_data *us, u16 PhyBlock)
84133842cedSCho, Yu-Chen {
84233842cedSCho, Yu-Chen 	u32 Ende, Count;
84333842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
84433842cedSCho, Yu-Chen 
84533842cedSCho, Yu-Chen 	Ende = PhyBlock + MS_PHYSICAL_BLOCKS_PER_SEGMENT;
84633842cedSCho, Yu-Chen 	for (Count = 0; PhyBlock < Ende; PhyBlock++) {
84733842cedSCho, Yu-Chen 		switch (info->MS_Lib.Phy2LogMap[PhyBlock]) {
84833842cedSCho, Yu-Chen 		case MS_LB_NOT_USED:
84933842cedSCho, Yu-Chen 		case MS_LB_NOT_USED_ERASED:
85033842cedSCho, Yu-Chen 			Count++;
85133842cedSCho, Yu-Chen 		default:
85233842cedSCho, Yu-Chen 			break;
85333842cedSCho, Yu-Chen 		}
85433842cedSCho, Yu-Chen 	}
85533842cedSCho, Yu-Chen 
85633842cedSCho, Yu-Chen 	return Count;
85733842cedSCho, Yu-Chen }
85833842cedSCho, Yu-Chen 
85933842cedSCho, Yu-Chen static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
86033842cedSCho, Yu-Chen 		u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
86133842cedSCho, Yu-Chen {
86233842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
86333842cedSCho, Yu-Chen 	int result;
86433842cedSCho, Yu-Chen 	u8 ExtBuf[4];
86533842cedSCho, Yu-Chen 	u32 bn = PhyBlockAddr * 0x20 + PageNum;
86633842cedSCho, Yu-Chen 
86733842cedSCho, Yu-Chen 	result = ene_load_bincode(us, MS_RW_PATTERN);
86833842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
86933842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
87033842cedSCho, Yu-Chen 
87133842cedSCho, Yu-Chen 	/* Read Page Data */
87233842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
87333842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
87433842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x200;
875b8db6d64SSebastian Andrzej Siewior 	bcb->Flags      = US_BULK_FLAG_IN;
87633842cedSCho, Yu-Chen 	bcb->CDB[0]     = 0xF1;
87733842cedSCho, Yu-Chen 
87833842cedSCho, Yu-Chen 	bcb->CDB[1]     = 0x02; /* in init.c ENE_MSInit() is 0x01 */
87933842cedSCho, Yu-Chen 
88033842cedSCho, Yu-Chen 	bcb->CDB[5]     = (unsigned char)(bn);
88133842cedSCho, Yu-Chen 	bcb->CDB[4]     = (unsigned char)(bn>>8);
88233842cedSCho, Yu-Chen 	bcb->CDB[3]     = (unsigned char)(bn>>16);
88333842cedSCho, Yu-Chen 	bcb->CDB[2]     = (unsigned char)(bn>>24);
88433842cedSCho, Yu-Chen 
88533842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, PageBuf, 0);
88633842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
88733842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
88833842cedSCho, Yu-Chen 
88933842cedSCho, Yu-Chen 
89033842cedSCho, Yu-Chen 	/* Read Extra Data */
89133842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
89233842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
89333842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x4;
894b8db6d64SSebastian Andrzej Siewior 	bcb->Flags      = US_BULK_FLAG_IN;
89533842cedSCho, Yu-Chen 	bcb->CDB[0]     = 0xF1;
89633842cedSCho, Yu-Chen 	bcb->CDB[1]     = 0x03;
89733842cedSCho, Yu-Chen 
89833842cedSCho, Yu-Chen 	bcb->CDB[5]     = (unsigned char)(PageNum);
89933842cedSCho, Yu-Chen 	bcb->CDB[4]     = (unsigned char)(PhyBlockAddr);
90033842cedSCho, Yu-Chen 	bcb->CDB[3]     = (unsigned char)(PhyBlockAddr>>8);
90133842cedSCho, Yu-Chen 	bcb->CDB[2]     = (unsigned char)(PhyBlockAddr>>16);
90233842cedSCho, Yu-Chen 	bcb->CDB[6]     = 0x01;
90333842cedSCho, Yu-Chen 
90433842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
90533842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
90633842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
90733842cedSCho, Yu-Chen 
90833842cedSCho, Yu-Chen 	ExtraDat->reserved = 0;
90933842cedSCho, Yu-Chen 	ExtraDat->intr     = 0x80;  /* Not yet,fireware support */
91033842cedSCho, Yu-Chen 	ExtraDat->status0  = 0x10;  /* Not yet,fireware support */
91133842cedSCho, Yu-Chen 
91233842cedSCho, Yu-Chen 	ExtraDat->status1  = 0x00;  /* Not yet,fireware support */
91333842cedSCho, Yu-Chen 	ExtraDat->ovrflg   = ExtBuf[0];
91433842cedSCho, Yu-Chen 	ExtraDat->mngflg   = ExtBuf[1];
91533842cedSCho, Yu-Chen 	ExtraDat->logadr   = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
91633842cedSCho, Yu-Chen 
91733842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
91833842cedSCho, Yu-Chen }
91933842cedSCho, Yu-Chen 
92033842cedSCho, Yu-Chen static int ms_lib_process_bootblock(struct us_data *us, u16 PhyBlock, u8 *PageData)
92133842cedSCho, Yu-Chen {
92233842cedSCho, Yu-Chen 	struct ms_bootblock_sysent *SysEntry;
92333842cedSCho, Yu-Chen 	struct ms_bootblock_sysinf *SysInfo;
92433842cedSCho, Yu-Chen 	u32 i, result;
92533842cedSCho, Yu-Chen 	u8 PageNumber;
92633842cedSCho, Yu-Chen 	u8 *PageBuffer;
92733842cedSCho, Yu-Chen 	struct ms_lib_type_extdat ExtraData;
92833842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
92933842cedSCho, Yu-Chen 
93033842cedSCho, Yu-Chen 	PageBuffer = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
93133842cedSCho, Yu-Chen 	if (PageBuffer == NULL)
93233842cedSCho, Yu-Chen 		return (u32)-1;
93333842cedSCho, Yu-Chen 
93433842cedSCho, Yu-Chen 	result = (u32)-1;
93533842cedSCho, Yu-Chen 
93633842cedSCho, Yu-Chen 	SysInfo = &(((struct ms_bootblock_page0 *)PageData)->sysinf);
93733842cedSCho, Yu-Chen 
93833842cedSCho, Yu-Chen 	if ((SysInfo->bMsClass != MS_SYSINF_MSCLASS_TYPE_1) ||
93933842cedSCho, Yu-Chen 		(be16_to_cpu(SysInfo->wPageSize) != MS_SYSINF_PAGE_SIZE) ||
94033842cedSCho, Yu-Chen 		((SysInfo->bSecuritySupport & MS_SYSINF_SECURITY) == MS_SYSINF_SECURITY_SUPPORT) ||
94133842cedSCho, Yu-Chen 		(SysInfo->bReserved1 != MS_SYSINF_RESERVED1) ||
94233842cedSCho, Yu-Chen 		(SysInfo->bReserved2 != MS_SYSINF_RESERVED2) ||
94333842cedSCho, Yu-Chen 		(SysInfo->bFormatType != MS_SYSINF_FORMAT_FAT) ||
94433842cedSCho, Yu-Chen 		(SysInfo->bUsage != MS_SYSINF_USAGE_GENERAL))
94533842cedSCho, Yu-Chen 		goto exit;
94633842cedSCho, Yu-Chen 		/* */
94733842cedSCho, Yu-Chen 	switch (info->MS_Lib.cardType = SysInfo->bCardType) {
94833842cedSCho, Yu-Chen 	case MS_SYSINF_CARDTYPE_RDONLY:
94933842cedSCho, Yu-Chen 		ms_lib_ctrl_set(info, MS_LIB_CTRL_RDONLY);
95033842cedSCho, Yu-Chen 		break;
95133842cedSCho, Yu-Chen 	case MS_SYSINF_CARDTYPE_RDWR:
95233842cedSCho, Yu-Chen 		ms_lib_ctrl_reset(info, MS_LIB_CTRL_RDONLY);
95333842cedSCho, Yu-Chen 		break;
95433842cedSCho, Yu-Chen 	case MS_SYSINF_CARDTYPE_HYBRID:
95533842cedSCho, Yu-Chen 	default:
95633842cedSCho, Yu-Chen 		goto exit;
95733842cedSCho, Yu-Chen 	}
95833842cedSCho, Yu-Chen 
95933842cedSCho, Yu-Chen 	info->MS_Lib.blockSize = be16_to_cpu(SysInfo->wBlockSize);
96033842cedSCho, Yu-Chen 	info->MS_Lib.NumberOfPhyBlock = be16_to_cpu(SysInfo->wBlockNumber);
96133842cedSCho, Yu-Chen 	info->MS_Lib.NumberOfLogBlock = be16_to_cpu(SysInfo->wTotalBlockNumber)-2;
96233842cedSCho, Yu-Chen 	info->MS_Lib.PagesPerBlock = info->MS_Lib.blockSize * SIZE_OF_KIRO / MS_BYTES_PER_PAGE;
96333842cedSCho, Yu-Chen 	info->MS_Lib.NumberOfSegment = info->MS_Lib.NumberOfPhyBlock / MS_PHYSICAL_BLOCKS_PER_SEGMENT;
96433842cedSCho, Yu-Chen 	info->MS_Model = be16_to_cpu(SysInfo->wMemorySize);
96533842cedSCho, Yu-Chen 
96633842cedSCho, Yu-Chen 	/*Allocate to all number of logicalblock and physicalblock */
96733842cedSCho, Yu-Chen 	if (ms_lib_alloc_logicalmap(us))
96833842cedSCho, Yu-Chen 		goto exit;
96933842cedSCho, Yu-Chen 
97033842cedSCho, Yu-Chen 	/* Mark the book block */
97133842cedSCho, Yu-Chen 	ms_lib_set_bootblockmark(us, PhyBlock);
97233842cedSCho, Yu-Chen 
97333842cedSCho, Yu-Chen 	SysEntry = &(((struct ms_bootblock_page0 *)PageData)->sysent);
97433842cedSCho, Yu-Chen 
97533842cedSCho, Yu-Chen 	for (i = 0; i < MS_NUMBER_OF_SYSTEM_ENTRY; i++) {
97633842cedSCho, Yu-Chen 		u32  EntryOffset, EntrySize;
97733842cedSCho, Yu-Chen 
97833842cedSCho, Yu-Chen 		EntryOffset = be32_to_cpu(SysEntry->entry[i].dwStart);
97933842cedSCho, Yu-Chen 
98033842cedSCho, Yu-Chen 		if (EntryOffset == 0xffffff)
98133842cedSCho, Yu-Chen 			continue;
98233842cedSCho, Yu-Chen 		EntrySize = be32_to_cpu(SysEntry->entry[i].dwSize);
98333842cedSCho, Yu-Chen 
98433842cedSCho, Yu-Chen 		if (EntrySize == 0)
98533842cedSCho, Yu-Chen 			continue;
98633842cedSCho, Yu-Chen 
98733842cedSCho, Yu-Chen 		if (EntryOffset + MS_BYTES_PER_PAGE + EntrySize > info->MS_Lib.blockSize * (u32)SIZE_OF_KIRO)
98833842cedSCho, Yu-Chen 			continue;
98933842cedSCho, Yu-Chen 
99033842cedSCho, Yu-Chen 		if (i == 0) {
99133842cedSCho, Yu-Chen 			u8 PrevPageNumber = 0;
99233842cedSCho, Yu-Chen 			u16 phyblk;
99333842cedSCho, Yu-Chen 
99433842cedSCho, Yu-Chen 			if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_INVALID_BLOCK)
99533842cedSCho, Yu-Chen 				goto exit;
99633842cedSCho, Yu-Chen 
99733842cedSCho, Yu-Chen 			while (EntrySize > 0) {
99833842cedSCho, Yu-Chen 
99933842cedSCho, Yu-Chen 				PageNumber = (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1);
100033842cedSCho, Yu-Chen 				if (PageNumber != PrevPageNumber) {
100133842cedSCho, Yu-Chen 					switch (ms_read_readpage(us, PhyBlock, PageNumber, (u32 *)PageBuffer, &ExtraData)) {
100233842cedSCho, Yu-Chen 					case MS_STATUS_SUCCESS:
100333842cedSCho, Yu-Chen 						break;
100433842cedSCho, Yu-Chen 					case MS_STATUS_WRITE_PROTECT:
100533842cedSCho, Yu-Chen 					case MS_ERROR_FLASH_READ:
100633842cedSCho, Yu-Chen 					case MS_STATUS_ERROR:
100733842cedSCho, Yu-Chen 					default:
100833842cedSCho, Yu-Chen 						goto exit;
100933842cedSCho, Yu-Chen 					}
101033842cedSCho, Yu-Chen 
101133842cedSCho, Yu-Chen 					PrevPageNumber = PageNumber;
101233842cedSCho, Yu-Chen 				}
101333842cedSCho, Yu-Chen 
101433842cedSCho, Yu-Chen 				phyblk = be16_to_cpu(*(u16 *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)));
101533842cedSCho, Yu-Chen 				if (phyblk < 0x0fff)
101633842cedSCho, Yu-Chen 					ms_lib_set_initialerrorblock(us, phyblk);
101733842cedSCho, Yu-Chen 
101833842cedSCho, Yu-Chen 				EntryOffset += 2;
101933842cedSCho, Yu-Chen 				EntrySize -= 2;
102033842cedSCho, Yu-Chen 			}
102133842cedSCho, Yu-Chen 		} else if (i == 1) {  /* CIS/IDI */
102233842cedSCho, Yu-Chen 			struct ms_bootblock_idi *idi;
102333842cedSCho, Yu-Chen 
102433842cedSCho, Yu-Chen 			if (SysEntry->entry[i].bType != MS_SYSENT_TYPE_CIS_IDI)
102533842cedSCho, Yu-Chen 				goto exit;
102633842cedSCho, Yu-Chen 
102733842cedSCho, Yu-Chen 			switch (ms_read_readpage(us, PhyBlock, (u8)(EntryOffset / MS_BYTES_PER_PAGE + 1), (u32 *)PageBuffer, &ExtraData)) {
102833842cedSCho, Yu-Chen 			case MS_STATUS_SUCCESS:
102933842cedSCho, Yu-Chen 				break;
103033842cedSCho, Yu-Chen 			case MS_STATUS_WRITE_PROTECT:
103133842cedSCho, Yu-Chen 			case MS_ERROR_FLASH_READ:
103233842cedSCho, Yu-Chen 			case MS_STATUS_ERROR:
103333842cedSCho, Yu-Chen 			default:
103433842cedSCho, Yu-Chen 				goto exit;
103533842cedSCho, Yu-Chen 			}
103633842cedSCho, Yu-Chen 
103733842cedSCho, Yu-Chen 			idi = &((struct ms_bootblock_cis_idi *)(PageBuffer + (EntryOffset % MS_BYTES_PER_PAGE)))->idi.idi;
103833842cedSCho, Yu-Chen 			if (le16_to_cpu(idi->wIDIgeneralConfiguration) != MS_IDI_GENERAL_CONF)
103933842cedSCho, Yu-Chen 				goto exit;
104033842cedSCho, Yu-Chen 
104133842cedSCho, Yu-Chen 			info->MS_Lib.BytesPerSector = le16_to_cpu(idi->wIDIbytesPerSector);
104233842cedSCho, Yu-Chen 			if (info->MS_Lib.BytesPerSector != MS_BYTES_PER_PAGE)
104333842cedSCho, Yu-Chen 				goto exit;
104433842cedSCho, Yu-Chen 		}
104533842cedSCho, Yu-Chen 	} /* End for .. */
104633842cedSCho, Yu-Chen 
104733842cedSCho, Yu-Chen 	result = 0;
104833842cedSCho, Yu-Chen 
104933842cedSCho, Yu-Chen exit:
105033842cedSCho, Yu-Chen 	if (result)
105133842cedSCho, Yu-Chen 		ms_lib_free_logicalmap(us);
105233842cedSCho, Yu-Chen 
105333842cedSCho, Yu-Chen 	kfree(PageBuffer);
105433842cedSCho, Yu-Chen 
105533842cedSCho, Yu-Chen 	result = 0;
105633842cedSCho, Yu-Chen 	return result;
105733842cedSCho, Yu-Chen }
105833842cedSCho, Yu-Chen 
105933842cedSCho, Yu-Chen static void ms_lib_free_writebuf(struct us_data *us)
106033842cedSCho, Yu-Chen {
106133842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
106233842cedSCho, Yu-Chen 	info->MS_Lib.wrtblk = (u16)-1; /* set to -1 */
106333842cedSCho, Yu-Chen 
106433842cedSCho, Yu-Chen 	/* memset((fdoExt)->MS_Lib.pagemap, 0, sizeof((fdoExt)->MS_Lib.pagemap)) */
106533842cedSCho, Yu-Chen 
106633842cedSCho, Yu-Chen 	ms_lib_clear_pagemap(info); /* (pdx)->MS_Lib.pagemap memset 0 in ms.h */
106733842cedSCho, Yu-Chen 
106833842cedSCho, Yu-Chen 	if (info->MS_Lib.blkpag) {
1069e6533e87SAmitoj Kaur Chawla 		kfree(info->MS_Lib.blkpag);  /* Arnold test ... */
107033842cedSCho, Yu-Chen 		info->MS_Lib.blkpag = NULL;
107133842cedSCho, Yu-Chen 	}
107233842cedSCho, Yu-Chen 
107333842cedSCho, Yu-Chen 	if (info->MS_Lib.blkext) {
1074e6533e87SAmitoj Kaur Chawla 		kfree(info->MS_Lib.blkext);  /* Arnold test ... */
107533842cedSCho, Yu-Chen 		info->MS_Lib.blkext = NULL;
107633842cedSCho, Yu-Chen 	}
107733842cedSCho, Yu-Chen }
107833842cedSCho, Yu-Chen 
107933842cedSCho, Yu-Chen 
108033842cedSCho, Yu-Chen static void ms_lib_free_allocatedarea(struct us_data *us)
108133842cedSCho, Yu-Chen {
108233842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
108333842cedSCho, Yu-Chen 
108433842cedSCho, Yu-Chen 	ms_lib_free_writebuf(us); /* Free MS_Lib.pagemap */
108533842cedSCho, Yu-Chen 	ms_lib_free_logicalmap(us); /* kfree MS_Lib.Phy2LogMap and MS_Lib.Log2PhyMap */
108633842cedSCho, Yu-Chen 
108733842cedSCho, Yu-Chen 	/* set struct us point flag to 0 */
108833842cedSCho, Yu-Chen 	info->MS_Lib.flags = 0;
108933842cedSCho, Yu-Chen 	info->MS_Lib.BytesPerSector = 0;
109033842cedSCho, Yu-Chen 	info->MS_Lib.SectorsPerCylinder = 0;
109133842cedSCho, Yu-Chen 
109233842cedSCho, Yu-Chen 	info->MS_Lib.cardType = 0;
109333842cedSCho, Yu-Chen 	info->MS_Lib.blockSize = 0;
109433842cedSCho, Yu-Chen 	info->MS_Lib.PagesPerBlock = 0;
109533842cedSCho, Yu-Chen 
109633842cedSCho, Yu-Chen 	info->MS_Lib.NumberOfPhyBlock = 0;
109733842cedSCho, Yu-Chen 	info->MS_Lib.NumberOfLogBlock = 0;
109833842cedSCho, Yu-Chen }
109933842cedSCho, Yu-Chen 
110033842cedSCho, Yu-Chen 
110133842cedSCho, Yu-Chen static int ms_lib_alloc_writebuf(struct us_data *us)
110233842cedSCho, Yu-Chen {
110333842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
110433842cedSCho, Yu-Chen 
110533842cedSCho, Yu-Chen 	info->MS_Lib.wrtblk = (u16)-1;
110633842cedSCho, Yu-Chen 
110733842cedSCho, Yu-Chen 	info->MS_Lib.blkpag = kmalloc(info->MS_Lib.PagesPerBlock * info->MS_Lib.BytesPerSector, GFP_KERNEL);
110833842cedSCho, Yu-Chen 	info->MS_Lib.blkext = kmalloc(info->MS_Lib.PagesPerBlock * sizeof(struct ms_lib_type_extdat), GFP_KERNEL);
110933842cedSCho, Yu-Chen 
111033842cedSCho, Yu-Chen 	if ((info->MS_Lib.blkpag == NULL) || (info->MS_Lib.blkext == NULL)) {
111133842cedSCho, Yu-Chen 		ms_lib_free_writebuf(us);
111233842cedSCho, Yu-Chen 		return (u32)-1;
111333842cedSCho, Yu-Chen 	}
111433842cedSCho, Yu-Chen 
111533842cedSCho, Yu-Chen 	ms_lib_clear_writebuf(us);
111633842cedSCho, Yu-Chen 
111733842cedSCho, Yu-Chen return 0;
111833842cedSCho, Yu-Chen }
111933842cedSCho, Yu-Chen 
112033842cedSCho, Yu-Chen static int ms_lib_force_setlogical_pair(struct us_data *us, u16 logblk, u16 phyblk)
112133842cedSCho, Yu-Chen {
112233842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
112333842cedSCho, Yu-Chen 
112433842cedSCho, Yu-Chen 	if (logblk == MS_LB_NOT_USED)
112533842cedSCho, Yu-Chen 		return 0;
112633842cedSCho, Yu-Chen 
112733842cedSCho, Yu-Chen 	if ((logblk >= info->MS_Lib.NumberOfLogBlock) ||
112833842cedSCho, Yu-Chen 		(phyblk >= info->MS_Lib.NumberOfPhyBlock))
112933842cedSCho, Yu-Chen 		return (u32)-1;
113033842cedSCho, Yu-Chen 
113133842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap[phyblk] = logblk;
113233842cedSCho, Yu-Chen 	info->MS_Lib.Log2PhyMap[logblk] = phyblk;
113333842cedSCho, Yu-Chen 
113433842cedSCho, Yu-Chen 	return 0;
113533842cedSCho, Yu-Chen }
113633842cedSCho, Yu-Chen 
113733842cedSCho, Yu-Chen static int ms_read_copyblock(struct us_data *us, u16 oldphy, u16 newphy,
113833842cedSCho, Yu-Chen 			u16 PhyBlockAddr, u8 PageNum, unsigned char *buf, u16 len)
113933842cedSCho, Yu-Chen {
114033842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
114133842cedSCho, Yu-Chen 	int result;
114233842cedSCho, Yu-Chen 
114333842cedSCho, Yu-Chen 	result = ene_load_bincode(us, MS_RW_PATTERN);
114433842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
114533842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
114633842cedSCho, Yu-Chen 
114733842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
114833842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
114933842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x200*len;
115033842cedSCho, Yu-Chen 	bcb->Flags = 0x00;
115133842cedSCho, Yu-Chen 	bcb->CDB[0] = 0xF0;
115233842cedSCho, Yu-Chen 	bcb->CDB[1] = 0x08;
115333842cedSCho, Yu-Chen 	bcb->CDB[4] = (unsigned char)(oldphy);
115433842cedSCho, Yu-Chen 	bcb->CDB[3] = (unsigned char)(oldphy>>8);
115533842cedSCho, Yu-Chen 	bcb->CDB[2] = 0; /* (BYTE)(oldphy>>16) */
115633842cedSCho, Yu-Chen 	bcb->CDB[7] = (unsigned char)(newphy);
115733842cedSCho, Yu-Chen 	bcb->CDB[6] = (unsigned char)(newphy>>8);
115833842cedSCho, Yu-Chen 	bcb->CDB[5] = 0; /* (BYTE)(newphy>>16) */
115933842cedSCho, Yu-Chen 	bcb->CDB[9] = (unsigned char)(PhyBlockAddr);
116033842cedSCho, Yu-Chen 	bcb->CDB[8] = (unsigned char)(PhyBlockAddr>>8);
116133842cedSCho, Yu-Chen 	bcb->CDB[10] = PageNum;
116233842cedSCho, Yu-Chen 
116333842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
116433842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
116533842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
116633842cedSCho, Yu-Chen 
116733842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
116833842cedSCho, Yu-Chen }
116933842cedSCho, Yu-Chen 
117033842cedSCho, Yu-Chen static int ms_read_eraseblock(struct us_data *us, u32 PhyBlockAddr)
117133842cedSCho, Yu-Chen {
117233842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
117333842cedSCho, Yu-Chen 	int result;
117433842cedSCho, Yu-Chen 	u32 bn = PhyBlockAddr;
117533842cedSCho, Yu-Chen 
117633842cedSCho, Yu-Chen 	result = ene_load_bincode(us, MS_RW_PATTERN);
117733842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
117833842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
117933842cedSCho, Yu-Chen 
118033842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
118133842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
118233842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x200;
1183b8db6d64SSebastian Andrzej Siewior 	bcb->Flags = US_BULK_FLAG_IN;
118433842cedSCho, Yu-Chen 	bcb->CDB[0] = 0xF2;
118533842cedSCho, Yu-Chen 	bcb->CDB[1] = 0x06;
118633842cedSCho, Yu-Chen 	bcb->CDB[4] = (unsigned char)(bn);
118733842cedSCho, Yu-Chen 	bcb->CDB[3] = (unsigned char)(bn>>8);
118833842cedSCho, Yu-Chen 	bcb->CDB[2] = (unsigned char)(bn>>16);
118933842cedSCho, Yu-Chen 
119033842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
119133842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
119233842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
119333842cedSCho, Yu-Chen 
119433842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
119533842cedSCho, Yu-Chen }
119633842cedSCho, Yu-Chen 
119733842cedSCho, Yu-Chen static int ms_lib_check_disableblock(struct us_data *us, u16 PhyBlock)
119833842cedSCho, Yu-Chen {
119933842cedSCho, Yu-Chen 	unsigned char *PageBuf = NULL;
120033842cedSCho, Yu-Chen 	u16 result = MS_STATUS_SUCCESS;
120133842cedSCho, Yu-Chen 	u16 blk, index = 0;
120233842cedSCho, Yu-Chen 	struct ms_lib_type_extdat extdat;
120333842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
120433842cedSCho, Yu-Chen 
120533842cedSCho, Yu-Chen 	PageBuf = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
120633842cedSCho, Yu-Chen 	if (PageBuf == NULL) {
120733842cedSCho, Yu-Chen 		result = MS_NO_MEMORY_ERROR;
120833842cedSCho, Yu-Chen 		goto exit;
120933842cedSCho, Yu-Chen 	}
121033842cedSCho, Yu-Chen 
121133842cedSCho, Yu-Chen 	ms_read_readpage(us, PhyBlock, 1, (u32 *)PageBuf, &extdat);
121233842cedSCho, Yu-Chen 	do {
121333842cedSCho, Yu-Chen 		blk = be16_to_cpu(PageBuf[index]);
121433842cedSCho, Yu-Chen 		if (blk == MS_LB_NOT_USED)
121533842cedSCho, Yu-Chen 			break;
121633842cedSCho, Yu-Chen 		if (blk == info->MS_Lib.Log2PhyMap[0]) {
121733842cedSCho, Yu-Chen 			result = MS_ERROR_FLASH_READ;
121833842cedSCho, Yu-Chen 			break;
121933842cedSCho, Yu-Chen 		}
122033842cedSCho, Yu-Chen 		index++;
122133842cedSCho, Yu-Chen 	} while (1);
122233842cedSCho, Yu-Chen 
122333842cedSCho, Yu-Chen exit:
122433842cedSCho, Yu-Chen 	kfree(PageBuf);
122533842cedSCho, Yu-Chen 	return result;
122633842cedSCho, Yu-Chen }
122733842cedSCho, Yu-Chen 
122833842cedSCho, Yu-Chen static int ms_lib_setacquired_errorblock(struct us_data *us, u16 phyblk)
122933842cedSCho, Yu-Chen {
123033842cedSCho, Yu-Chen 	u16 log;
123133842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
123233842cedSCho, Yu-Chen 
123333842cedSCho, Yu-Chen 	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
123433842cedSCho, Yu-Chen 		return (u32)-1;
123533842cedSCho, Yu-Chen 
123633842cedSCho, Yu-Chen 	log = info->MS_Lib.Phy2LogMap[phyblk];
123733842cedSCho, Yu-Chen 
123833842cedSCho, Yu-Chen 	if (log < info->MS_Lib.NumberOfLogBlock)
123933842cedSCho, Yu-Chen 		info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
124033842cedSCho, Yu-Chen 
124133842cedSCho, Yu-Chen 	if (info->MS_Lib.Phy2LogMap[phyblk] != MS_LB_INITIAL_ERROR)
124233842cedSCho, Yu-Chen 		info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_ACQUIRED_ERROR;
124333842cedSCho, Yu-Chen 
124433842cedSCho, Yu-Chen 	return 0;
124533842cedSCho, Yu-Chen }
124633842cedSCho, Yu-Chen 
124733842cedSCho, Yu-Chen static int ms_lib_overwrite_extra(struct us_data *us, u32 PhyBlockAddr,
124833842cedSCho, Yu-Chen 				u8 PageNum, u8 OverwriteFlag)
124933842cedSCho, Yu-Chen {
125033842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
125133842cedSCho, Yu-Chen 	int result;
125233842cedSCho, Yu-Chen 
125333842cedSCho, Yu-Chen 	result = ene_load_bincode(us, MS_RW_PATTERN);
125433842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
125533842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
125633842cedSCho, Yu-Chen 
125733842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
125833842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
125933842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x4;
1260b8db6d64SSebastian Andrzej Siewior 	bcb->Flags = US_BULK_FLAG_IN;
126133842cedSCho, Yu-Chen 	bcb->CDB[0] = 0xF2;
126233842cedSCho, Yu-Chen 	bcb->CDB[1] = 0x05;
126333842cedSCho, Yu-Chen 	bcb->CDB[5] = (unsigned char)(PageNum);
126433842cedSCho, Yu-Chen 	bcb->CDB[4] = (unsigned char)(PhyBlockAddr);
126533842cedSCho, Yu-Chen 	bcb->CDB[3] = (unsigned char)(PhyBlockAddr>>8);
126633842cedSCho, Yu-Chen 	bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
126733842cedSCho, Yu-Chen 	bcb->CDB[6] = OverwriteFlag;
126833842cedSCho, Yu-Chen 	bcb->CDB[7] = 0xFF;
126933842cedSCho, Yu-Chen 	bcb->CDB[8] = 0xFF;
127033842cedSCho, Yu-Chen 	bcb->CDB[9] = 0xFF;
127133842cedSCho, Yu-Chen 
127233842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
127333842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
127433842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
127533842cedSCho, Yu-Chen 
127633842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
127733842cedSCho, Yu-Chen }
127833842cedSCho, Yu-Chen 
127933842cedSCho, Yu-Chen static int ms_lib_error_phyblock(struct us_data *us, u16 phyblk)
128033842cedSCho, Yu-Chen {
128133842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
128233842cedSCho, Yu-Chen 
128333842cedSCho, Yu-Chen 	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
128433842cedSCho, Yu-Chen 		return MS_STATUS_ERROR;
128533842cedSCho, Yu-Chen 
128633842cedSCho, Yu-Chen 	ms_lib_setacquired_errorblock(us, phyblk);
128733842cedSCho, Yu-Chen 
128833842cedSCho, Yu-Chen 	if (ms_lib_iswritable(info))
128933842cedSCho, Yu-Chen 		return ms_lib_overwrite_extra(us, phyblk, 0, (u8)(~MS_REG_OVR_BKST & BYTE_MASK));
129033842cedSCho, Yu-Chen 
129133842cedSCho, Yu-Chen 	return MS_STATUS_SUCCESS;
129233842cedSCho, Yu-Chen }
129333842cedSCho, Yu-Chen 
129433842cedSCho, Yu-Chen static int ms_lib_erase_phyblock(struct us_data *us, u16 phyblk)
129533842cedSCho, Yu-Chen {
129633842cedSCho, Yu-Chen 	u16 log;
129733842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
129833842cedSCho, Yu-Chen 
129933842cedSCho, Yu-Chen 	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
130033842cedSCho, Yu-Chen 		return MS_STATUS_ERROR;
130133842cedSCho, Yu-Chen 
130233842cedSCho, Yu-Chen 	log = info->MS_Lib.Phy2LogMap[phyblk];
130333842cedSCho, Yu-Chen 
130433842cedSCho, Yu-Chen 	if (log < info->MS_Lib.NumberOfLogBlock)
130533842cedSCho, Yu-Chen 		info->MS_Lib.Log2PhyMap[log] = MS_LB_NOT_USED;
130633842cedSCho, Yu-Chen 
130733842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED;
130833842cedSCho, Yu-Chen 
130933842cedSCho, Yu-Chen 	if (ms_lib_iswritable(info)) {
131033842cedSCho, Yu-Chen 		switch (ms_read_eraseblock(us, phyblk)) {
131133842cedSCho, Yu-Chen 		case MS_STATUS_SUCCESS:
131233842cedSCho, Yu-Chen 			info->MS_Lib.Phy2LogMap[phyblk] = MS_LB_NOT_USED_ERASED;
131333842cedSCho, Yu-Chen 			return MS_STATUS_SUCCESS;
131433842cedSCho, Yu-Chen 		case MS_ERROR_FLASH_ERASE:
131533842cedSCho, Yu-Chen 		case MS_STATUS_INT_ERROR:
131633842cedSCho, Yu-Chen 			ms_lib_error_phyblock(us, phyblk);
131733842cedSCho, Yu-Chen 			return MS_ERROR_FLASH_ERASE;
131833842cedSCho, Yu-Chen 		case MS_STATUS_ERROR:
131933842cedSCho, Yu-Chen 		default:
132033842cedSCho, 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*/
132133842cedSCho, Yu-Chen 			ms_lib_setacquired_errorblock(us, phyblk);
132233842cedSCho, Yu-Chen 			return MS_STATUS_ERROR;
132333842cedSCho, Yu-Chen 		}
132433842cedSCho, Yu-Chen 	}
132533842cedSCho, Yu-Chen 
132633842cedSCho, Yu-Chen 	ms_lib_setacquired_errorblock(us, phyblk);
132733842cedSCho, Yu-Chen 
132833842cedSCho, Yu-Chen 	return MS_STATUS_SUCCESS;
132933842cedSCho, Yu-Chen }
133033842cedSCho, Yu-Chen 
133133842cedSCho, Yu-Chen static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
133233842cedSCho, Yu-Chen 				u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
133333842cedSCho, Yu-Chen {
133433842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
133533842cedSCho, Yu-Chen 	int result;
133633842cedSCho, Yu-Chen 	u8 ExtBuf[4];
133733842cedSCho, Yu-Chen 
133833842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
133933842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
134033842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x4;
1341b8db6d64SSebastian Andrzej Siewior 	bcb->Flags      = US_BULK_FLAG_IN;
134233842cedSCho, Yu-Chen 	bcb->CDB[0]     = 0xF1;
134333842cedSCho, Yu-Chen 	bcb->CDB[1]     = 0x03;
134433842cedSCho, Yu-Chen 	bcb->CDB[5]     = (unsigned char)(PageNum);
134533842cedSCho, Yu-Chen 	bcb->CDB[4]     = (unsigned char)(PhyBlock);
134633842cedSCho, Yu-Chen 	bcb->CDB[3]     = (unsigned char)(PhyBlock>>8);
134733842cedSCho, Yu-Chen 	bcb->CDB[2]     = (unsigned char)(PhyBlock>>16);
134833842cedSCho, Yu-Chen 	bcb->CDB[6]     = 0x01;
134933842cedSCho, Yu-Chen 
135033842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0);
135133842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
135233842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
135333842cedSCho, Yu-Chen 
135433842cedSCho, Yu-Chen 	ExtraDat->reserved = 0;
135533842cedSCho, Yu-Chen 	ExtraDat->intr     = 0x80;  /* Not yet, waiting for fireware support */
135633842cedSCho, Yu-Chen 	ExtraDat->status0  = 0x10;  /* Not yet, waiting for fireware support */
135733842cedSCho, Yu-Chen 	ExtraDat->status1  = 0x00;  /* Not yet, waiting for fireware support */
135833842cedSCho, Yu-Chen 	ExtraDat->ovrflg   = ExtBuf[0];
135933842cedSCho, Yu-Chen 	ExtraDat->mngflg   = ExtBuf[1];
136033842cedSCho, Yu-Chen 	ExtraDat->logadr   = memstick_logaddr(ExtBuf[2], ExtBuf[3]);
136133842cedSCho, Yu-Chen 
136233842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
136333842cedSCho, Yu-Chen }
136433842cedSCho, Yu-Chen 
136533842cedSCho, Yu-Chen static int ms_libsearch_block_from_physical(struct us_data *us, u16 phyblk)
136633842cedSCho, Yu-Chen {
136733842cedSCho, Yu-Chen 	u16 blk;
136833842cedSCho, Yu-Chen 	struct ms_lib_type_extdat extdat; /* need check */
136933842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
137033842cedSCho, Yu-Chen 
137133842cedSCho, Yu-Chen 
137233842cedSCho, Yu-Chen 	if (phyblk >= info->MS_Lib.NumberOfPhyBlock)
137333842cedSCho, Yu-Chen 		return MS_LB_ERROR;
137433842cedSCho, Yu-Chen 
137533842cedSCho, Yu-Chen 	for (blk = phyblk + 1; blk != phyblk; blk++) {
137633842cedSCho, Yu-Chen 		if ((blk & MS_PHYSICAL_BLOCKS_PER_SEGMENT_MASK) == 0)
137733842cedSCho, Yu-Chen 			blk -= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
137833842cedSCho, Yu-Chen 
137933842cedSCho, Yu-Chen 		if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED_ERASED) {
138033842cedSCho, Yu-Chen 			return blk;
138133842cedSCho, Yu-Chen 		} else if (info->MS_Lib.Phy2LogMap[blk] == MS_LB_NOT_USED) {
138233842cedSCho, Yu-Chen 			switch (ms_lib_read_extra(us, blk, 0, &extdat)) {
138333842cedSCho, Yu-Chen 			case MS_STATUS_SUCCESS:
138433842cedSCho, Yu-Chen 			case MS_STATUS_SUCCESS_WITH_ECC:
138533842cedSCho, Yu-Chen 				break;
138633842cedSCho, Yu-Chen 			case MS_NOCARD_ERROR:
138733842cedSCho, Yu-Chen 				return MS_NOCARD_ERROR;
138833842cedSCho, Yu-Chen 			case MS_STATUS_INT_ERROR:
138933842cedSCho, Yu-Chen 				return MS_LB_ERROR;
139033842cedSCho, Yu-Chen 			case MS_ERROR_FLASH_READ:
139133842cedSCho, Yu-Chen 			default:
139233842cedSCho, Yu-Chen 				ms_lib_setacquired_errorblock(us, blk);
139333842cedSCho, Yu-Chen 				continue;
139433842cedSCho, Yu-Chen 			} /* End switch */
139533842cedSCho, Yu-Chen 
139633842cedSCho, Yu-Chen 			if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
139733842cedSCho, Yu-Chen 				ms_lib_setacquired_errorblock(us, blk);
139833842cedSCho, Yu-Chen 				continue;
139933842cedSCho, Yu-Chen 			}
140033842cedSCho, Yu-Chen 
140133842cedSCho, Yu-Chen 			switch (ms_lib_erase_phyblock(us, blk)) {
140233842cedSCho, Yu-Chen 			case MS_STATUS_SUCCESS:
140333842cedSCho, Yu-Chen 				return blk;
140433842cedSCho, Yu-Chen 			case MS_STATUS_ERROR:
140533842cedSCho, Yu-Chen 				return MS_LB_ERROR;
140633842cedSCho, Yu-Chen 			case MS_ERROR_FLASH_ERASE:
140733842cedSCho, Yu-Chen 			default:
140833842cedSCho, Yu-Chen 				ms_lib_error_phyblock(us, blk);
140933842cedSCho, Yu-Chen 				break;
141033842cedSCho, Yu-Chen 			}
141133842cedSCho, Yu-Chen 		}
141233842cedSCho, Yu-Chen 	} /* End for */
141333842cedSCho, Yu-Chen 
141433842cedSCho, Yu-Chen 	return MS_LB_ERROR;
141533842cedSCho, Yu-Chen }
141633842cedSCho, Yu-Chen static int ms_libsearch_block_from_logical(struct us_data *us, u16 logblk)
141733842cedSCho, Yu-Chen {
141833842cedSCho, Yu-Chen 	u16 phyblk;
141933842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
142033842cedSCho, Yu-Chen 
142133842cedSCho, Yu-Chen 	phyblk = ms_libconv_to_physical(info, logblk);
142233842cedSCho, Yu-Chen 	if (phyblk >= MS_LB_ERROR) {
142333842cedSCho, Yu-Chen 		if (logblk >= info->MS_Lib.NumberOfLogBlock)
142433842cedSCho, Yu-Chen 			return MS_LB_ERROR;
142533842cedSCho, Yu-Chen 
142633842cedSCho, Yu-Chen 		phyblk = (logblk + MS_NUMBER_OF_BOOT_BLOCK) / MS_LOGICAL_BLOCKS_PER_SEGMENT;
142733842cedSCho, Yu-Chen 		phyblk *= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
142833842cedSCho, Yu-Chen 		phyblk += MS_PHYSICAL_BLOCKS_PER_SEGMENT - 1;
142933842cedSCho, Yu-Chen 	}
143033842cedSCho, Yu-Chen 
143133842cedSCho, Yu-Chen 	return ms_libsearch_block_from_physical(us, phyblk);
143233842cedSCho, Yu-Chen }
143333842cedSCho, Yu-Chen 
143433842cedSCho, Yu-Chen static int ms_scsi_test_unit_ready(struct us_data *us, struct scsi_cmnd *srb)
143533842cedSCho, Yu-Chen {
143633842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
143733842cedSCho, Yu-Chen 
143833842cedSCho, Yu-Chen 	/* pr_info("MS_SCSI_Test_Unit_Ready\n"); */
143933842cedSCho, Yu-Chen 	if (info->MS_Status.Insert && info->MS_Status.Ready) {
144033842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_GOOD;
144133842cedSCho, Yu-Chen 	} else {
144233842cedSCho, Yu-Chen 		ene_ms_init(us);
144333842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_GOOD;
144433842cedSCho, Yu-Chen 	}
144533842cedSCho, Yu-Chen 
144633842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
144733842cedSCho, Yu-Chen }
144833842cedSCho, Yu-Chen 
144933842cedSCho, Yu-Chen static int ms_scsi_inquiry(struct us_data *us, struct scsi_cmnd *srb)
145033842cedSCho, Yu-Chen {
145133842cedSCho, Yu-Chen 	/* pr_info("MS_SCSI_Inquiry\n"); */
145233842cedSCho, Yu-Chen 	unsigned char data_ptr[36] = {
145333842cedSCho, Yu-Chen 		0x00, 0x80, 0x02, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x55,
145433842cedSCho, Yu-Chen 		0x53, 0x42, 0x32, 0x2E, 0x30, 0x20, 0x20, 0x43, 0x61,
145533842cedSCho, Yu-Chen 		0x72, 0x64, 0x52, 0x65, 0x61, 0x64, 0x65, 0x72, 0x20,
145633842cedSCho, Yu-Chen 		0x20, 0x20, 0x20, 0x20, 0x20, 0x30, 0x31, 0x30, 0x30};
145733842cedSCho, Yu-Chen 
145833842cedSCho, Yu-Chen 	usb_stor_set_xfer_buf(data_ptr, 36, srb);
145933842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
146033842cedSCho, Yu-Chen }
146133842cedSCho, Yu-Chen 
146233842cedSCho, Yu-Chen static int ms_scsi_mode_sense(struct us_data *us, struct scsi_cmnd *srb)
146333842cedSCho, Yu-Chen {
146433842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
146533842cedSCho, Yu-Chen 	unsigned char mediaNoWP[12] = {
146633842cedSCho, Yu-Chen 		0x0b, 0x00, 0x00, 0x08, 0x00, 0x00,
146733842cedSCho, Yu-Chen 		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
146833842cedSCho, Yu-Chen 	unsigned char mediaWP[12]   = {
146933842cedSCho, Yu-Chen 		0x0b, 0x00, 0x80, 0x08, 0x00, 0x00,
147033842cedSCho, Yu-Chen 		0x71, 0xc0, 0x00, 0x00, 0x02, 0x00 };
147133842cedSCho, Yu-Chen 
147233842cedSCho, Yu-Chen 	if (info->MS_Status.WtP)
147333842cedSCho, Yu-Chen 		usb_stor_set_xfer_buf(mediaWP, 12, srb);
147433842cedSCho, Yu-Chen 	else
147533842cedSCho, Yu-Chen 		usb_stor_set_xfer_buf(mediaNoWP, 12, srb);
147633842cedSCho, Yu-Chen 
147733842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
147833842cedSCho, Yu-Chen }
147933842cedSCho, Yu-Chen 
148033842cedSCho, Yu-Chen static int ms_scsi_read_capacity(struct us_data *us, struct scsi_cmnd *srb)
148133842cedSCho, Yu-Chen {
148233842cedSCho, Yu-Chen 	u32   bl_num;
148333842cedSCho, Yu-Chen 	u16    bl_len;
148433842cedSCho, Yu-Chen 	unsigned int offset = 0;
148533842cedSCho, Yu-Chen 	unsigned char    buf[8];
148633842cedSCho, Yu-Chen 	struct scatterlist *sg = NULL;
148733842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
148833842cedSCho, Yu-Chen 
1489191648d0SJoe Perches 	usb_stor_dbg(us, "ms_scsi_read_capacity\n");
149033842cedSCho, Yu-Chen 	bl_len = 0x200;
149133842cedSCho, Yu-Chen 	if (info->MS_Status.IsMSPro)
149233842cedSCho, Yu-Chen 		bl_num = info->MSP_TotalBlock - 1;
149333842cedSCho, Yu-Chen 	else
149433842cedSCho, Yu-Chen 		bl_num = info->MS_Lib.NumberOfLogBlock * info->MS_Lib.blockSize * 2 - 1;
149533842cedSCho, Yu-Chen 
149633842cedSCho, Yu-Chen 	info->bl_num = bl_num;
1497191648d0SJoe Perches 	usb_stor_dbg(us, "bl_len = %x\n", bl_len);
1498191648d0SJoe Perches 	usb_stor_dbg(us, "bl_num = %x\n", bl_num);
149933842cedSCho, Yu-Chen 
150033842cedSCho, Yu-Chen 	/*srb->request_bufflen = 8; */
150133842cedSCho, Yu-Chen 	buf[0] = (bl_num >> 24) & 0xff;
150233842cedSCho, Yu-Chen 	buf[1] = (bl_num >> 16) & 0xff;
150333842cedSCho, Yu-Chen 	buf[2] = (bl_num >> 8) & 0xff;
150433842cedSCho, Yu-Chen 	buf[3] = (bl_num >> 0) & 0xff;
150533842cedSCho, Yu-Chen 	buf[4] = (bl_len >> 24) & 0xff;
150633842cedSCho, Yu-Chen 	buf[5] = (bl_len >> 16) & 0xff;
150733842cedSCho, Yu-Chen 	buf[6] = (bl_len >> 8) & 0xff;
150833842cedSCho, Yu-Chen 	buf[7] = (bl_len >> 0) & 0xff;
150933842cedSCho, Yu-Chen 
151033842cedSCho, Yu-Chen 	usb_stor_access_xfer_buf(buf, 8, srb, &sg, &offset, TO_XFER_BUF);
151133842cedSCho, Yu-Chen 
151233842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
151333842cedSCho, Yu-Chen }
151433842cedSCho, Yu-Chen 
151533842cedSCho, Yu-Chen static void ms_lib_phy_to_log_range(u16 PhyBlock, u16 *LogStart, u16 *LogEnde)
151633842cedSCho, Yu-Chen {
151733842cedSCho, Yu-Chen 	PhyBlock /= MS_PHYSICAL_BLOCKS_PER_SEGMENT;
151833842cedSCho, Yu-Chen 
151933842cedSCho, Yu-Chen 	if (PhyBlock) {
152033842cedSCho, Yu-Chen 		*LogStart = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT + (PhyBlock - 1) * MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
152133842cedSCho, Yu-Chen 		*LogEnde = *LogStart + MS_LOGICAL_BLOCKS_PER_SEGMENT;/*496*/
152233842cedSCho, Yu-Chen 	} else {
152333842cedSCho, Yu-Chen 		*LogStart = 0;
152433842cedSCho, Yu-Chen 		*LogEnde = MS_LOGICAL_BLOCKS_IN_1ST_SEGMENT;/*494*/
152533842cedSCho, Yu-Chen 	}
152633842cedSCho, Yu-Chen }
152733842cedSCho, Yu-Chen 
152833842cedSCho, Yu-Chen static int ms_lib_read_extrablock(struct us_data *us, u32 PhyBlock,
152933842cedSCho, Yu-Chen 	u8 PageNum, u8 blen, void *buf)
153033842cedSCho, Yu-Chen {
153133842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
153233842cedSCho, Yu-Chen 	int     result;
153333842cedSCho, Yu-Chen 
153433842cedSCho, Yu-Chen 	/* Read Extra Data */
153533842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
153633842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
153733842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x4 * blen;
1538b8db6d64SSebastian Andrzej Siewior 	bcb->Flags      = US_BULK_FLAG_IN;
153933842cedSCho, Yu-Chen 	bcb->CDB[0]     = 0xF1;
154033842cedSCho, Yu-Chen 	bcb->CDB[1]     = 0x03;
154133842cedSCho, Yu-Chen 	bcb->CDB[5]     = (unsigned char)(PageNum);
154233842cedSCho, Yu-Chen 	bcb->CDB[4]     = (unsigned char)(PhyBlock);
154333842cedSCho, Yu-Chen 	bcb->CDB[3]     = (unsigned char)(PhyBlock>>8);
154433842cedSCho, Yu-Chen 	bcb->CDB[2]     = (unsigned char)(PhyBlock>>16);
154533842cedSCho, Yu-Chen 	bcb->CDB[6]     = blen;
154633842cedSCho, Yu-Chen 
154733842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
154833842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD)
154933842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
155033842cedSCho, Yu-Chen 
155133842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
155233842cedSCho, Yu-Chen }
155333842cedSCho, Yu-Chen 
155433842cedSCho, Yu-Chen static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
155533842cedSCho, Yu-Chen {
155633842cedSCho, Yu-Chen 	u16 PhyBlock, newblk, i;
155733842cedSCho, Yu-Chen 	u16 LogStart, LogEnde;
155833842cedSCho, Yu-Chen 	struct ms_lib_type_extdat extdat;
155933842cedSCho, Yu-Chen 	u8 buf[0x200];
156033842cedSCho, Yu-Chen 	u32 count = 0, index = 0;
156133842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
156233842cedSCho, Yu-Chen 
156333842cedSCho, Yu-Chen 	for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
156433842cedSCho, Yu-Chen 		ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
156533842cedSCho, Yu-Chen 
156633842cedSCho, Yu-Chen 		for (i = 0; i < MS_PHYSICAL_BLOCKS_PER_SEGMENT; i++, PhyBlock++) {
156733842cedSCho, Yu-Chen 			switch (ms_libconv_to_logical(info, PhyBlock)) {
156833842cedSCho, Yu-Chen 			case MS_STATUS_ERROR:
156933842cedSCho, Yu-Chen 				continue;
157033842cedSCho, Yu-Chen 			default:
157133842cedSCho, Yu-Chen 				break;
157233842cedSCho, Yu-Chen 			}
157333842cedSCho, Yu-Chen 
157433842cedSCho, Yu-Chen 			if (count == PhyBlock) {
157533842cedSCho, Yu-Chen 				ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf);
157633842cedSCho, Yu-Chen 				count += 0x80;
157733842cedSCho, Yu-Chen 			}
157833842cedSCho, Yu-Chen 			index = (PhyBlock % 0x80) * 4;
157933842cedSCho, Yu-Chen 
158033842cedSCho, Yu-Chen 			extdat.ovrflg = buf[index];
158133842cedSCho, Yu-Chen 			extdat.mngflg = buf[index+1];
158233842cedSCho, Yu-Chen 			extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]);
158333842cedSCho, Yu-Chen 
158433842cedSCho, Yu-Chen 			if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
158533842cedSCho, Yu-Chen 				ms_lib_setacquired_errorblock(us, PhyBlock);
158633842cedSCho, Yu-Chen 				continue;
158733842cedSCho, Yu-Chen 			}
158833842cedSCho, Yu-Chen 
158933842cedSCho, Yu-Chen 			if ((extdat.mngflg & MS_REG_MNG_ATFLG) == MS_REG_MNG_ATFLG_ATTBL) {
159033842cedSCho, Yu-Chen 				ms_lib_erase_phyblock(us, PhyBlock);
159133842cedSCho, Yu-Chen 				continue;
159233842cedSCho, Yu-Chen 			}
159333842cedSCho, Yu-Chen 
159433842cedSCho, Yu-Chen 			if (extdat.logadr != MS_LB_NOT_USED) {
159533842cedSCho, Yu-Chen 				if ((extdat.logadr < LogStart) || (LogEnde <= extdat.logadr)) {
159633842cedSCho, Yu-Chen 					ms_lib_erase_phyblock(us, PhyBlock);
159733842cedSCho, Yu-Chen 					continue;
159833842cedSCho, Yu-Chen 				}
159933842cedSCho, Yu-Chen 
160033842cedSCho, Yu-Chen 				newblk = ms_libconv_to_physical(info, extdat.logadr);
160133842cedSCho, Yu-Chen 
160233842cedSCho, Yu-Chen 				if (newblk != MS_LB_NOT_USED) {
160333842cedSCho, Yu-Chen 					if (extdat.logadr == 0) {
160433842cedSCho, Yu-Chen 						ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
160533842cedSCho, Yu-Chen 						if (ms_lib_check_disableblock(us, btBlk1st)) {
160633842cedSCho, Yu-Chen 							ms_lib_set_logicalpair(us, extdat.logadr, newblk);
160733842cedSCho, Yu-Chen 							continue;
160833842cedSCho, Yu-Chen 						}
160933842cedSCho, Yu-Chen 					}
161033842cedSCho, Yu-Chen 
161133842cedSCho, Yu-Chen 					ms_lib_read_extra(us, newblk, 0, &extdat);
161233842cedSCho, Yu-Chen 					if ((extdat.ovrflg & MS_REG_OVR_UDST) == MS_REG_OVR_UDST_UPDATING) {
161333842cedSCho, Yu-Chen 						ms_lib_erase_phyblock(us, PhyBlock);
161433842cedSCho, Yu-Chen 						continue;
161533842cedSCho, Yu-Chen 					} else {
161633842cedSCho, Yu-Chen 						ms_lib_erase_phyblock(us, newblk);
161733842cedSCho, Yu-Chen 					}
161833842cedSCho, Yu-Chen 				}
161933842cedSCho, Yu-Chen 
162033842cedSCho, Yu-Chen 				ms_lib_set_logicalpair(us, extdat.logadr, PhyBlock);
162133842cedSCho, Yu-Chen 			}
162233842cedSCho, Yu-Chen 		}
162333842cedSCho, Yu-Chen 	} /* End for ... */
162433842cedSCho, Yu-Chen 
162533842cedSCho, Yu-Chen 	return MS_STATUS_SUCCESS;
162633842cedSCho, Yu-Chen }
162733842cedSCho, Yu-Chen 
162833842cedSCho, Yu-Chen 
162933842cedSCho, Yu-Chen static int ms_scsi_read(struct us_data *us, struct scsi_cmnd *srb)
163033842cedSCho, Yu-Chen {
163133842cedSCho, Yu-Chen 	int result;
163233842cedSCho, Yu-Chen 	unsigned char *cdb = srb->cmnd;
163333842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
163433842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
163533842cedSCho, Yu-Chen 
163633842cedSCho, Yu-Chen 	u32 bn = ((cdb[2] << 24) & 0xff000000) | ((cdb[3] << 16) & 0x00ff0000) |
163733842cedSCho, Yu-Chen 		((cdb[4] << 8) & 0x0000ff00) | ((cdb[5] << 0) & 0x000000ff);
163833842cedSCho, Yu-Chen 	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
163933842cedSCho, Yu-Chen 	u32 blenByte = blen * 0x200;
164033842cedSCho, Yu-Chen 
164133842cedSCho, Yu-Chen 	if (bn > info->bl_num)
164233842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
164333842cedSCho, Yu-Chen 
164433842cedSCho, Yu-Chen 	if (info->MS_Status.IsMSPro) {
164533842cedSCho, Yu-Chen 		result = ene_load_bincode(us, MSP_RW_PATTERN);
164633842cedSCho, Yu-Chen 		if (result != USB_STOR_XFER_GOOD) {
1647191648d0SJoe Perches 			usb_stor_dbg(us, "Load MPS RW pattern Fail !!\n");
164833842cedSCho, Yu-Chen 			return USB_STOR_TRANSPORT_ERROR;
164933842cedSCho, Yu-Chen 		}
165033842cedSCho, Yu-Chen 
165133842cedSCho, Yu-Chen 		/* set up the command wrapper */
165233842cedSCho, Yu-Chen 		memset(bcb, 0, sizeof(struct bulk_cb_wrap));
165333842cedSCho, Yu-Chen 		bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
165433842cedSCho, Yu-Chen 		bcb->DataTransferLength = blenByte;
1655b8db6d64SSebastian Andrzej Siewior 		bcb->Flags  = US_BULK_FLAG_IN;
165633842cedSCho, Yu-Chen 		bcb->CDB[0] = 0xF1;
165733842cedSCho, Yu-Chen 		bcb->CDB[1] = 0x02;
165833842cedSCho, Yu-Chen 		bcb->CDB[5] = (unsigned char)(bn);
165933842cedSCho, Yu-Chen 		bcb->CDB[4] = (unsigned char)(bn>>8);
166033842cedSCho, Yu-Chen 		bcb->CDB[3] = (unsigned char)(bn>>16);
166133842cedSCho, Yu-Chen 		bcb->CDB[2] = (unsigned char)(bn>>24);
166233842cedSCho, Yu-Chen 
166333842cedSCho, Yu-Chen 		result = ene_send_scsi_cmd(us, FDIR_READ, scsi_sglist(srb), 1);
166433842cedSCho, Yu-Chen 	} else {
166533842cedSCho, Yu-Chen 		void *buf;
166633842cedSCho, Yu-Chen 		int offset = 0;
166733842cedSCho, Yu-Chen 		u16 phyblk, logblk;
166833842cedSCho, Yu-Chen 		u8 PageNum;
166933842cedSCho, Yu-Chen 		u16 len;
167033842cedSCho, Yu-Chen 		u32 blkno;
167133842cedSCho, Yu-Chen 
167233842cedSCho, Yu-Chen 		buf = kmalloc(blenByte, GFP_KERNEL);
167333842cedSCho, Yu-Chen 		if (buf == NULL)
167433842cedSCho, Yu-Chen 			return USB_STOR_TRANSPORT_ERROR;
167533842cedSCho, Yu-Chen 
167633842cedSCho, Yu-Chen 		result = ene_load_bincode(us, MS_RW_PATTERN);
167733842cedSCho, Yu-Chen 		if (result != USB_STOR_XFER_GOOD) {
167833842cedSCho, Yu-Chen 			pr_info("Load MS RW pattern Fail !!\n");
167933842cedSCho, Yu-Chen 			result = USB_STOR_TRANSPORT_ERROR;
168033842cedSCho, Yu-Chen 			goto exit;
168133842cedSCho, Yu-Chen 		}
168233842cedSCho, Yu-Chen 
168333842cedSCho, Yu-Chen 		logblk  = (u16)(bn / info->MS_Lib.PagesPerBlock);
168433842cedSCho, Yu-Chen 		PageNum = (u8)(bn % info->MS_Lib.PagesPerBlock);
168533842cedSCho, Yu-Chen 
168633842cedSCho, Yu-Chen 		while (1) {
168733842cedSCho, Yu-Chen 			if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
168833842cedSCho, Yu-Chen 				len = info->MS_Lib.PagesPerBlock-PageNum;
168933842cedSCho, Yu-Chen 			else
169033842cedSCho, Yu-Chen 				len = blen;
169133842cedSCho, Yu-Chen 
169233842cedSCho, Yu-Chen 			phyblk = ms_libconv_to_physical(info, logblk);
169333842cedSCho, Yu-Chen 			blkno  = phyblk * 0x20 + PageNum;
169433842cedSCho, Yu-Chen 
169533842cedSCho, Yu-Chen 			/* set up the command wrapper */
169633842cedSCho, Yu-Chen 			memset(bcb, 0, sizeof(struct bulk_cb_wrap));
169733842cedSCho, Yu-Chen 			bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
169833842cedSCho, Yu-Chen 			bcb->DataTransferLength = 0x200 * len;
1699b8db6d64SSebastian Andrzej Siewior 			bcb->Flags  = US_BULK_FLAG_IN;
170033842cedSCho, Yu-Chen 			bcb->CDB[0] = 0xF1;
170133842cedSCho, Yu-Chen 			bcb->CDB[1] = 0x02;
170233842cedSCho, Yu-Chen 			bcb->CDB[5] = (unsigned char)(blkno);
170333842cedSCho, Yu-Chen 			bcb->CDB[4] = (unsigned char)(blkno>>8);
170433842cedSCho, Yu-Chen 			bcb->CDB[3] = (unsigned char)(blkno>>16);
170533842cedSCho, Yu-Chen 			bcb->CDB[2] = (unsigned char)(blkno>>24);
170633842cedSCho, Yu-Chen 
170733842cedSCho, Yu-Chen 			result = ene_send_scsi_cmd(us, FDIR_READ, buf+offset, 0);
170833842cedSCho, Yu-Chen 			if (result != USB_STOR_XFER_GOOD) {
170933842cedSCho, Yu-Chen 				pr_info("MS_SCSI_Read --- result = %x\n", result);
171033842cedSCho, Yu-Chen 				result = USB_STOR_TRANSPORT_ERROR;
171133842cedSCho, Yu-Chen 				goto exit;
171233842cedSCho, Yu-Chen 			}
171333842cedSCho, Yu-Chen 
171433842cedSCho, Yu-Chen 			blen -= len;
171533842cedSCho, Yu-Chen 			if (blen <= 0)
171633842cedSCho, Yu-Chen 				break;
171733842cedSCho, Yu-Chen 			logblk++;
171833842cedSCho, Yu-Chen 			PageNum = 0;
171933842cedSCho, Yu-Chen 			offset += MS_BYTES_PER_PAGE*len;
172033842cedSCho, Yu-Chen 		}
172133842cedSCho, Yu-Chen 		usb_stor_set_xfer_buf(buf, blenByte, srb);
172233842cedSCho, Yu-Chen exit:
172333842cedSCho, Yu-Chen 		kfree(buf);
172433842cedSCho, Yu-Chen 	}
172533842cedSCho, Yu-Chen 	return result;
172633842cedSCho, Yu-Chen }
172733842cedSCho, Yu-Chen 
172833842cedSCho, Yu-Chen static int ms_scsi_write(struct us_data *us, struct scsi_cmnd *srb)
172933842cedSCho, Yu-Chen {
173033842cedSCho, Yu-Chen 	int result;
173133842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
173233842cedSCho, Yu-Chen 	unsigned char *cdb = srb->cmnd;
173333842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
173433842cedSCho, Yu-Chen 
173533842cedSCho, Yu-Chen 	u32 bn = ((cdb[2] << 24) & 0xff000000) |
173633842cedSCho, Yu-Chen 			((cdb[3] << 16) & 0x00ff0000) |
173733842cedSCho, Yu-Chen 			((cdb[4] << 8) & 0x0000ff00) |
173833842cedSCho, Yu-Chen 			((cdb[5] << 0) & 0x000000ff);
173933842cedSCho, Yu-Chen 	u16 blen = ((cdb[7] << 8) & 0xff00) | ((cdb[8] << 0) & 0x00ff);
174033842cedSCho, Yu-Chen 	u32 blenByte = blen * 0x200;
174133842cedSCho, Yu-Chen 
174233842cedSCho, Yu-Chen 	if (bn > info->bl_num)
174333842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
174433842cedSCho, Yu-Chen 
174533842cedSCho, Yu-Chen 	if (info->MS_Status.IsMSPro) {
174633842cedSCho, Yu-Chen 		result = ene_load_bincode(us, MSP_RW_PATTERN);
174733842cedSCho, Yu-Chen 		if (result != USB_STOR_XFER_GOOD) {
174833842cedSCho, Yu-Chen 			pr_info("Load MSP RW pattern Fail !!\n");
174933842cedSCho, Yu-Chen 			return USB_STOR_TRANSPORT_ERROR;
175033842cedSCho, Yu-Chen 		}
175133842cedSCho, Yu-Chen 
175233842cedSCho, Yu-Chen 		/* set up the command wrapper */
175333842cedSCho, Yu-Chen 		memset(bcb, 0, sizeof(struct bulk_cb_wrap));
175433842cedSCho, Yu-Chen 		bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
175533842cedSCho, Yu-Chen 		bcb->DataTransferLength = blenByte;
175633842cedSCho, Yu-Chen 		bcb->Flags  = 0x00;
175733842cedSCho, Yu-Chen 		bcb->CDB[0] = 0xF0;
175833842cedSCho, Yu-Chen 		bcb->CDB[1] = 0x04;
175933842cedSCho, Yu-Chen 		bcb->CDB[5] = (unsigned char)(bn);
176033842cedSCho, Yu-Chen 		bcb->CDB[4] = (unsigned char)(bn>>8);
176133842cedSCho, Yu-Chen 		bcb->CDB[3] = (unsigned char)(bn>>16);
176233842cedSCho, Yu-Chen 		bcb->CDB[2] = (unsigned char)(bn>>24);
176333842cedSCho, Yu-Chen 
176433842cedSCho, Yu-Chen 		result = ene_send_scsi_cmd(us, FDIR_WRITE, scsi_sglist(srb), 1);
176533842cedSCho, Yu-Chen 	} else {
176633842cedSCho, Yu-Chen 		void *buf;
1767bc985c10SFelipe Balbi 		int offset = 0;
176833842cedSCho, Yu-Chen 		u16 PhyBlockAddr;
176933842cedSCho, Yu-Chen 		u8 PageNum;
177033842cedSCho, Yu-Chen 		u16 len, oldphy, newphy;
177133842cedSCho, Yu-Chen 
177233842cedSCho, Yu-Chen 		buf = kmalloc(blenByte, GFP_KERNEL);
177333842cedSCho, Yu-Chen 		if (buf == NULL)
177433842cedSCho, Yu-Chen 			return USB_STOR_TRANSPORT_ERROR;
177533842cedSCho, Yu-Chen 		usb_stor_set_xfer_buf(buf, blenByte, srb);
177633842cedSCho, Yu-Chen 
177733842cedSCho, Yu-Chen 		result = ene_load_bincode(us, MS_RW_PATTERN);
177833842cedSCho, Yu-Chen 		if (result != USB_STOR_XFER_GOOD) {
177933842cedSCho, Yu-Chen 			pr_info("Load MS RW pattern Fail !!\n");
178033842cedSCho, Yu-Chen 			result = USB_STOR_TRANSPORT_ERROR;
178133842cedSCho, Yu-Chen 			goto exit;
178233842cedSCho, Yu-Chen 		}
178333842cedSCho, Yu-Chen 
178433842cedSCho, Yu-Chen 		PhyBlockAddr = (u16)(bn / info->MS_Lib.PagesPerBlock);
178533842cedSCho, Yu-Chen 		PageNum      = (u8)(bn % info->MS_Lib.PagesPerBlock);
178633842cedSCho, Yu-Chen 
178733842cedSCho, Yu-Chen 		while (1) {
178833842cedSCho, Yu-Chen 			if (blen > (info->MS_Lib.PagesPerBlock-PageNum))
178933842cedSCho, Yu-Chen 				len = info->MS_Lib.PagesPerBlock-PageNum;
179033842cedSCho, Yu-Chen 			else
179133842cedSCho, Yu-Chen 				len = blen;
179233842cedSCho, Yu-Chen 
179333842cedSCho, Yu-Chen 			oldphy = ms_libconv_to_physical(info, PhyBlockAddr); /* need check us <-> info */
179433842cedSCho, Yu-Chen 			newphy = ms_libsearch_block_from_logical(us, PhyBlockAddr);
179533842cedSCho, Yu-Chen 
179633842cedSCho, Yu-Chen 			result = ms_read_copyblock(us, oldphy, newphy, PhyBlockAddr, PageNum, buf+offset, len);
179733842cedSCho, Yu-Chen 
179833842cedSCho, Yu-Chen 			if (result != USB_STOR_XFER_GOOD) {
179933842cedSCho, Yu-Chen 				pr_info("MS_SCSI_Write --- result = %x\n", result);
180033842cedSCho, Yu-Chen 				result =  USB_STOR_TRANSPORT_ERROR;
180133842cedSCho, Yu-Chen 				goto exit;
180233842cedSCho, Yu-Chen 			}
180333842cedSCho, Yu-Chen 
180433842cedSCho, Yu-Chen 			info->MS_Lib.Phy2LogMap[oldphy] = MS_LB_NOT_USED_ERASED;
180533842cedSCho, Yu-Chen 			ms_lib_force_setlogical_pair(us, PhyBlockAddr, newphy);
180633842cedSCho, Yu-Chen 
180733842cedSCho, Yu-Chen 			blen -= len;
180833842cedSCho, Yu-Chen 			if (blen <= 0)
180933842cedSCho, Yu-Chen 				break;
181033842cedSCho, Yu-Chen 			PhyBlockAddr++;
181133842cedSCho, Yu-Chen 			PageNum = 0;
181233842cedSCho, Yu-Chen 			offset += MS_BYTES_PER_PAGE*len;
181333842cedSCho, Yu-Chen 		}
181433842cedSCho, Yu-Chen exit:
181533842cedSCho, Yu-Chen 		kfree(buf);
181633842cedSCho, Yu-Chen 	}
181733842cedSCho, Yu-Chen 	return result;
181833842cedSCho, Yu-Chen }
181933842cedSCho, Yu-Chen 
182033842cedSCho, Yu-Chen /*
182133842cedSCho, Yu-Chen  * ENE MS Card
182233842cedSCho, Yu-Chen  */
182333842cedSCho, Yu-Chen 
182441e568d1Shuajun li static int ene_get_card_type(struct us_data *us, u16 index, void *buf)
182541e568d1Shuajun li {
182641e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
182741e568d1Shuajun li 	int result;
182841e568d1Shuajun li 
182941e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
183041e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
183141e568d1Shuajun li 	bcb->DataTransferLength	= 0x01;
1832b8db6d64SSebastian Andrzej Siewior 	bcb->Flags			= US_BULK_FLAG_IN;
183341e568d1Shuajun li 	bcb->CDB[0]			= 0xED;
183441e568d1Shuajun li 	bcb->CDB[2]			= (unsigned char)(index>>8);
183541e568d1Shuajun li 	bcb->CDB[3]			= (unsigned char)index;
183641e568d1Shuajun li 
183741e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, buf, 0);
183841e568d1Shuajun li 	return result;
183941e568d1Shuajun li }
184041e568d1Shuajun li 
184141e568d1Shuajun li static int ene_get_card_status(struct us_data *us, u8 *buf)
184241e568d1Shuajun li {
184341e568d1Shuajun li 	u16 tmpreg;
184441e568d1Shuajun li 	u32 reg4b;
184541e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
184641e568d1Shuajun li 
1847191648d0SJoe Perches 	/*usb_stor_dbg(us, "transport --- ENE_ReadSDReg\n");*/
184841e568d1Shuajun li 	reg4b = *(u32 *)&buf[0x18];
184941e568d1Shuajun li 	info->SD_READ_BL_LEN = (u8)((reg4b >> 8) & 0x0f);
185041e568d1Shuajun li 
185141e568d1Shuajun li 	tmpreg = (u16) reg4b;
185241e568d1Shuajun li 	reg4b = *(u32 *)(&buf[0x14]);
185341e568d1Shuajun li 	if (info->SD_Status.HiCapacity && !info->SD_Status.IsMMC)
185441e568d1Shuajun li 		info->HC_C_SIZE = (reg4b >> 8) & 0x3fffff;
185541e568d1Shuajun li 
185641e568d1Shuajun li 	info->SD_C_SIZE = ((tmpreg & 0x03) << 10) | (u16)(reg4b >> 22);
185741e568d1Shuajun li 	info->SD_C_SIZE_MULT = (u8)(reg4b >> 7)  & 0x07;
185841e568d1Shuajun li 	if (info->SD_Status.HiCapacity && info->SD_Status.IsMMC)
185941e568d1Shuajun li 		info->HC_C_SIZE = *(u32 *)(&buf[0x100]);
186041e568d1Shuajun li 
186141e568d1Shuajun li 	if (info->SD_READ_BL_LEN > SD_BLOCK_LEN) {
186241e568d1Shuajun li 		info->SD_Block_Mult = 1 << (info->SD_READ_BL_LEN-SD_BLOCK_LEN);
186341e568d1Shuajun li 		info->SD_READ_BL_LEN = SD_BLOCK_LEN;
186441e568d1Shuajun li 	} else {
186541e568d1Shuajun li 		info->SD_Block_Mult = 1;
186641e568d1Shuajun li 	}
186741e568d1Shuajun li 
186841e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
186941e568d1Shuajun li }
187041e568d1Shuajun li 
187141e568d1Shuajun li static int ene_load_bincode(struct us_data *us, unsigned char flag)
187241e568d1Shuajun li {
187341e568d1Shuajun li 	int err;
187441e568d1Shuajun li 	char *fw_name = NULL;
187541e568d1Shuajun li 	unsigned char *buf = NULL;
187641e568d1Shuajun li 	const struct firmware *sd_fw = NULL;
187741e568d1Shuajun li 	int result = USB_STOR_TRANSPORT_ERROR;
187841e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
187941e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
188041e568d1Shuajun li 
188141e568d1Shuajun li 	if (info->BIN_FLAG == flag)
188241e568d1Shuajun li 		return USB_STOR_TRANSPORT_GOOD;
188341e568d1Shuajun li 
188441e568d1Shuajun li 	switch (flag) {
188541e568d1Shuajun li 	/* For SD */
188641e568d1Shuajun li 	case SD_INIT1_PATTERN:
1887191648d0SJoe Perches 		usb_stor_dbg(us, "SD_INIT1_PATTERN\n");
1888595c8970STim Gardner 		fw_name = SD_INIT1_FIRMWARE;
188941e568d1Shuajun li 		break;
189041e568d1Shuajun li 	case SD_INIT2_PATTERN:
1891191648d0SJoe Perches 		usb_stor_dbg(us, "SD_INIT2_PATTERN\n");
1892595c8970STim Gardner 		fw_name = SD_INIT2_FIRMWARE;
189341e568d1Shuajun li 		break;
189441e568d1Shuajun li 	case SD_RW_PATTERN:
1895191648d0SJoe Perches 		usb_stor_dbg(us, "SD_RW_PATTERN\n");
1896595c8970STim Gardner 		fw_name = SD_RW_FIRMWARE;
189741e568d1Shuajun li 		break;
189833842cedSCho, Yu-Chen 	/* For MS */
189933842cedSCho, Yu-Chen 	case MS_INIT_PATTERN:
1900191648d0SJoe Perches 		usb_stor_dbg(us, "MS_INIT_PATTERN\n");
1901595c8970STim Gardner 		fw_name = MS_INIT_FIRMWARE;
190233842cedSCho, Yu-Chen 		break;
190333842cedSCho, Yu-Chen 	case MSP_RW_PATTERN:
1904191648d0SJoe Perches 		usb_stor_dbg(us, "MSP_RW_PATTERN\n");
1905595c8970STim Gardner 		fw_name = MSP_RW_FIRMWARE;
190633842cedSCho, Yu-Chen 		break;
190733842cedSCho, Yu-Chen 	case MS_RW_PATTERN:
1908191648d0SJoe Perches 		usb_stor_dbg(us, "MS_RW_PATTERN\n");
1909595c8970STim Gardner 		fw_name = MS_RW_FIRMWARE;
191033842cedSCho, Yu-Chen 		break;
191141e568d1Shuajun li 	default:
1912191648d0SJoe Perches 		usb_stor_dbg(us, "----------- Unknown PATTERN ----------\n");
191341e568d1Shuajun li 		goto nofw;
191441e568d1Shuajun li 	}
191541e568d1Shuajun li 
191641e568d1Shuajun li 	err = request_firmware(&sd_fw, fw_name, &us->pusb_dev->dev);
191741e568d1Shuajun li 	if (err) {
1918191648d0SJoe Perches 		usb_stor_dbg(us, "load firmware %s failed\n", fw_name);
191941e568d1Shuajun li 		goto nofw;
192041e568d1Shuajun li 	}
1921a328512dSBenoit Taine 	buf = kmemdup(sd_fw->data, sd_fw->size, GFP_KERNEL);
1922191648d0SJoe Perches 	if (buf == NULL)
192341e568d1Shuajun li 		goto nofw;
1924191648d0SJoe Perches 
192541e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
192641e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
192741e568d1Shuajun li 	bcb->DataTransferLength = sd_fw->size;
192841e568d1Shuajun li 	bcb->Flags = 0x00;
192941e568d1Shuajun li 	bcb->CDB[0] = 0xEF;
193041e568d1Shuajun li 
193141e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_WRITE, buf, 0);
1932aa18c4b6SAlan Stern 	if (us->srb != NULL)
1933aa18c4b6SAlan Stern 		scsi_set_resid(us->srb, 0);
193441e568d1Shuajun li 	info->BIN_FLAG = flag;
193541e568d1Shuajun li 	kfree(buf);
193641e568d1Shuajun li 
193741e568d1Shuajun li nofw:
193841e568d1Shuajun li 	release_firmware(sd_fw);
193941e568d1Shuajun li 	return result;
194041e568d1Shuajun li }
194141e568d1Shuajun li 
194233842cedSCho, Yu-Chen static int ms_card_init(struct us_data *us)
194333842cedSCho, Yu-Chen {
194433842cedSCho, Yu-Chen 	u32 result;
194533842cedSCho, Yu-Chen 	u16 TmpBlock;
194633842cedSCho, Yu-Chen 	unsigned char *PageBuffer0 = NULL, *PageBuffer1 = NULL;
194733842cedSCho, Yu-Chen 	struct ms_lib_type_extdat extdat;
194833842cedSCho, Yu-Chen 	u16 btBlk1st, btBlk2nd;
194933842cedSCho, Yu-Chen 	u32 btBlk1stErred;
195033842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
195133842cedSCho, Yu-Chen 
195233842cedSCho, Yu-Chen 	printk(KERN_INFO "MS_CardInit start\n");
195333842cedSCho, Yu-Chen 
195433842cedSCho, Yu-Chen 	ms_lib_free_allocatedarea(us); /* Clean buffer and set struct us_data flag to 0 */
195533842cedSCho, Yu-Chen 
195633842cedSCho, Yu-Chen 	/* get two PageBuffer */
195733842cedSCho, Yu-Chen 	PageBuffer0 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
195833842cedSCho, Yu-Chen 	PageBuffer1 = kmalloc(MS_BYTES_PER_PAGE, GFP_KERNEL);
195933842cedSCho, Yu-Chen 	if ((PageBuffer0 == NULL) || (PageBuffer1 == NULL)) {
196033842cedSCho, Yu-Chen 		result = MS_NO_MEMORY_ERROR;
196133842cedSCho, Yu-Chen 		goto exit;
196233842cedSCho, Yu-Chen 	}
196333842cedSCho, Yu-Chen 
196433842cedSCho, Yu-Chen 	btBlk1st = btBlk2nd = MS_LB_NOT_USED;
196533842cedSCho, Yu-Chen 	btBlk1stErred = 0;
196633842cedSCho, Yu-Chen 
196733842cedSCho, Yu-Chen 	for (TmpBlock = 0; TmpBlock < MS_MAX_INITIAL_ERROR_BLOCKS+2; TmpBlock++) {
196833842cedSCho, Yu-Chen 
196933842cedSCho, Yu-Chen 		switch (ms_read_readpage(us, TmpBlock, 0, (u32 *)PageBuffer0, &extdat)) {
197033842cedSCho, Yu-Chen 		case MS_STATUS_SUCCESS:
197133842cedSCho, Yu-Chen 			break;
197233842cedSCho, Yu-Chen 		case MS_STATUS_INT_ERROR:
197333842cedSCho, Yu-Chen 			break;
197433842cedSCho, Yu-Chen 		case MS_STATUS_ERROR:
197533842cedSCho, Yu-Chen 		default:
197633842cedSCho, Yu-Chen 			continue;
197733842cedSCho, Yu-Chen 		}
197833842cedSCho, Yu-Chen 
197933842cedSCho, Yu-Chen 		if ((extdat.ovrflg & MS_REG_OVR_BKST) == MS_REG_OVR_BKST_NG)
198033842cedSCho, Yu-Chen 			continue;
198133842cedSCho, Yu-Chen 
198233842cedSCho, Yu-Chen 		if (((extdat.mngflg & MS_REG_MNG_SYSFLG) == MS_REG_MNG_SYSFLG_USER) ||
198333842cedSCho, Yu-Chen 			(be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wBlockID) != MS_BOOT_BLOCK_ID) ||
198433842cedSCho, Yu-Chen 			(be16_to_cpu(((struct ms_bootblock_page0 *)PageBuffer0)->header.wFormatVersion) != MS_BOOT_BLOCK_FORMAT_VERSION) ||
198533842cedSCho, Yu-Chen 			(((struct ms_bootblock_page0 *)PageBuffer0)->header.bNumberOfDataEntry != MS_BOOT_BLOCK_DATA_ENTRIES))
198633842cedSCho, Yu-Chen 				continue;
198733842cedSCho, Yu-Chen 
198833842cedSCho, Yu-Chen 		if (btBlk1st != MS_LB_NOT_USED) {
198933842cedSCho, Yu-Chen 			btBlk2nd = TmpBlock;
199033842cedSCho, Yu-Chen 			break;
199133842cedSCho, Yu-Chen 		}
199233842cedSCho, Yu-Chen 
199333842cedSCho, Yu-Chen 		btBlk1st = TmpBlock;
199433842cedSCho, Yu-Chen 		memcpy(PageBuffer1, PageBuffer0, MS_BYTES_PER_PAGE);
199533842cedSCho, Yu-Chen 		if (extdat.status1 & (MS_REG_ST1_DTER | MS_REG_ST1_EXER | MS_REG_ST1_FGER))
199633842cedSCho, Yu-Chen 			btBlk1stErred = 1;
199733842cedSCho, Yu-Chen 	}
199833842cedSCho, Yu-Chen 
199933842cedSCho, Yu-Chen 	if (btBlk1st == MS_LB_NOT_USED) {
200033842cedSCho, Yu-Chen 		result = MS_STATUS_ERROR;
200133842cedSCho, Yu-Chen 		goto exit;
200233842cedSCho, Yu-Chen 	}
200333842cedSCho, Yu-Chen 
200433842cedSCho, Yu-Chen 	/* write protect */
200533842cedSCho, Yu-Chen 	if ((extdat.status0 & MS_REG_ST0_WP) == MS_REG_ST0_WP_ON)
200633842cedSCho, Yu-Chen 		ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
200733842cedSCho, Yu-Chen 
200833842cedSCho, Yu-Chen 	result = MS_STATUS_ERROR;
200933842cedSCho, Yu-Chen 	/* 1st Boot Block */
201033842cedSCho, Yu-Chen 	if (btBlk1stErred == 0)
201133842cedSCho, Yu-Chen 		result = ms_lib_process_bootblock(us, btBlk1st, PageBuffer1);
201233842cedSCho, Yu-Chen 		/* 1st */
201333842cedSCho, Yu-Chen 	/* 2nd Boot Block */
201433842cedSCho, Yu-Chen 	if (result && (btBlk2nd != MS_LB_NOT_USED))
201533842cedSCho, Yu-Chen 		result = ms_lib_process_bootblock(us, btBlk2nd, PageBuffer0);
201633842cedSCho, Yu-Chen 
201733842cedSCho, Yu-Chen 	if (result) {
201833842cedSCho, Yu-Chen 		result = MS_STATUS_ERROR;
201933842cedSCho, Yu-Chen 		goto exit;
202033842cedSCho, Yu-Chen 	}
202133842cedSCho, Yu-Chen 
202233842cedSCho, Yu-Chen 	for (TmpBlock = 0; TmpBlock < btBlk1st; TmpBlock++)
202333842cedSCho, Yu-Chen 		info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
202433842cedSCho, Yu-Chen 
202533842cedSCho, Yu-Chen 	info->MS_Lib.Phy2LogMap[btBlk1st] = MS_LB_BOOT_BLOCK;
202633842cedSCho, Yu-Chen 
202733842cedSCho, Yu-Chen 	if (btBlk2nd != MS_LB_NOT_USED) {
202833842cedSCho, Yu-Chen 		for (TmpBlock = btBlk1st + 1; TmpBlock < btBlk2nd; TmpBlock++)
202933842cedSCho, Yu-Chen 			info->MS_Lib.Phy2LogMap[TmpBlock] = MS_LB_INITIAL_ERROR;
203033842cedSCho, Yu-Chen 
203133842cedSCho, Yu-Chen 		info->MS_Lib.Phy2LogMap[btBlk2nd] = MS_LB_BOOT_BLOCK;
203233842cedSCho, Yu-Chen 	}
203333842cedSCho, Yu-Chen 
203433842cedSCho, Yu-Chen 	result = ms_lib_scan_logicalblocknumber(us, btBlk1st);
203533842cedSCho, Yu-Chen 	if (result)
203633842cedSCho, Yu-Chen 		goto exit;
203733842cedSCho, Yu-Chen 
203833842cedSCho, Yu-Chen 	for (TmpBlock = MS_PHYSICAL_BLOCKS_PER_SEGMENT;
203933842cedSCho, Yu-Chen 		TmpBlock < info->MS_Lib.NumberOfPhyBlock;
204033842cedSCho, Yu-Chen 		TmpBlock += MS_PHYSICAL_BLOCKS_PER_SEGMENT) {
204133842cedSCho, Yu-Chen 		if (ms_count_freeblock(us, TmpBlock) == 0) {
204233842cedSCho, Yu-Chen 			ms_lib_ctrl_set(info, MS_LIB_CTRL_WRPROTECT);
204333842cedSCho, Yu-Chen 			break;
204433842cedSCho, Yu-Chen 		}
204533842cedSCho, Yu-Chen 	}
204633842cedSCho, Yu-Chen 
204733842cedSCho, Yu-Chen 	/* write */
204833842cedSCho, Yu-Chen 	if (ms_lib_alloc_writebuf(us)) {
204933842cedSCho, Yu-Chen 		result = MS_NO_MEMORY_ERROR;
205033842cedSCho, Yu-Chen 		goto exit;
205133842cedSCho, Yu-Chen 	}
205233842cedSCho, Yu-Chen 
205333842cedSCho, Yu-Chen 	result = MS_STATUS_SUCCESS;
205433842cedSCho, Yu-Chen 
205533842cedSCho, Yu-Chen exit:
205633842cedSCho, Yu-Chen 	kfree(PageBuffer1);
205733842cedSCho, Yu-Chen 	kfree(PageBuffer0);
205833842cedSCho, Yu-Chen 
205933842cedSCho, Yu-Chen 	printk(KERN_INFO "MS_CardInit end\n");
206033842cedSCho, Yu-Chen 	return result;
206133842cedSCho, Yu-Chen }
206233842cedSCho, Yu-Chen 
206333842cedSCho, Yu-Chen static int ene_ms_init(struct us_data *us)
206433842cedSCho, Yu-Chen {
206533842cedSCho, Yu-Chen 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
206633842cedSCho, Yu-Chen 	int result;
206733842cedSCho, Yu-Chen 	u8 buf[0x200];
206833842cedSCho, Yu-Chen 	u16 MSP_BlockSize, MSP_UserAreaBlocks;
206933842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
207033842cedSCho, Yu-Chen 
207133842cedSCho, Yu-Chen 	printk(KERN_INFO "transport --- ENE_MSInit\n");
207233842cedSCho, Yu-Chen 
207333842cedSCho, Yu-Chen 	/* the same part to test ENE */
207433842cedSCho, Yu-Chen 
207533842cedSCho, Yu-Chen 	result = ene_load_bincode(us, MS_INIT_PATTERN);
207633842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD) {
207733842cedSCho, Yu-Chen 		printk(KERN_ERR "Load MS Init Code Fail !!\n");
207833842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
207933842cedSCho, Yu-Chen 	}
208033842cedSCho, Yu-Chen 
208133842cedSCho, Yu-Chen 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
208233842cedSCho, Yu-Chen 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
208333842cedSCho, Yu-Chen 	bcb->DataTransferLength = 0x200;
2084b8db6d64SSebastian Andrzej Siewior 	bcb->Flags      = US_BULK_FLAG_IN;
208533842cedSCho, Yu-Chen 	bcb->CDB[0]     = 0xF1;
208633842cedSCho, Yu-Chen 	bcb->CDB[1]     = 0x01;
208733842cedSCho, Yu-Chen 
208833842cedSCho, Yu-Chen 	result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
208933842cedSCho, Yu-Chen 	if (result != USB_STOR_XFER_GOOD) {
209033842cedSCho, Yu-Chen 		printk(KERN_ERR "Execution MS Init Code Fail !!\n");
209133842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
209233842cedSCho, Yu-Chen 	}
209333842cedSCho, Yu-Chen 	/* the same part to test ENE */
209433842cedSCho, Yu-Chen 	info->MS_Status = *(struct MS_STATUS *)&buf[0];
209533842cedSCho, Yu-Chen 
209633842cedSCho, Yu-Chen 	if (info->MS_Status.Insert && info->MS_Status.Ready) {
209733842cedSCho, Yu-Chen 		printk(KERN_INFO "Insert     = %x\n", info->MS_Status.Insert);
209833842cedSCho, Yu-Chen 		printk(KERN_INFO "Ready      = %x\n", info->MS_Status.Ready);
209933842cedSCho, Yu-Chen 		printk(KERN_INFO "IsMSPro    = %x\n", info->MS_Status.IsMSPro);
210033842cedSCho, Yu-Chen 		printk(KERN_INFO "IsMSPHG    = %x\n", info->MS_Status.IsMSPHG);
210133842cedSCho, Yu-Chen 		printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
210233842cedSCho, Yu-Chen 		if (info->MS_Status.IsMSPro) {
210333842cedSCho, Yu-Chen 			MSP_BlockSize      = (buf[6] << 8) | buf[7];
210433842cedSCho, Yu-Chen 			MSP_UserAreaBlocks = (buf[10] << 8) | buf[11];
210533842cedSCho, Yu-Chen 			info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
210633842cedSCho, Yu-Chen 		} else {
210733842cedSCho, Yu-Chen 			ms_card_init(us); /* Card is MS (to ms.c)*/
210833842cedSCho, Yu-Chen 		}
2109191648d0SJoe Perches 		usb_stor_dbg(us, "MS Init Code OK !!\n");
211033842cedSCho, Yu-Chen 	} else {
2111191648d0SJoe Perches 		usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]);
211233842cedSCho, Yu-Chen 		return USB_STOR_TRANSPORT_ERROR;
211333842cedSCho, Yu-Chen 	}
211433842cedSCho, Yu-Chen 
211533842cedSCho, Yu-Chen 	return USB_STOR_TRANSPORT_GOOD;
211633842cedSCho, Yu-Chen }
211733842cedSCho, Yu-Chen 
211841e568d1Shuajun li static int ene_sd_init(struct us_data *us)
211941e568d1Shuajun li {
212041e568d1Shuajun li 	int result;
212141e568d1Shuajun li 	u8  buf[0x200];
212241e568d1Shuajun li 	struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
212341e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
212441e568d1Shuajun li 
2125191648d0SJoe Perches 	usb_stor_dbg(us, "transport --- ENE_SDInit\n");
212641e568d1Shuajun li 	/* SD Init Part-1 */
212741e568d1Shuajun li 	result = ene_load_bincode(us, SD_INIT1_PATTERN);
212841e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
2129191648d0SJoe Perches 		usb_stor_dbg(us, "Load SD Init Code Part-1 Fail !!\n");
213041e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
213141e568d1Shuajun li 	}
213241e568d1Shuajun li 
213341e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
213441e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
2135b8db6d64SSebastian Andrzej Siewior 	bcb->Flags = US_BULK_FLAG_IN;
213641e568d1Shuajun li 	bcb->CDB[0] = 0xF2;
213741e568d1Shuajun li 
213841e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, NULL, 0);
213941e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
2140191648d0SJoe Perches 		usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
214141e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
214241e568d1Shuajun li 	}
214341e568d1Shuajun li 
214441e568d1Shuajun li 	/* SD Init Part-2 */
214541e568d1Shuajun li 	result = ene_load_bincode(us, SD_INIT2_PATTERN);
214641e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
2147191648d0SJoe Perches 		usb_stor_dbg(us, "Load SD Init Code Part-2 Fail !!\n");
214841e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
214941e568d1Shuajun li 	}
215041e568d1Shuajun li 
215141e568d1Shuajun li 	memset(bcb, 0, sizeof(struct bulk_cb_wrap));
215241e568d1Shuajun li 	bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
215341e568d1Shuajun li 	bcb->DataTransferLength = 0x200;
2154b8db6d64SSebastian Andrzej Siewior 	bcb->Flags              = US_BULK_FLAG_IN;
215541e568d1Shuajun li 	bcb->CDB[0]             = 0xF1;
215641e568d1Shuajun li 
215741e568d1Shuajun li 	result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0);
215841e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
2159191648d0SJoe Perches 		usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
216041e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
216141e568d1Shuajun li 	}
216241e568d1Shuajun li 
216341e568d1Shuajun li 	info->SD_Status =  *(struct SD_STATUS *)&buf[0];
216441e568d1Shuajun li 	if (info->SD_Status.Insert && info->SD_Status.Ready) {
2165191648d0SJoe Perches 		struct SD_STATUS *s = &info->SD_Status;
2166191648d0SJoe Perches 
216741e568d1Shuajun li 		ene_get_card_status(us, (unsigned char *)&buf);
2168191648d0SJoe Perches 		usb_stor_dbg(us, "Insert     = %x\n", s->Insert);
2169191648d0SJoe Perches 		usb_stor_dbg(us, "Ready      = %x\n", s->Ready);
2170191648d0SJoe Perches 		usb_stor_dbg(us, "IsMMC      = %x\n", s->IsMMC);
2171191648d0SJoe Perches 		usb_stor_dbg(us, "HiCapacity = %x\n", s->HiCapacity);
2172191648d0SJoe Perches 		usb_stor_dbg(us, "HiSpeed    = %x\n", s->HiSpeed);
2173191648d0SJoe Perches 		usb_stor_dbg(us, "WtP        = %x\n", s->WtP);
217441e568d1Shuajun li 	} else {
2175191648d0SJoe Perches 		usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]);
217641e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
217741e568d1Shuajun li 	}
217841e568d1Shuajun li 	return USB_STOR_TRANSPORT_GOOD;
217941e568d1Shuajun li }
218041e568d1Shuajun li 
218141e568d1Shuajun li 
218241e568d1Shuajun li static int ene_init(struct us_data *us)
218341e568d1Shuajun li {
218441e568d1Shuajun li 	int result;
218541e568d1Shuajun li 	u8  misc_reg03 = 0;
218641e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
218741e568d1Shuajun li 
218841e568d1Shuajun li 	result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
218941e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD)
219041e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
219141e568d1Shuajun li 
219241e568d1Shuajun li 	if (misc_reg03 & 0x01) {
219341e568d1Shuajun li 		if (!info->SD_Status.Ready) {
219441e568d1Shuajun li 			result = ene_sd_init(us);
219541e568d1Shuajun li 			if (result != USB_STOR_XFER_GOOD)
219641e568d1Shuajun li 				return USB_STOR_TRANSPORT_ERROR;
219741e568d1Shuajun li 		}
219841e568d1Shuajun li 	}
219933842cedSCho, Yu-Chen 	if (misc_reg03 & 0x02) {
220033842cedSCho, Yu-Chen 		if (!info->MS_Status.Ready) {
220133842cedSCho, Yu-Chen 			result = ene_ms_init(us);
220233842cedSCho, Yu-Chen 			if (result != USB_STOR_XFER_GOOD)
220333842cedSCho, Yu-Chen 				return USB_STOR_TRANSPORT_ERROR;
220433842cedSCho, Yu-Chen 		}
220533842cedSCho, Yu-Chen 	}
220641e568d1Shuajun li 	return result;
220741e568d1Shuajun li }
220841e568d1Shuajun li 
220941e568d1Shuajun li /*----- sd_scsi_irp() ---------*/
221041e568d1Shuajun li static int sd_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
221141e568d1Shuajun li {
221241e568d1Shuajun li 	int    result;
221341e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
221441e568d1Shuajun li 
221541e568d1Shuajun li 	info->SrbStatus = SS_SUCCESS;
221641e568d1Shuajun li 	switch (srb->cmnd[0]) {
221741e568d1Shuajun li 	case TEST_UNIT_READY:
221841e568d1Shuajun li 		result = sd_scsi_test_unit_ready(us, srb);
221941e568d1Shuajun li 		break; /* 0x00 */
222041e568d1Shuajun li 	case INQUIRY:
222141e568d1Shuajun li 		result = sd_scsi_inquiry(us, srb);
222241e568d1Shuajun li 		break; /* 0x12 */
222341e568d1Shuajun li 	case MODE_SENSE:
222441e568d1Shuajun li 		result = sd_scsi_mode_sense(us, srb);
222541e568d1Shuajun li 		break; /* 0x1A */
222641e568d1Shuajun li 	/*
222741e568d1Shuajun li 	case START_STOP:
222841e568d1Shuajun li 		result = SD_SCSI_Start_Stop(us, srb);
222941e568d1Shuajun li 		break; //0x1B
223041e568d1Shuajun li 	*/
223141e568d1Shuajun li 	case READ_CAPACITY:
223241e568d1Shuajun li 		result = sd_scsi_read_capacity(us, srb);
223341e568d1Shuajun li 		break; /* 0x25 */
223441e568d1Shuajun li 	case READ_10:
223541e568d1Shuajun li 		result = sd_scsi_read(us, srb);
223641e568d1Shuajun li 		break; /* 0x28 */
223741e568d1Shuajun li 	case WRITE_10:
223841e568d1Shuajun li 		result = sd_scsi_write(us, srb);
223941e568d1Shuajun li 		break; /* 0x2A */
224041e568d1Shuajun li 	default:
224141e568d1Shuajun li 		info->SrbStatus = SS_ILLEGAL_REQUEST;
224241e568d1Shuajun li 		result = USB_STOR_TRANSPORT_FAILED;
224341e568d1Shuajun li 		break;
224441e568d1Shuajun li 	}
224541e568d1Shuajun li 	return result;
224641e568d1Shuajun li }
224741e568d1Shuajun li 
224833842cedSCho, Yu-Chen /*
224933842cedSCho, Yu-Chen  * ms_scsi_irp()
225033842cedSCho, Yu-Chen  */
225136f3a14dSFelipe Balbi static int ms_scsi_irp(struct us_data *us, struct scsi_cmnd *srb)
225233842cedSCho, Yu-Chen {
225333842cedSCho, Yu-Chen 	int result;
225433842cedSCho, Yu-Chen 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)us->extra;
225533842cedSCho, Yu-Chen 	info->SrbStatus = SS_SUCCESS;
225633842cedSCho, Yu-Chen 	switch (srb->cmnd[0]) {
225733842cedSCho, Yu-Chen 	case TEST_UNIT_READY:
225833842cedSCho, Yu-Chen 		result = ms_scsi_test_unit_ready(us, srb);
225933842cedSCho, Yu-Chen 		break; /* 0x00 */
226033842cedSCho, Yu-Chen 	case INQUIRY:
226133842cedSCho, Yu-Chen 		result = ms_scsi_inquiry(us, srb);
226233842cedSCho, Yu-Chen 		break; /* 0x12 */
226333842cedSCho, Yu-Chen 	case MODE_SENSE:
226433842cedSCho, Yu-Chen 		result = ms_scsi_mode_sense(us, srb);
226533842cedSCho, Yu-Chen 		break; /* 0x1A */
226633842cedSCho, Yu-Chen 	case READ_CAPACITY:
226733842cedSCho, Yu-Chen 		result = ms_scsi_read_capacity(us, srb);
226833842cedSCho, Yu-Chen 		break; /* 0x25 */
226933842cedSCho, Yu-Chen 	case READ_10:
227033842cedSCho, Yu-Chen 		result = ms_scsi_read(us, srb);
227133842cedSCho, Yu-Chen 		break; /* 0x28 */
227233842cedSCho, Yu-Chen 	case WRITE_10:
227333842cedSCho, Yu-Chen 		result = ms_scsi_write(us, srb);
227433842cedSCho, Yu-Chen 		break;  /* 0x2A */
227533842cedSCho, Yu-Chen 	default:
227633842cedSCho, Yu-Chen 		info->SrbStatus = SS_ILLEGAL_REQUEST;
227733842cedSCho, Yu-Chen 		result = USB_STOR_TRANSPORT_FAILED;
227833842cedSCho, Yu-Chen 		break;
227933842cedSCho, Yu-Chen 	}
228033842cedSCho, Yu-Chen 	return result;
228133842cedSCho, Yu-Chen }
228233842cedSCho, Yu-Chen 
228341e568d1Shuajun li static int ene_transport(struct scsi_cmnd *srb, struct us_data *us)
228441e568d1Shuajun li {
22854b309f1cSAlan Stern 	int result = USB_STOR_XFER_GOOD;
228641e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
228741e568d1Shuajun li 
2288191648d0SJoe Perches 	/*US_DEBUG(usb_stor_show_command(us, srb)); */
228941e568d1Shuajun li 	scsi_set_resid(srb, 0);
22904b309f1cSAlan Stern 	if (unlikely(!(info->SD_Status.Ready || info->MS_Status.Ready)))
229141e568d1Shuajun li 		result = ene_init(us);
22924b309f1cSAlan Stern 	if (result == USB_STOR_XFER_GOOD) {
22934b309f1cSAlan Stern 		result = USB_STOR_TRANSPORT_ERROR;
229433842cedSCho, Yu-Chen 		if (info->SD_Status.Ready)
229541e568d1Shuajun li 			result = sd_scsi_irp(us, srb);
229641e568d1Shuajun li 
229733842cedSCho, Yu-Chen 		if (info->MS_Status.Ready)
229833842cedSCho, Yu-Chen 			result = ms_scsi_irp(us, srb);
229933842cedSCho, Yu-Chen 	}
23004b309f1cSAlan Stern 	return result;
230141e568d1Shuajun li }
230241e568d1Shuajun li 
2303aa519be3SAkinobu Mita static struct scsi_host_template ene_ub6250_host_template;
230441e568d1Shuajun li 
230541e568d1Shuajun li static int ene_ub6250_probe(struct usb_interface *intf,
230641e568d1Shuajun li 			 const struct usb_device_id *id)
230741e568d1Shuajun li {
230841e568d1Shuajun li 	int result;
230941e568d1Shuajun li 	u8  misc_reg03 = 0;
231041e568d1Shuajun li 	struct us_data *us;
231141e568d1Shuajun li 
231241e568d1Shuajun li 	result = usb_stor_probe1(&us, intf, id,
2313aa519be3SAkinobu Mita 		   (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
2314aa519be3SAkinobu Mita 		   &ene_ub6250_host_template);
231541e568d1Shuajun li 	if (result)
231641e568d1Shuajun li 		return result;
231741e568d1Shuajun li 
231841e568d1Shuajun li 	/* FIXME: where should the code alloc extra buf ? */
231941e568d1Shuajun li 	if (!us->extra) {
232041e568d1Shuajun li 		us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
232141e568d1Shuajun li 		if (!us->extra)
232241e568d1Shuajun li 			return -ENOMEM;
232341e568d1Shuajun li 		us->extra_destructor = ene_ub6250_info_destructor;
232441e568d1Shuajun li 	}
232541e568d1Shuajun li 
232641e568d1Shuajun li 	us->transport_name = "ene_ub6250";
232741e568d1Shuajun li 	us->transport = ene_transport;
232841e568d1Shuajun li 	us->max_lun = 0;
232941e568d1Shuajun li 
233041e568d1Shuajun li 	result = usb_stor_probe2(us);
233141e568d1Shuajun li 	if (result)
233241e568d1Shuajun li 		return result;
233341e568d1Shuajun li 
233441e568d1Shuajun li 	/* probe card type */
233541e568d1Shuajun li 	result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03);
233641e568d1Shuajun li 	if (result != USB_STOR_XFER_GOOD) {
233741e568d1Shuajun li 		usb_stor_disconnect(intf);
233841e568d1Shuajun li 		return USB_STOR_TRANSPORT_ERROR;
233941e568d1Shuajun li 	}
234041e568d1Shuajun li 
234141e568d1Shuajun li 	if (!(misc_reg03 & 0x01)) {
234216fae052SKristina Martšenko 		pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
234316fae052SKristina Martšenko 			"It does not support SM cards.\n");
234441e568d1Shuajun li 	}
234541e568d1Shuajun li 
234641e568d1Shuajun li 	return result;
234741e568d1Shuajun li }
234841e568d1Shuajun li 
234941e568d1Shuajun li 
235041e568d1Shuajun li #ifdef CONFIG_PM
235141e568d1Shuajun li 
235241e568d1Shuajun li static int ene_ub6250_resume(struct usb_interface *iface)
235341e568d1Shuajun li {
235441e568d1Shuajun li 	u8 tmp = 0;
235541e568d1Shuajun li 	struct us_data *us = usb_get_intfdata(iface);
235641e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
235741e568d1Shuajun li 
235841e568d1Shuajun li 	mutex_lock(&us->dev_mutex);
235941e568d1Shuajun li 
236041e568d1Shuajun li 	if (us->suspend_resume_hook)
236141e568d1Shuajun li 		(us->suspend_resume_hook)(us, US_RESUME);
236241e568d1Shuajun li 
236341e568d1Shuajun li 	mutex_unlock(&us->dev_mutex);
236441e568d1Shuajun li 
236541e568d1Shuajun li 	info->Power_IsResum = true;
236641e568d1Shuajun li 	/*info->SD_Status.Ready = 0; */
236741e568d1Shuajun li 	info->SD_Status = *(struct SD_STATUS *)&tmp;
236841e568d1Shuajun li 	info->MS_Status = *(struct MS_STATUS *)&tmp;
236941e568d1Shuajun li 	info->SM_Status = *(struct SM_STATUS *)&tmp;
237041e568d1Shuajun li 
237141e568d1Shuajun li 	return 0;
237241e568d1Shuajun li }
237341e568d1Shuajun li 
237441e568d1Shuajun li static int ene_ub6250_reset_resume(struct usb_interface *iface)
237541e568d1Shuajun li {
237641e568d1Shuajun li 	u8 tmp = 0;
237741e568d1Shuajun li 	struct us_data *us = usb_get_intfdata(iface);
237841e568d1Shuajun li 	struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
2379191648d0SJoe Perches 
238041e568d1Shuajun li 	/* Report the reset to the SCSI core */
238141e568d1Shuajun li 	usb_stor_reset_resume(iface);
238241e568d1Shuajun li 
2383f0183a33SFelipe Balbi 	/*
2384f0183a33SFelipe Balbi 	 * FIXME: Notify the subdrivers that they need to reinitialize
2385f0183a33SFelipe Balbi 	 * the device
2386f0183a33SFelipe Balbi 	 */
238741e568d1Shuajun li 	info->Power_IsResum = true;
238841e568d1Shuajun li 	/*info->SD_Status.Ready = 0; */
238941e568d1Shuajun li 	info->SD_Status = *(struct SD_STATUS *)&tmp;
239041e568d1Shuajun li 	info->MS_Status = *(struct MS_STATUS *)&tmp;
239141e568d1Shuajun li 	info->SM_Status = *(struct SM_STATUS *)&tmp;
239241e568d1Shuajun li 
239341e568d1Shuajun li 	return 0;
239441e568d1Shuajun li }
239541e568d1Shuajun li 
239641e568d1Shuajun li #else
239741e568d1Shuajun li 
239841e568d1Shuajun li #define ene_ub6250_resume		NULL
239941e568d1Shuajun li #define ene_ub6250_reset_resume		NULL
240041e568d1Shuajun li 
240141e568d1Shuajun li #endif
240241e568d1Shuajun li 
240341e568d1Shuajun li static struct usb_driver ene_ub6250_driver = {
2404aa519be3SAkinobu Mita 	.name =		DRV_NAME,
240541e568d1Shuajun li 	.probe =	ene_ub6250_probe,
240641e568d1Shuajun li 	.disconnect =	usb_stor_disconnect,
240741e568d1Shuajun li 	.suspend =	usb_stor_suspend,
240841e568d1Shuajun li 	.resume =	ene_ub6250_resume,
240941e568d1Shuajun li 	.reset_resume =	ene_ub6250_reset_resume,
241041e568d1Shuajun li 	.pre_reset =	usb_stor_pre_reset,
241141e568d1Shuajun li 	.post_reset =	usb_stor_post_reset,
241241e568d1Shuajun li 	.id_table =	ene_ub6250_usb_ids,
241341e568d1Shuajun li 	.soft_unbind =	1,
2414e73b2db6SHuajun Li 	.no_dynamic_id = 1,
241541e568d1Shuajun li };
241641e568d1Shuajun li 
2417aa519be3SAkinobu Mita module_usb_stor_driver(ene_ub6250_driver, ene_ub6250_host_template, DRV_NAME);
2418