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