Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
4bc91a02
Commit
4bc91a02
authored
Apr 30, 2002
by
Andries E. Brouwer
Committed by
Greg Kroah-Hartman
Apr 30, 2002
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[PATCH] sddr09 write capability
USB sddr09 The main purpose of the patch is to add write capability.
parent
7adcd3c4
Changes
9
Show whitespace changes
Inline
Side-by-side
Showing
9 changed files
with
1335 additions
and
560 deletions
+1335
-560
drivers/scsi/sd.c
drivers/scsi/sd.c
+7
-1
drivers/usb/storage/Config.help
drivers/usb/storage/Config.help
+7
-3
drivers/usb/storage/Config.in
drivers/usb/storage/Config.in
+1
-1
drivers/usb/storage/debug.c
drivers/usb/storage/debug.c
+1
-0
drivers/usb/storage/initializers.h
drivers/usb/storage/initializers.h
+5
-0
drivers/usb/storage/jumpshot.c
drivers/usb/storage/jumpshot.c
+1
-1
drivers/usb/storage/sddr09.c
drivers/usb/storage/sddr09.c
+1307
-552
drivers/usb/storage/sddr09.h
drivers/usb/storage/sddr09.h
+4
-0
drivers/usb/storage/unusual_devs.h
drivers/usb/storage/unusual_devs.h
+2
-2
No files found.
drivers/scsi/sd.c
View file @
4bc91a02
...
...
@@ -1005,6 +1005,10 @@ static int sd_init_onedisk(int i)
* we're only interested in the header anyway, this should
* be fine.
* -- Matthew Dharm (mdharm-scsi@one-eyed-alien.net)
*
* As it turns out, some devices return an error for
* every MODE_SENSE request except one for page 0.
* So, we should also try that. --aeb
*/
memset
((
void
*
)
&
cmd
[
0
],
0
,
8
);
...
...
@@ -1025,7 +1029,9 @@ static int sd_init_onedisk(int i)
the_result
=
SRpnt
->
sr_result
;
if
(
the_result
)
{
printk
(
"%s: test WP failed, assume Write Enabled
\n
"
,
nbuff
);
printk
(
"%s: test WP failed, assume Write Enabled
\n
"
,
nbuff
);
/* alternatively, try page 0 */
}
else
{
rscsi_disks
[
i
].
write_prot
=
((
buffer
[
2
]
&
0x80
)
!=
0
);
printk
(
"%s: Write Protect is %s
\n
"
,
nbuff
,
...
...
drivers/usb/storage/Config.help
View file @
4bc91a02
...
...
@@ -28,11 +28,15 @@ CONFIG_USB_STORAGE_FREECOM
Support for the Freecom USB to IDE/ATAPI adaptor.
Freecom has a web page at <http://www.freecom.de/>.
CONFIG_USB_STORAGE_DATAFAB
Support for certain Datafab CompactFlash readers.
Datafab has a web page at <http://www.datafabusa.com/>.
CONFIG_USB_STORAGE_DPCM
Say Y here to support the Microtech ZiO! CompactFlash/SmartMedia
reader, details at <http://www.microtechint.com/zio/index.html>.
This driver treats the flash card as a removable storage device.
Say Y here to support the Microtech ZiO! CompactFlash reader.
There is a web page at <http://www.microtechint.com/zio/index.html>.
CONFIG_USB_STORAGE_SDDR09
Say Y here to include additional code to support the Sandisk SDDR-09
SmartMedia reader in the USB Mass Storage driver.
Also works for the Microtech Zio! SmartMedia reader.
drivers/usb/storage/Config.in
View file @
4bc91a02
...
...
@@ -6,7 +6,7 @@ if [ "$CONFIG_SCSI" = "n" ]; then
fi
dep_tristate ' USB Mass Storage support' CONFIG_USB_STORAGE $CONFIG_USB $CONFIG_SCSI
dep_mbool ' USB Mass Storage verbose debug' CONFIG_USB_STORAGE_DEBUG $CONFIG_USB_STORAGE
dep_mbool ' Datafab
MDCFE-B
Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
dep_mbool ' Datafab Compact Flash Reader support' CONFIG_USB_STORAGE_DATAFAB $CONFIG_USB_STORAGE $CONFIG_EXPERIMENTAL
dep_mbool ' Freecom USB/ATAPI Bridge support' CONFIG_USB_STORAGE_FREECOM $CONFIG_USB_STORAGE
dep_mbool ' ISD-200 USB/ATA Bridge support' CONFIG_USB_STORAGE_ISD200 $CONFIG_USB_STORAGE
dep_mbool ' Microtech CompactFlash/SmartMedia support' CONFIG_USB_STORAGE_DPCM $CONFIG_USB_STORAGE
...
...
drivers/usb/storage/debug.c
View file @
4bc91a02
...
...
@@ -327,6 +327,7 @@ void usb_stor_show_sense(
case
0x3502
:
what
=
"enclosure services unavailable"
;
break
;
case
0x3503
:
what
=
"enclosure services transfer failure"
;
break
;
case
0x3504
:
what
=
"enclosure services transfer refused"
;
break
;
case
0x3A00
:
what
=
"medium not present"
;
break
;
case
0x3B0F
:
what
=
"end of medium reached"
;
break
;
case
0x3F02
:
what
=
"changed operating definition"
;
break
;
case
0x4100
:
what
=
"data path failure (should use 40 NN)"
;
break
;
...
...
drivers/usb/storage/initializers.h
View file @
4bc91a02
...
...
@@ -37,8 +37,13 @@
* 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <linux/config.h>
#include "usb.h"
/* This places the Shuttle/SCM USB<->SCSI bridge devices in multi-target
* mode */
int
usb_stor_euscsi_init
(
struct
us_data
*
us
);
#ifdef CONFIG_USB_STORAGE_SDDR09
int
sddr09_init
(
struct
us_data
*
us
);
#endif
drivers/usb/storage/jumpshot.c
View file @
4bc91a02
...
...
@@ -192,7 +192,7 @@ static int jumpshot_raw_bulk(int direction,
return
US_BULK_TRANSFER_SHORT
;
}
US_DEBUGP
(
"jumpshot_raw_bulk: Transfered %d of %d bytes
\n
"
,
act_len
,
len
);
US_DEBUGP
(
"jumpshot_raw_bulk: Transfer
r
ed %d of %d bytes
\n
"
,
act_len
,
len
);
return
US_BULK_TRANSFER_GOOD
;
}
...
...
drivers/usb/storage/sddr09.c
View file @
4bc91a02
/* Driver for SanDisk SDDR-09 SmartMedia reader
*
* $Id: sddr09.c,v 1.22 2001/12/08 23:32:48 mdharm Exp $
*
* SDDR09 driver v0.1:
*
* First release
*
* Current development and maintenance by:
* (c) 2000, 2001 Robert Baruch (autophile@starband.net)
* (c) 2002 Andries Brouwer (aeb@cwi.nl)
*
* The SanDisk SDDR-09 SmartMedia reader uses the Shuttle EUSB-01 chip.
* This chip is a programmable USB controller. In the SDDR-09, it has
* been programmed to obey a certain limited set of SCSI commands.
This
* driver translates the "real" SCSI commands to the SDDR-09 SCSI
* been programmed to obey a certain limited set of SCSI commands.
*
This
driver translates the "real" SCSI commands to the SDDR-09 SCSI
* commands.
*
* This program is free software; you can redistribute it and/or modify it
...
...
@@ -44,6 +38,180 @@
#define LSB_of(s) ((s)&0xFF)
#define MSB_of(s) ((s)>>8)
/* #define US_DEBUGP printk */
/*
* First some stuff that does not belong here:
* data on SmartMedia and other cards, completely
* unrelated to this driver.
* Similar stuff occurs in <linux/mtd/nand_ids.h>.
*/
struct
nand_flash_dev
{
int
model_id
;
int
chipshift
;
/* 1<<cs bytes total capacity */
char
pageshift
;
/* 1<<ps bytes in a page */
char
blockshift
;
/* 1<<bs pages in an erase block */
char
zoneshift
;
/* 1<<zs blocks in a zone */
/* # of logical blocks is 125/128 of this */
char
pageadrlen
;
/* length of an address in bytes - 1 */
};
/*
* NAND Flash Manufacturer ID Codes
*/
#define NAND_MFR_AMD 0x01
#define NAND_MFR_TOSHIBA 0x98
#define NAND_MFR_SAMSUNG 0xec
static
inline
char
*
nand_flash_manufacturer
(
int
manuf_id
)
{
switch
(
manuf_id
)
{
case
NAND_MFR_AMD
:
return
"AMD"
;
case
NAND_MFR_TOSHIBA
:
return
"Toshiba"
;
case
NAND_MFR_SAMSUNG
:
return
"Samsung"
;
default:
return
"unknown"
;
}
}
/*
* It looks like it is unnecessary to attach manufacturer to the
* remaining data: SSFDC prescribes manufacturer-independent id codes.
*/
static
struct
nand_flash_dev
nand_flash_ids
[]
=
{
/* NAND flash - these I verified */
{
0x6e
,
20
,
8
,
4
,
8
,
2
},
/* 1 MB */
{
0xe8
,
20
,
8
,
4
,
8
,
2
},
/* 1 MB */
{
0xec
,
20
,
8
,
4
,
8
,
2
},
/* 1 MB */
{
0x64
,
21
,
8
,
4
,
9
,
2
},
/* 2 MB */
{
0xea
,
21
,
8
,
4
,
9
,
2
},
/* 2 MB */
{
0x6b
,
22
,
9
,
4
,
9
,
2
},
/* 4 MB */
{
0xe3
,
22
,
9
,
4
,
9
,
2
},
/* 4 MB */
{
0xe5
,
22
,
9
,
4
,
9
,
2
},
/* 4 MB */
{
0xe6
,
23
,
9
,
4
,
10
,
2
},
/* 8 MB */
{
0x73
,
24
,
9
,
5
,
10
,
2
},
/* 16 MB */
{
0x75
,
25
,
9
,
5
,
10
,
2
},
/* 32 MB */
{
0x76
,
26
,
9
,
5
,
10
,
3
},
/* 64 MB */
{
0x79
,
27
,
9
,
5
,
10
,
3
},
/* 128 MB */
/* There do also exist 96 MB (from Datafab) and 256 MB cards */
/* MASK ROM - from unknown source */
{
0x5d
,
21
,
9
,
4
,
8
,
2
},
/* 2 MB */
{
0xd5
,
22
,
9
,
4
,
9
,
2
},
/* 4 MB */
{
0xd6
,
23
,
9
,
4
,
10
,
2
},
/* 8 MB */
{
0
,}
};
#define SIZE(a) (sizeof(a)/sizeof((a)[0]))
static
struct
nand_flash_dev
*
nand_find_id
(
unsigned
char
id
)
{
int
i
;
for
(
i
=
0
;
i
<
SIZE
(
nand_flash_ids
);
i
++
)
if
(
nand_flash_ids
[
i
].
model_id
==
id
)
return
&
(
nand_flash_ids
[
i
]);
return
NULL
;
}
/*
* ECC computation.
*/
static
unsigned
char
parity
[
256
];
static
unsigned
char
ecc2
[
256
];
static
void
nand_init_ecc
(
void
)
{
int
i
,
j
,
a
;
parity
[
0
]
=
0
;
for
(
i
=
1
;
i
<
256
;
i
++
)
parity
[
i
]
=
(
parity
[
i
&
(
i
-
1
)]
^
1
);
for
(
i
=
0
;
i
<
256
;
i
++
)
{
a
=
0
;
for
(
j
=
0
;
j
<
8
;
j
++
)
{
if
(
i
&
(
1
<<
j
))
{
if
((
j
&
1
)
==
0
)
a
^=
0x04
;
if
((
j
&
2
)
==
0
)
a
^=
0x10
;
if
((
j
&
4
)
==
0
)
a
^=
0x40
;
}
}
ecc2
[
i
]
=
~
(
a
^
(
a
<<
1
)
^
(
parity
[
i
]
?
0xa8
:
0
));
}
}
/* compute 3-byte ecc on 256 bytes */
static
void
nand_compute_ecc
(
unsigned
char
*
data
,
unsigned
char
*
ecc
)
{
int
i
,
j
,
a
;
unsigned
char
par
,
bit
,
bits
[
8
];
par
=
0
;
for
(
j
=
0
;
j
<
8
;
j
++
)
bits
[
j
]
=
0
;
/* collect 16 checksum bits */
for
(
i
=
0
;
i
<
256
;
i
++
)
{
par
^=
data
[
i
];
bit
=
parity
[
data
[
i
]];
for
(
j
=
0
;
j
<
8
;
j
++
)
if
((
i
&
(
1
<<
j
))
==
0
)
bits
[
j
]
^=
bit
;
}
/* put 4+4+4 = 12 bits in the ecc */
a
=
(
bits
[
3
]
<<
6
)
+
(
bits
[
2
]
<<
4
)
+
(
bits
[
1
]
<<
2
)
+
bits
[
0
];
ecc
[
0
]
=
~
(
a
^
(
a
<<
1
)
^
(
parity
[
par
]
?
0xaa
:
0
));
a
=
(
bits
[
7
]
<<
6
)
+
(
bits
[
6
]
<<
4
)
+
(
bits
[
5
]
<<
2
)
+
bits
[
4
];
ecc
[
1
]
=
~
(
a
^
(
a
<<
1
)
^
(
parity
[
par
]
?
0xaa
:
0
));
ecc
[
2
]
=
ecc2
[
par
];
}
static
int
nand_compare_ecc
(
unsigned
char
*
data
,
unsigned
char
*
ecc
)
{
return
(
data
[
0
]
==
ecc
[
0
]
&&
data
[
1
]
==
ecc
[
1
]
&&
data
[
2
]
==
ecc
[
2
]);
}
static
void
nand_store_ecc
(
unsigned
char
*
data
,
unsigned
char
*
ecc
)
{
memcpy
(
data
,
ecc
,
3
);
}
/*
* The actual driver starts here.
*/
/*
* On my 16MB card, control blocks have size 64 (16 real control bytes,
* and 48 junk bytes). In reality of course the card uses 16 control bytes,
* so the reader makes up the remaining 48. Don't know whether these numbers
* depend on the card. For now a constant.
*/
#define CONTROL_SHIFT 6
/*
* On my Combo CF/SM reader, the SM reader has LUN 1.
* (and things fail with LUN 0).
* It seems LUN is irrelevant for others.
*/
#define LUN 1
#define LUNBITS (LUN << 5)
/*
* LBA and PBA are unsigned ints. Special values.
*/
#define UNDEF 0xffffffff
#define SPARE 0xfffffffe
#define UNUSABLE 0xfffffffd
static
int
erase_bad_lba_entries
=
0
;
/*
* Send a control message and wait for the response.
*
...
...
@@ -63,27 +231,18 @@
*
*/
static
int
sddr09_send_control
(
struct
us_data
*
us
,
static
int
sddr09_send_control
(
struct
us_data
*
us
,
int
pipe
,
unsigned
char
request
,
unsigned
char
requesttype
,
unsigned
shor
t
value
,
unsigned
shor
t
index
,
unsigned
in
t
value
,
unsigned
in
t
index
,
unsigned
char
*
xfer_data
,
unsigned
int
xfer_len
)
{
int
result
;
// If data is going to be sent or received with the URB,
// then allocate a buffer for it. If data is to be sent,
// copy the data into the buffer.
/*
if (xfer_len > 0) {
buffer = kmalloc(xfer_len, GFP_NOIO);
if (!(command[0] & USB_DIR_IN))
memcpy(buffer, xfer_data, xfer_len);
}
*/
// Send the URB to the device and wait for a response.
/* Why are request and request type reversed in this call? */
...
...
@@ -93,16 +252,6 @@ static int sddr09_send_control(struct us_data *us,
xfer_data
,
xfer_len
);
// If data was sent or received with the URB, free the buffer we
// allocated earlier, but not before reading the data out of the
// buffer if we wanted to receive data.
/*
if (xfer_len > 0) {
if (command[0] & USB_DIR_IN)
memcpy(xfer_data, buffer, xfer_len);
kfree(buffer);
}
*/
// Check the return code for the command.
if
(
result
<
0
)
{
...
...
@@ -118,17 +267,44 @@ static int sddr09_send_control(struct us_data *us,
return
USB_STOR_TRANSPORT_FAILED
;
}
/* Uh oh... serious problem here */
return
USB_STOR_TRANSPORT_ERROR
;
}
return
USB_STOR_TRANSPORT_GOOD
;
}
static
int
sddr09_raw_bulk
(
struct
us_data
*
us
,
int
direction
,
unsigned
char
*
data
,
unsigned
int
len
)
{
/* send vendor interface command (0x41) */
/* called for requests 0, 1, 8 */
static
int
sddr09_send_command
(
struct
us_data
*
us
,
unsigned
char
request
,
unsigned
char
direction
,
unsigned
char
*
xfer_data
,
unsigned
int
xfer_len
)
{
int
pipe
;
unsigned
char
requesttype
=
(
0x41
|
direction
);
// Get the receive or send control pipe number
if
(
direction
==
USB_DIR_IN
)
pipe
=
usb_rcvctrlpipe
(
us
->
pusb_dev
,
0
);
else
pipe
=
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
);
return
sddr09_send_control
(
us
,
pipe
,
request
,
requesttype
,
0
,
0
,
xfer_data
,
xfer_len
);
}
static
int
sddr09_send_scsi_command
(
struct
us_data
*
us
,
unsigned
char
*
command
,
unsigned
int
command_len
)
{
return
sddr09_send_command
(
us
,
0
,
USB_DIR_OUT
,
command
,
command_len
);
}
static
int
sddr09_raw_bulk
(
struct
us_data
*
us
,
int
direction
,
unsigned
char
*
data
,
unsigned
int
len
)
{
int
result
;
int
act_len
;
...
...
@@ -150,51 +326,36 @@ static int sddr09_raw_bulk(struct us_data *us,
}
if
(
result
)
{
/* NAK - that means we've retried a few times already */
if
(
result
==
-
ETIMEDOUT
)
{
US_DEBUGP
(
"usbat_raw_bulk():"
" device NAKed
\n
"
);
return
US_BULK_TRANSFER_FAILED
;
}
/* -ENOENT -- we canceled this transfer */
if
(
result
==
-
ENOENT
)
{
US_DEBUGP
(
"usbat_raw_bulk():"
" transfer aborted
\n
"
);
US_DEBUGP
(
"usbat_raw_bulk(): transfer aborted
\n
"
);
return
US_BULK_TRANSFER_ABORTED
;
}
if
(
result
==
-
EPIPE
)
{
US_DEBUGP
(
"usbat_raw_bulk():"
" output pipe stalled
\n
"
);
return
USB_STOR_TRANSPORT_FAILED
;
}
/* NAK - that means we've retried a few times already */
if
(
result
==
-
ETIMEDOUT
)
US_DEBUGP
(
"usbat_raw_bulk(): device NAKed
\n
"
);
else
if
(
result
==
-
EOVERFLOW
)
US_DEBUGP
(
"us_transfer_partial(): babble/overflow
\n
"
);
else
if
(
result
!=
-
EPIPE
)
US_DEBUGP
(
"us_transfer_partial(): unknown error %d
\n
"
,
result
);
/* the catch-all case */
US_DEBUGP
(
"us_transfer_partial(): unknown error
\n
"
);
return
US_BULK_TRANSFER_FAILED
;
}
if
(
act_len
!=
len
)
{
US_DEBUGP
(
"Warning: Transferred only %d bytes
\n
"
,
act_
len
);
US_DEBUGP
(
"Warning: Transferred only %d
of %d
bytes
\n
"
,
act_len
,
len
);
return
US_BULK_TRANSFER_SHORT
;
}
US_DEBUGP
(
"Transferred %d of %d bytes
\n
"
,
act_len
,
len
);
return
US_BULK_TRANSFER_GOOD
;
}
/*
* Note: direction must be set if command_len == 0.
*/
static
int
sddr09_bulk_transport
(
struct
us_data
*
us
,
int
direction
,
unsigned
char
*
data
,
unsigned
int
len
,
static
int
sddr09_bulk_transport
(
struct
us_data
*
us
,
int
direction
,
unsigned
char
*
data
,
unsigned
int
len
,
int
use_sg
)
{
int
result
=
USB_STOR_TRANSPORT_GOOD
;
...
...
@@ -203,97 +364,724 @@ static int sddr09_bulk_transport(struct us_data *us,
struct
scatterlist
*
sg
;
char
string
[
64
];
if
(
len
==
0
)
return
USB_STOR_TRANSPORT_GOOD
;
#define DEBUG_PRCT 12
if
(
len
==
0
)
return
USB_STOR_TRANSPORT_GOOD
;
/* transfer the data */
if
(
direction
==
SCSI_DATA_WRITE
)
{
if
(
direction
==
SCSI_DATA_WRITE
&&
!
use_sg
)
{
/* Debug-print the first
48
bytes of the write transfer */
/* Debug-print the first
N
bytes of the write transfer */
if
(
!
use_sg
)
{
strcpy
(
string
,
"wr: "
);
for
(
i
=
0
;
i
<
len
&&
i
<
48
;
i
++
)
{
for
(
i
=
0
;
i
<
len
&&
i
<
DEBUG_PRCT
;
i
++
)
{
sprintf
(
string
+
strlen
(
string
),
"%02X "
,
data
[
i
]);
if
((
i
%
16
)
==
15
)
{
if
((
i
%
16
)
==
15
)
{
US_DEBUGP
(
"%s
\n
"
,
string
);
strcpy
(
string
,
"wr: "
);
}
}
if
((
i
%
16
)
!=
0
)
US_DEBUGP
(
"%s
\n
"
,
string
);
if
((
i
%
16
)
!=
0
)
US_DEBUGP
(
"%s
\n
"
,
string
);
}
US_DEBUGP
(
"SCM data %s transfer %d sg buffers %d
\n
"
,
(
direction
==
SCSI_DATA_READ
)
?
"in"
:
"out"
,
len
,
use_sg
);
if
(
!
use_sg
)
result
=
sddr09_raw_bulk
(
us
,
direction
,
data
,
len
);
else
{
sg
=
(
struct
scatterlist
*
)
data
;
for
(
i
=
0
;
i
<
use_sg
&&
transferred
<
len
;
i
++
)
{
unsigned
char
*
buf
;
unsigned
int
length
;
buf
=
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
;
length
=
len
-
transferred
;
if
(
length
>
sg
[
i
].
length
)
length
=
sg
[
i
].
length
;
result
=
sddr09_raw_bulk
(
us
,
direction
,
buf
,
length
);
if
(
result
!=
US_BULK_TRANSFER_GOOD
)
break
;
transferred
+=
sg
[
i
].
length
;
}
}
if
(
direction
==
SCSI_DATA_READ
&&
!
use_sg
)
{
/* Debug-print the first N bytes of the read transfer */
strcpy
(
string
,
"rd: "
);
for
(
i
=
0
;
i
<
len
&&
i
<
DEBUG_PRCT
;
i
++
)
{
sprintf
(
string
+
strlen
(
string
),
"%02X "
,
data
[
i
]);
if
((
i
%
16
)
==
15
)
{
US_DEBUGP
(
"%s
\n
"
,
string
);
strcpy
(
string
,
"rd: "
);
}
}
if
((
i
%
16
)
!=
0
)
US_DEBUGP
(
"%s
\n
"
,
string
);
}
return
result
;
}
#if 0
/*
* Test Unit Ready Command: 12 bytes.
* byte 0: opcode: 00
*/
static int
sddr09_test_unit_ready(struct us_data *us) {
unsigned char command[6] = {
0, LUNBITS, 0, 0, 0, 0
};
int result;
result = sddr09_send_scsi_command(us, command, sizeof(command));
US_DEBUGP("sddr09_test_unit_ready returns %d\n", result);
return result;
}
#endif
/*
* Request Sense Command: 12 bytes.
* byte 0: opcode: 03
* byte 4: data length
*/
static
int
sddr09_request_sense
(
struct
us_data
*
us
,
unsigned
char
*
sensebuf
,
int
buflen
)
{
unsigned
char
command
[
12
]
=
{
0x03
,
LUNBITS
,
0
,
0
,
buflen
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
int
result
;
result
=
sddr09_send_scsi_command
(
us
,
command
,
sizeof
(
command
));
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"request sense failed
\n
"
);
return
result
;
}
result
=
sddr09_raw_bulk
(
us
,
SCSI_DATA_READ
,
sensebuf
,
buflen
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
US_DEBUGP
(
"request sense bulk in failed
\n
"
);
else
US_DEBUGP
(
"request sense worked
\n
"
);
return
result
;
}
/*
* Read Command: 12 bytes.
* byte 0: opcode: E8
* byte 1: last two bits: 00: read data, 01: read blockwise control,
* 10: read both, 11: read pagewise control.
* It turns out we need values 20, 21, 22, 23 here (LUN 1).
* bytes 2-5: address (interpretation depends on byte 1, see below)
* bytes 10-11: count (idem)
*
* A page has 512 data bytes and 64 control bytes (16 control and 48 junk).
* A read data command gets data in 512-byte pages.
* A read control command gets control in 64-byte chunks.
* A read both command gets data+control in 576-byte chunks.
*
* Blocks are groups of 32 pages, and read blockwise control jumps to the
* next block, while read pagewise control jumps to the next page after
* reading a group of 64 control bytes.
* [Here 512 = 1<<pageshift, 32 = 1<<blockshift, 64 is constant?]
*
* (1 MB and 2 MB cards are a bit different, but I have only a 16 MB card.)
*/
static
int
sddr09_readX
(
struct
us_data
*
us
,
int
x
,
unsigned
long
fromaddress
,
int
nr_of_pages
,
int
bulklen
,
unsigned
char
*
buf
,
int
use_sg
)
{
unsigned
char
command
[
12
]
=
{
0xe8
,
LUNBITS
|
x
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
int
result
;
command
[
2
]
=
MSB_of
(
fromaddress
>>
16
);
command
[
3
]
=
LSB_of
(
fromaddress
>>
16
);
command
[
4
]
=
MSB_of
(
fromaddress
&
0xFFFF
);
command
[
5
]
=
LSB_of
(
fromaddress
&
0xFFFF
);
command
[
10
]
=
MSB_of
(
nr_of_pages
);
command
[
11
]
=
LSB_of
(
nr_of_pages
);
result
=
sddr09_send_scsi_command
(
us
,
command
,
sizeof
(
command
));
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"Result for send_control in sddr09_read2%d %d
\n
"
,
x
,
result
);
return
result
;
}
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
buf
,
bulklen
,
use_sg
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
US_DEBUGP
(
"Result for bulk_transport in sddr09_read2%d %d
\n
"
,
x
,
result
);
return
result
;
}
/*
* Read Data
*
* fromaddress counts data shorts:
* increasing it by 256 shifts the bytestream by 512 bytes;
* the last 8 bits are ignored.
*
* nr_of_pages counts pages of size (1 << pageshift).
*/
static
int
sddr09_read20
(
struct
us_data
*
us
,
unsigned
long
fromaddress
,
int
nr_of_pages
,
int
pageshift
,
unsigned
char
*
buf
,
int
use_sg
)
{
int
bulklen
=
nr_of_pages
<<
pageshift
;
/* The last 8 bits of fromaddress are ignored. */
return
sddr09_readX
(
us
,
0
,
fromaddress
,
nr_of_pages
,
bulklen
,
buf
,
use_sg
);
}
/*
* Read Blockwise Control
*
* fromaddress gives the starting position (as in read data;
* the last 8 bits are ignored); increasing it by 32*256 shifts
* the output stream by 64 bytes.
*
* count counts control groups of size (1 << controlshift).
* For me, controlshift = 6. Is this constant?
*
* After getting one control group, jump to the next block
* (fromaddress += 8192).
*/
static
int
sddr09_read21
(
struct
us_data
*
us
,
unsigned
long
fromaddress
,
int
count
,
int
controlshift
,
unsigned
char
*
buf
,
int
use_sg
)
{
int
bulklen
=
(
count
<<
controlshift
);
return
sddr09_readX
(
us
,
1
,
fromaddress
,
count
,
bulklen
,
buf
,
use_sg
);
}
/*
* Read both Data and Control
*
* fromaddress counts data shorts, ignoring control:
* increasing it by 256 shifts the bytestream by 576 = 512+64 bytes;
* the last 8 bits are ignored.
*
* nr_of_pages counts pages of size (1 << pageshift) + (1 << controlshift).
*/
static
int
sddr09_read22
(
struct
us_data
*
us
,
unsigned
long
fromaddress
,
int
nr_of_pages
,
int
pageshift
,
unsigned
char
*
buf
,
int
use_sg
)
{
int
bulklen
=
(
nr_of_pages
<<
pageshift
)
+
(
nr_of_pages
<<
CONTROL_SHIFT
);
US_DEBUGP
(
"sddr09_read22: reading %d pages, %d bytes
\n
"
,
nr_of_pages
,
bulklen
);
return
sddr09_readX
(
us
,
2
,
fromaddress
,
nr_of_pages
,
bulklen
,
buf
,
use_sg
);
}
#if 0
/*
* Read Pagewise Control
*
* fromaddress gives the starting position (as in read data;
* the last 8 bits are ignored); increasing it by 256 shifts
* the output stream by 64 bytes.
*
* count counts control groups of size (1 << controlshift).
* For me, controlshift = 6. Is this constant?
*
* After getting one control group, jump to the next page
* (fromaddress += 256).
*/
static int
sddr09_read23(struct us_data *us, unsigned long fromaddress,
int count, int controlshift, unsigned char *buf, int use_sg) {
int bulklen = (count << controlshift);
return sddr09_readX(us, 3, fromaddress, count, bulklen,
buf, use_sg);
}
#endif
/*
* Erase Command: 12 bytes.
* byte 0: opcode: EA
* bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
*
* Always precisely one block is erased; bytes 2-5 and 10-11 are ignored.
* The byte address being erased is 2*Eaddress.
*/
static
int
sddr09_erase
(
struct
us_data
*
us
,
unsigned
long
Eaddress
)
{
unsigned
char
command
[
12
]
=
{
0xea
,
LUNBITS
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
int
result
;
command
[
6
]
=
MSB_of
(
Eaddress
>>
16
);
command
[
7
]
=
LSB_of
(
Eaddress
>>
16
);
command
[
8
]
=
MSB_of
(
Eaddress
&
0xFFFF
);
command
[
9
]
=
LSB_of
(
Eaddress
&
0xFFFF
);
result
=
sddr09_send_scsi_command
(
us
,
command
,
sizeof
(
command
));
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
US_DEBUGP
(
"Result for send_control in sddr09_erase %d
\n
"
,
result
);
return
result
;
}
/*
* Write Command: 12 bytes.
* byte 0: opcode: E9
* bytes 2-5: write address (big-endian, counting shorts, sector aligned).
* bytes 6-9: erase address (big-endian, counting shorts, sector aligned).
* bytes 10-11: sector count (big-endian, in 512-byte sectors).
*
* If write address equals erase address, the erase is done first,
* otherwise the write is done first. When erase address equals zero
* no erase is done?
*/
static
int
sddr09_writeX
(
struct
us_data
*
us
,
unsigned
long
Waddress
,
unsigned
long
Eaddress
,
int
nr_of_pages
,
int
bulklen
,
unsigned
char
*
buf
,
int
use_sg
)
{
unsigned
char
command
[
12
]
=
{
0xe9
,
LUNBITS
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
int
result
;
command
[
2
]
=
MSB_of
(
Waddress
>>
16
);
command
[
3
]
=
LSB_of
(
Waddress
>>
16
);
command
[
4
]
=
MSB_of
(
Waddress
&
0xFFFF
);
command
[
5
]
=
LSB_of
(
Waddress
&
0xFFFF
);
command
[
6
]
=
MSB_of
(
Eaddress
>>
16
);
command
[
7
]
=
LSB_of
(
Eaddress
>>
16
);
command
[
8
]
=
MSB_of
(
Eaddress
&
0xFFFF
);
command
[
9
]
=
LSB_of
(
Eaddress
&
0xFFFF
);
command
[
10
]
=
MSB_of
(
nr_of_pages
);
command
[
11
]
=
LSB_of
(
nr_of_pages
);
result
=
sddr09_send_scsi_command
(
us
,
command
,
sizeof
(
command
));
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"Result for send_control in sddr09_writeX %d
\n
"
,
result
);
return
result
;
}
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_WRITE
,
buf
,
bulklen
,
use_sg
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
US_DEBUGP
(
"Result for bulk_transport in sddr09_writeX %d
\n
"
,
result
);
return
result
;
}
/* erase address, write same address */
static
int
sddr09_write_inplace
(
struct
us_data
*
us
,
unsigned
long
address
,
int
nr_of_pages
,
int
pageshift
,
unsigned
char
*
buf
,
int
use_sg
)
{
int
bulklen
=
(
nr_of_pages
<<
pageshift
)
+
(
nr_of_pages
<<
CONTROL_SHIFT
);
return
sddr09_writeX
(
us
,
address
,
address
,
nr_of_pages
,
bulklen
,
buf
,
use_sg
);
}
#if 0
/*
* Read Scatter Gather Command: 3+4n bytes.
* byte 0: opcode E7
* byte 2: n
* bytes 4i-1,4i,4i+1: page address
* byte 4i+2: page count
* (i=1..n)
*
* This reads several pages from the card to a single memory buffer.
* The last two bits of byte 1 have the same meaning as for E8.
*/
static int
sddr09_read_sg_test_only(struct us_data *us) {
unsigned char command[15] = {
0xe7, LUNBITS, 0
};
int result, bulklen, nsg, ct;
unsigned char *buf;
unsigned long address;
nsg = bulklen = 0;
address = 040000; ct = 1;
nsg++;
bulklen += (ct << 9);
command[4*nsg+2] = ct;
command[4*nsg+1] = ((address >> 9) & 0xFF);
command[4*nsg+0] = ((address >> 17) & 0xFF);
command[4*nsg-1] = ((address >> 25) & 0xFF);
address = 0340000; ct = 1;
nsg++;
bulklen += (ct << 9);
command[4*nsg+2] = ct;
command[4*nsg+1] = ((address >> 9) & 0xFF);
command[4*nsg+0] = ((address >> 17) & 0xFF);
command[4*nsg-1] = ((address >> 25) & 0xFF);
address = 01000000; ct = 2;
nsg++;
bulklen += (ct << 9);
command[4*nsg+2] = ct;
command[4*nsg+1] = ((address >> 9) & 0xFF);
command[4*nsg+0] = ((address >> 17) & 0xFF);
command[4*nsg-1] = ((address >> 25) & 0xFF);
command[2] = nsg;
result = sddr09_send_scsi_command(us, command, 4*nsg+3);
if (result != USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("Result for send_control in sddr09_read_sg %d\n",
result);
return result;
}
buf = (unsigned char *) kmalloc(bulklen, GFP_NOIO);
if (!buf)
return USB_STOR_TRANSPORT_ERROR;
result = sddr09_bulk_transport(us, SCSI_DATA_READ,
buf, bulklen, 0);
if (result != USB_STOR_TRANSPORT_GOOD)
US_DEBUGP("Result for bulk_transport in sddr09_read_sg %d\n",
result);
kfree(buf);
return result;
}
#endif
/*
* Read Status Command: 12 bytes.
* byte 0: opcode: EC
*
* Returns 64 bytes, all zero except for the first.
* bit 0: 1: Error
* bit 5: 1: Suspended
* bit 6: 1: Ready
* bit 7: 1: Not write-protected
*/
static
int
sddr09_read_status
(
struct
us_data
*
us
,
unsigned
char
*
status
)
{
unsigned
char
command
[
12
]
=
{
0xec
,
LUNBITS
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
unsigned
char
data
[
64
];
int
result
;
US_DEBUGP
(
"Reading status...
\n
"
);
result
=
sddr09_send_scsi_command
(
us
,
command
,
sizeof
(
command
));
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
return
result
;
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
data
,
sizeof
(
data
),
0
);
*
status
=
data
[
0
];
return
result
;
}
static
int
sddr09_read_data
(
struct
us_data
*
us
,
unsigned
long
address
,
unsigned
int
sectors
,
unsigned
char
*
content
,
int
use_sg
)
{
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
unsigned
int
lba
,
maxlba
,
pba
;
unsigned
int
page
,
pages
;
unsigned
char
*
buffer
=
NULL
;
unsigned
char
*
ptr
;
struct
scatterlist
*
sg
=
NULL
;
int
result
,
i
,
len
;
// If we're using scatter-gather, we have to create a new
// buffer to read all of the data in first, since a
// scatter-gather buffer could in theory start in the middle
// of a page, which would be bad. A developer who wants a
// challenge might want to write a limited-buffer
// version of this code.
len
=
sectors
*
info
->
pagesize
;
if
(
use_sg
)
{
sg
=
(
struct
scatterlist
*
)
content
;
buffer
=
kmalloc
(
len
,
GFP_NOIO
);
if
(
buffer
==
NULL
)
return
USB_STOR_TRANSPORT_ERROR
;
ptr
=
buffer
;
}
else
ptr
=
content
;
// Figure out the initial LBA and page
lba
=
address
>>
info
->
blockshift
;
page
=
(
address
&
info
->
blockmask
);
maxlba
=
info
->
capacity
>>
(
info
->
pageshift
+
info
->
blockshift
);
// This could be made much more efficient by checking for
// contiguous LBA's. Another exercise left to the student.
result
=
USB_STOR_TRANSPORT_GOOD
;
while
(
sectors
>
0
)
{
/* Find number of pages we can read in this block */
pages
=
info
->
blocksize
-
page
;
if
(
pages
>
sectors
)
pages
=
sectors
;
/* Not overflowing capacity? */
if
(
lba
>=
maxlba
)
{
US_DEBUGP
(
"Error: Requested lba %u exceeds "
"maximum %u
\n
"
,
lba
,
maxlba
);
result
=
USB_STOR_TRANSPORT_ERROR
;
break
;
}
/* Find where this lba lives on disk */
pba
=
info
->
lba_to_pba
[
lba
];
if
(
pba
==
UNDEF
)
{
/* this lba was never written */
US_DEBUGP
(
"Read %d zero pages (LBA %d) page %d
\n
"
,
pages
,
lba
,
page
);
/* This is not really an error. It just means
that the block has never been written.
Instead of returning USB_STOR_TRANSPORT_ERROR
it is better to return all zero data. */
memset
(
ptr
,
0
,
pages
<<
info
->
pageshift
);
}
else
{
US_DEBUGP
(
"Read %d pages, from PBA %d"
" (LBA %d) page %d
\n
"
,
pages
,
pba
,
lba
,
page
);
address
=
((
pba
<<
info
->
blockshift
)
+
page
)
<<
info
->
pageshift
;
result
=
sddr09_read20
(
us
,
address
>>
1
,
pages
,
info
->
pageshift
,
ptr
,
0
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
break
;
}
page
=
0
;
lba
++
;
sectors
-=
pages
;
ptr
+=
(
pages
<<
info
->
pageshift
);
}
if
(
use_sg
&&
result
==
USB_STOR_TRANSPORT_GOOD
)
{
int
transferred
=
0
;
for
(
i
=
0
;
i
<
use_sg
&&
transferred
<
len
;
i
++
)
{
unsigned
char
*
buf
;
unsigned
int
length
;
buf
=
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
;
length
=
len
-
transferred
;
if
(
length
>
sg
[
i
].
length
)
length
=
sg
[
i
].
length
;
memcpy
(
buf
,
buffer
+
transferred
,
length
);
transferred
+=
sg
[
i
].
length
;
}
}
if
(
use_sg
)
kfree
(
buffer
);
return
result
;
}
/* we never free blocks, so lastpba can only increase */
static
unsigned
int
sddr09_find_unused_pba
(
struct
sddr09_card_info
*
info
)
{
static
unsigned
int
lastpba
=
1
;
int
numblocks
=
info
->
capacity
>>
(
info
->
blockshift
+
info
->
pageshift
);
int
i
;
for
(
i
=
lastpba
+
1
;
i
<
numblocks
;
i
++
)
{
if
(
info
->
pba_to_lba
[
i
]
==
UNDEF
)
{
lastpba
=
i
;
return
i
;
}
}
return
0
;
}
static
int
sddr09_write_lba
(
struct
us_data
*
us
,
unsigned
int
lba
,
unsigned
int
page
,
unsigned
int
pages
,
unsigned
char
*
ptr
)
{
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
unsigned
long
address
;
unsigned
int
pba
,
lbap
;
unsigned
int
pagelen
,
blocklen
;
unsigned
char
*
blockbuffer
,
*
bptr
,
*
cptr
,
*
xptr
;
unsigned
char
ecc
[
3
];
int
i
,
result
;
lbap
=
((
lba
&
0x3ff
)
<<
1
)
|
0x1000
;
if
(
parity
[
MSB_of
(
lbap
)
^
LSB_of
(
lbap
)])
lbap
^=
1
;
pba
=
info
->
lba_to_pba
[
lba
];
if
(
pba
==
UNDEF
)
{
pba
=
sddr09_find_unused_pba
(
info
);
if
(
!
pba
)
{
printk
(
"sddr09_write_lba: Out of unused blocks
\n
"
);
return
USB_STOR_TRANSPORT_ERROR
;
}
info
->
pba_to_lba
[
pba
]
=
lba
;
info
->
lba_to_pba
[
lba
]
=
pba
;
}
if
(
pba
==
1
)
{
/* Maybe it is impossible to write to PBA 1.
Fake success, but don't do anything. */
printk
(
"sddr09: avoid writing to pba 1
\n
"
);
return
USB_STOR_TRANSPORT_GOOD
;
}
pagelen
=
(
1
<<
info
->
pageshift
)
+
(
1
<<
CONTROL_SHIFT
);
blocklen
=
(
pagelen
<<
info
->
blockshift
);
blockbuffer
=
kmalloc
(
blocklen
,
GFP_NOIO
);
if
(
!
blockbuffer
)
{
printk
(
"sddr09_write_lba: Out of memory
\n
"
);
return
USB_STOR_TRANSPORT_ERROR
;
}
/* read old contents */
address
=
(
pba
<<
(
info
->
pageshift
+
info
->
blockshift
));
result
=
sddr09_read22
(
us
,
address
>>
1
,
info
->
blocksize
,
info
->
pageshift
,
blockbuffer
,
0
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
goto
err
;
/* check old contents */
for
(
i
=
0
;
i
<
info
->
blockshift
;
i
++
)
{
bptr
=
blockbuffer
+
i
*
pagelen
;
cptr
=
bptr
+
info
->
pagesize
;
nand_compute_ecc
(
bptr
,
ecc
);
if
(
!
nand_compare_ecc
(
cptr
+
13
,
ecc
))
{
US_DEBUGP
(
"Warning: bad ecc in page %d- of pba %d
\n
"
,
i
,
pba
);
nand_store_ecc
(
cptr
+
13
,
ecc
);
}
nand_compute_ecc
(
bptr
+
(
info
->
pagesize
/
2
),
ecc
);
if
(
!
nand_compare_ecc
(
cptr
+
8
,
ecc
))
{
US_DEBUGP
(
"Warning: bad ecc in page %d+ of pba %d
\n
"
,
i
,
pba
);
nand_store_ecc
(
cptr
+
8
,
ecc
);
}
}
US_DEBUGP
(
"SCM data %s transfer %d sg buffers %d
\n
"
,
(
direction
==
SCSI_DATA_READ
?
"in"
:
"out"
),
len
,
use_sg
);
if
(
!
use_sg
)
result
=
sddr09_raw_bulk
(
us
,
direction
,
data
,
len
);
else
{
sg
=
(
struct
scatterlist
*
)
data
;
for
(
i
=
0
;
i
<
use_sg
&&
transferred
<
len
;
i
++
)
{
result
=
sddr09_raw_bulk
(
us
,
direction
,
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
,
len
-
transferred
>
sg
[
i
].
length
?
sg
[
i
].
length
:
len
-
transferred
);
if
(
result
!=
US_BULK_TRANSFER_GOOD
)
break
;
transferred
+=
sg
[
i
].
length
;
}
/* copy in new stuff and compute ECC */
xptr
=
ptr
;
for
(
i
=
page
;
i
<
page
+
pages
;
i
++
)
{
bptr
=
blockbuffer
+
i
*
pagelen
;
cptr
=
bptr
+
info
->
pagesize
;
memcpy
(
bptr
,
xptr
,
info
->
pagesize
);
xptr
+=
info
->
pagesize
;
nand_compute_ecc
(
bptr
,
ecc
);
nand_store_ecc
(
cptr
+
13
,
ecc
);
nand_compute_ecc
(
bptr
+
(
info
->
pagesize
/
2
),
ecc
);
nand_store_ecc
(
cptr
+
8
,
ecc
);
cptr
[
6
]
=
cptr
[
11
]
=
MSB_of
(
lbap
);
cptr
[
7
]
=
cptr
[
12
]
=
LSB_of
(
lbap
);
}
if
(
direction
==
SCSI_DATA_READ
)
{
US_DEBUGP
(
"Rewrite PBA %d (LBA %d)
\n
"
,
pba
,
lba
);
/* Debug-print the first 48 bytes of the read transfer */
result
=
sddr09_write_inplace
(
us
,
address
>>
1
,
info
->
blocksize
,
info
->
pageshift
,
blockbuffer
,
0
);
if
(
!
use_sg
)
{
strcpy
(
string
,
"rd: "
);
for
(
i
=
0
;
i
<
len
&&
i
<
48
;
i
++
)
{
sprintf
(
string
+
strlen
(
string
),
"%02X "
,
data
[
i
]);
if
((
i
%
16
)
==
15
)
{
US_DEBUGP
(
"%s
\n
"
,
string
);
strcpy
(
string
,
"rd: "
);
}
}
if
((
i
%
16
)
!=
0
)
US_DEBUGP
(
"%s
\n
"
,
string
);
US_DEBUGP
(
"sddr09_write_inplace returns %d
\n
"
,
result
);
#if 0
{
unsigned char status = 0;
int result2 = sddr09_read_status(us, &status);
if (result2 != USB_STOR_TRANSPORT_GOOD)
US_DEBUGP("sddr09_write_inplace: cannot read status\n");
else if (status != 0xc0)
US_DEBUGP("sddr09_write_inplace: status after write: 0x%x\n",
status);
}
#endif
#if 0
{
int result2 = sddr09_test_unit_ready(us);
}
#endif
err:
kfree
(
blockbuffer
);
/* TODO: instead of doing kmalloc/kfree for each block,
add a bufferpointer to the info structure */
return
result
;
}
int
sddr09_read_data
(
struct
us_data
*
us
,
static
int
sddr09_write_data
(
struct
us_data
*
us
,
unsigned
long
address
,
unsigned
shor
t
sectors
,
unsigned
in
t
sectors
,
unsigned
char
*
content
,
int
use_sg
)
{
int
result
;
unsigned
char
command
[
12
]
=
{
0xe8
,
0x20
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
unsigned
int
lba
;
unsigned
int
pba
;
unsigned
short
page
;
unsigned
short
pages
;
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
unsigned
int
lba
,
page
,
pages
;
unsigned
char
*
buffer
=
NULL
;
unsigned
char
*
ptr
;
struct
scatterlist
*
sg
=
NULL
;
int
i
;
int
len
;
int
transferred
;
int
result
,
i
,
len
;
// If we're using scatter-gather, we have to create a new
// buffer to
read
all of the data in first, since a
// buffer to
write
all of the data in first, since a
// scatter-gather buffer could in theory start in the middle
// of a page, which would be bad. A developer who wants a
// challenge might want to write a limited-buffer
...
...
@@ -302,78 +1090,50 @@ int sddr09_read_data(struct us_data *us,
len
=
sectors
*
info
->
pagesize
;
if
(
use_sg
)
{
int
transferred
=
0
;
sg
=
(
struct
scatterlist
*
)
content
;
buffer
=
kmalloc
(
len
,
GFP_NOIO
);
if
(
buffer
==
NULL
)
return
USB_STOR_TRANSPORT_ERROR
;
for
(
i
=
0
;
i
<
use_sg
&&
transferred
<
len
;
i
++
)
{
unsigned
char
*
buf
;
unsigned
int
length
;
buf
=
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
;
length
=
len
-
transferred
;
if
(
length
>
sg
[
i
].
length
)
length
=
sg
[
i
].
length
;
memcpy
(
buffer
+
transferred
,
buf
,
length
);
transferred
+=
sg
[
i
].
length
;
}
ptr
=
buffer
;
}
else
ptr
=
content
;
// Figure out the initial LBA and page
pba
=
address
>>
(
info
->
pageshift
+
info
->
blockshift
);
lba
=
info
->
pba_to_lba
[
pba
];
page
=
(
address
>>
info
->
pageshift
)
&
info
->
blockmask
;
lba
=
address
>>
info
->
blockshift
;
page
=
(
address
&
info
->
blockmask
);
// This could be made much more efficient by checking for
// contiguous LBA's. Another exercise left to the student.
while
(
sectors
>
0
)
{
result
=
USB_STOR_TRANSPORT_GOOD
;
pba
=
info
->
lba_to_pba
[
lba
];
while
(
sectors
>
0
)
{
//
Read
as many sectors as possible in this block
//
Write
as many sectors as possible in this block
pages
=
info
->
blocksize
-
page
;
if
(
pages
>
sectors
)
pages
=
sectors
;
US_DEBUGP
(
"Read %02X pages, from PBA %04X"
" (LBA %04X) page %02X
\n
"
,
pages
,
pba
,
lba
,
page
);
address
=
(
(
pba
<<
info
->
blockshift
)
+
page
)
<<
info
->
pageshift
;
// Unlike in the documentation, the address is in
// words of 2 bytes.
command
[
2
]
=
MSB_of
(
address
>>
17
);
command
[
3
]
=
LSB_of
(
address
>>
17
);
command
[
4
]
=
MSB_of
((
address
>>
1
)
&
0xFFFF
);
command
[
5
]
=
LSB_of
((
address
>>
1
)
&
0xFFFF
);
command
[
10
]
=
MSB_of
(
pages
);
command
[
11
]
=
LSB_of
(
pages
);
result
=
sddr09_send_control
(
us
,
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
),
0
,
0x41
,
0
,
0
,
command
,
12
);
US_DEBUGP
(
"Result for send_control in read_data %d
\n
"
,
result
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
if
(
use_sg
)
kfree
(
buffer
);
return
result
;
}
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
ptr
,
pages
<<
info
->
pageshift
,
0
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
if
(
use_sg
)
kfree
(
buffer
);
return
result
;
}
result
=
sddr09_write_lba
(
us
,
lba
,
page
,
pages
,
ptr
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
break
;
page
=
0
;
lba
++
;
...
...
@@ -381,234 +1141,164 @@ int sddr09_read_data(struct us_data *us,
ptr
+=
(
pages
<<
info
->
pageshift
);
}
if
(
use_sg
)
{
transferred
=
0
;
for
(
i
=
0
;
i
<
use_sg
&&
transferred
<
len
;
i
++
)
{
memcpy
(
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
,
buffer
+
transferred
,
len
-
transferred
>
sg
[
i
].
length
?
sg
[
i
].
length
:
len
-
transferred
);
transferred
+=
sg
[
i
].
length
;
}
if
(
use_sg
)
kfree
(
buffer
);
}
return
USB_STOR_TRANSPORT_GOOD
;
return
result
;
}
int
sddr09_read_control
(
struct
us_data
*
us
,
static
int
sddr09_read_control
(
struct
us_data
*
us
,
unsigned
long
address
,
unsigned
shor
t
blocks
,
unsigned
in
t
blocks
,
unsigned
char
*
content
,
int
use_sg
)
{
// Unlike in the documentation, the last two bytes are the
// number of blocks, not sectors.
int
result
;
unsigned
char
command
[
12
]
=
{
0xe8
,
0x21
,
MSB_of
(
address
>>
16
),
LSB_of
(
address
>>
16
),
MSB_of
(
address
&
0xFFFF
),
LSB_of
(
address
&
0xFFFF
),
0
,
0
,
0
,
0
,
MSB_of
(
blocks
),
LSB_of
(
blocks
)
};
US_DEBUGP
(
"Read control address %08lX blocks %04X
\n
"
,
address
,
blocks
);
result
=
sddr09_send_control
(
us
,
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
),
0
,
0x41
,
0
,
0
,
command
,
12
);
US_DEBUGP
(
"Result for send_control in read_control %d
\n
"
,
result
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
return
result
;
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
content
,
blocks
<<
6
,
use_sg
);
// 0x40 bytes per block
US_DEBUGP
(
"Result for bulk read in read_control %d
\n
"
,
result
);
return
result
;
return
sddr09_read21
(
us
,
address
,
blocks
,
CONTROL_SHIFT
,
content
,
use_sg
);
}
int
sddr09_read_deviceID
(
struct
us_data
*
us
,
unsigned
char
*
manufacturerID
,
unsigned
char
*
deviceID
)
{
int
result
;
/*
* Read Device ID Command: 12 bytes.
* byte 0: opcode: ED
*
* Returns 2 bytes: Manufacturer ID and Device ID.
* On more recent cards 3 bytes: the third byte is an option code A5
* signifying that the secret command to read an 128-bit ID is available.
* On still more recent cards 4 bytes: the fourth byte C0 means that
* a second read ID cmd is available.
*/
static
int
sddr09_read_deviceID
(
struct
us_data
*
us
,
unsigned
char
*
deviceID
)
{
unsigned
char
command
[
12
]
=
{
0xed
,
0x20
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
0xed
,
LUNBITS
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
unsigned
char
content
[
64
];
int
result
,
i
;
result
=
sddr09_send_control
(
us
,
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
),
0
,
0x41
,
0
,
0
,
command
,
12
);
US_DEBUGP
(
"Result of send_control for device ID is %d
\n
"
,
result
);
result
=
sddr09_send_scsi_command
(
us
,
command
,
sizeof
(
command
));
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
return
result
;
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
content
,
64
,
0
);
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
content
,
64
,
0
);
*
manufacturerID
=
content
[
0
];
*
deviceID
=
content
[
1
];
for
(
i
=
0
;
i
<
4
;
i
++
)
deviceID
[
i
]
=
content
[
i
];
return
result
;
}
int
sddr09_read_status
(
struct
us_data
*
us
,
unsigned
char
*
status
)
{
static
int
sddr09_get_wp
(
struct
us_data
*
us
,
struct
sddr09_card_info
*
info
)
{
int
result
;
unsigned
char
command
[
12
]
=
{
0xec
,
0x20
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
};
result
=
sddr09_send_control
(
us
,
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
),
0
,
0x41
,
0
,
0
,
command
,
12
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
return
result
;
result
=
sddr09_bulk_transport
(
us
,
SCSI_DATA_READ
,
status
,
1
,
0
);
unsigned
char
status
;
result
=
sddr09_read_status
(
us
,
&
status
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"sddr09_get_wp: read_status fails
\n
"
);
return
result
;
}
US_DEBUGP
(
"sddr09_get_wp: status %02X"
,
status
);
if
((
status
&
0x80
)
==
0
)
{
info
->
flags
|=
SDDR09_WP
;
/* write protected */
US_DEBUGP
(
" WP"
);
}
if
(
status
&
0x40
)
US_DEBUGP
(
" Ready"
);
if
(
status
&
LUNBITS
)
US_DEBUGP
(
" Suspended"
);
if
(
status
&
0x1
)
US_DEBUGP
(
" Error"
);
US_DEBUGP
(
"
\n
"
);
return
USB_STOR_TRANSPORT_GOOD
;
}
int
sddr09_reset
(
struct
us_data
*
us
)
{
#if 0
/*
* Reset Command: 12 bytes.
* byte 0: opcode: EB
*/
static int
sddr09_reset(struct us_data *us) {
int
result
;
unsigned char command[12] = {
0xeb
,
0x20
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
,
0
0xeb,
LUNBITS
, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
};
result
=
sddr09_send_control
(
us
,
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
),
0
,
0x41
,
0
,
0
,
command
,
12
);
return
result
;
return sddr09_send_scsi_command(us, command, sizeof(command));
}
#endif
unsigned
long
sddr09_get_capacity
(
struct
us_data
*
us
,
unsigned
int
*
pagesize
,
unsigned
int
*
blocksize
)
{
unsigned
char
manufacturerID
;
unsigned
char
deviceID
;
static
struct
nand_flash_dev
*
sddr09_get_cardinfo
(
struct
us_data
*
us
,
unsigned
char
flags
)
{
struct
nand_flash_dev
*
cardinfo
;
unsigned
char
deviceID
[
4
]
;
char
blurbtxt
[
256
]
;
int
result
;
US_DEBUGP
(
"Reading capacity...
\n
"
);
result
=
sddr09_read_deviceID
(
us
,
&
manufacturerID
,
&
deviceID
);
US_DEBUGP
(
"Result of read_deviceID is %d
\n
"
,
result
);
result
=
sddr09_read_deviceID
(
us
,
deviceID
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"Result of read_deviceID is %d
\n
"
,
result
);
printk
(
"sddr09: could not read card info
\n
"
);
return
0
;
}
US_DEBUGP
(
"Device ID = %02X
\n
"
,
deviceID
);
US_DEBUGP
(
"Manuf ID = %02X
\n
"
,
manufacturerID
);
*
pagesize
=
512
;
*
blocksize
=
16
;
switch
(
deviceID
)
{
case
0x6e
:
// 1MB
case
0xe8
:
case
0xec
:
*
pagesize
=
256
;
return
0x00100000
;
case
0xea
:
// 2MB
case
0x5d
:
// 5d is a ROM card with pagesize 512.
case
0x64
:
if
(
deviceID
!=
0x5D
)
*
pagesize
=
256
;
return
0x00200000
;
case
0xe3
:
// 4MB
case
0xe5
:
case
0x6b
:
case
0xd5
:
return
0x00400000
;
case
0xe6
:
// 8MB
case
0xd6
:
return
0x00800000
;
case
0x73
:
// 16MB
*
blocksize
=
32
;
return
0x01000000
;
sprintf
(
blurbtxt
,
"sddr09: Found Flash card, ID = %02X %02X %02X %02X"
,
deviceID
[
0
],
deviceID
[
1
],
deviceID
[
2
],
deviceID
[
3
]);
/* Byte 0 is the manufacturer */
sprintf
(
blurbtxt
+
strlen
(
blurbtxt
),
": Manuf. %s"
,
nand_flash_manufacturer
(
deviceID
[
0
]));
/* Byte 1 is the device type */
cardinfo
=
nand_find_id
(
deviceID
[
1
]);
if
(
cardinfo
)
{
/* MB or MiB? It is neither. A 16 MB card has
17301504 raw bytes, of which 16384000 are
usable for user data. */
sprintf
(
blurbtxt
+
strlen
(
blurbtxt
),
", %d MB"
,
1
<<
(
cardinfo
->
chipshift
-
20
));
}
else
{
sprintf
(
blurbtxt
+
strlen
(
blurbtxt
),
", type unrecognized"
);
}
case
0x75
:
// 32MB
*
blocksize
=
32
;
return
0x02000000
;
/* Byte 2 is code to signal availability of 128-bit ID */
if
(
deviceID
[
2
]
==
0xa5
)
{
sprintf
(
blurbtxt
+
strlen
(
blurbtxt
),
", 128-bit ID"
);
}
case
0x76
:
// 64MB
*
blocksize
=
32
;
return
0x04000000
;
/* Byte 3 announces the availability of another read ID command */
if
(
deviceID
[
3
]
==
0xc0
)
{
sprintf
(
blurbtxt
+
strlen
(
blurbtxt
),
", extra cmd"
);
}
case
0x79
:
// 128MB
*
blocksize
=
32
;
return
0x08000000
;
if
(
flags
&
SDDR09_WP
)
sprintf
(
blurbtxt
+
strlen
(
blurbtxt
),
", WP"
)
;
default:
// unknown
return
0
;
printk
(
"%s
\n
"
,
blurbtxt
);
}
return
cardinfo
;
}
int
sddr09_read_map
(
struct
us_data
*
us
)
{
static
int
sddr09_read_map
(
struct
us_data
*
us
)
{
struct
scatterlist
*
sg
;
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
(
us
->
extra
)
;
int
numblocks
;
int
i
;
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
int
numblocks
,
alloc_len
,
alloc_blocks
;
int
i
,
j
,
result
;
unsigned
char
*
ptr
;
unsigned
short
lba
;
unsigned
char
parity
;
unsigned
char
fast_parity
[
16
]
=
{
0
,
1
,
1
,
0
,
1
,
0
,
0
,
1
,
1
,
0
,
0
,
1
,
0
,
1
,
1
,
0
};
int
result
;
int
alloc_len
;
int
alloc_blocks
;
unsigned
int
lba
,
lbact
;
if
(
!
info
->
capacity
)
return
-
1
;
...
...
@@ -621,7 +1311,7 @@ int sddr09_read_map(struct us_data *us) {
// capacity>>(b+p-6)
alloc_len
=
info
->
capacity
>>
(
info
->
blockshift
+
info
->
pageshift
-
6
);
(
info
->
blockshift
+
info
->
pageshift
-
CONTROL_SHIFT
);
// Allocate a number of scatterlist structures according to
// the number of 128k blocks in the alloc_len. Adding 128k-1
...
...
@@ -660,28 +1350,22 @@ int sddr09_read_map(struct us_data *us) {
numblocks
=
info
->
capacity
>>
(
info
->
blockshift
+
info
->
pageshift
);
if
(
(
result
=
sddr09_read_control
(
us
,
0
,
numblocks
,
(
unsigned
char
*
)
sg
,
alloc_blocks
))
!=
USB_STOR_TRANSPORT_GOOD
)
{
result
=
sddr09_read_control
(
us
,
0
,
numblocks
,
(
unsigned
char
*
)
sg
,
alloc_blocks
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
for
(
i
=
0
;
i
<
alloc_blocks
;
i
++
)
kfree
(
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
);
kfree
(
sg
);
return
-
1
;
}
if
(
info
->
lba_to_pba
)
kfree
(
info
->
lba_to_pba
);
if
(
info
->
pba_to_lba
)
kfree
(
info
->
pba_to_lba
);
info
->
lba_to_pba
=
kmalloc
(
numblocks
*
sizeof
(
int
),
GFP_NOIO
);
info
->
pba_to_lba
=
kmalloc
(
numblocks
*
sizeof
(
int
),
GFP_NOIO
);
if
(
info
->
lba_to_pba
==
NULL
||
info
->
pba_to_lba
==
NULL
)
{
if
(
info
->
lba_to_pba
!=
NULL
)
kfree
(
info
->
lba_to_pba
);
if
(
info
->
pba_to_lba
!=
NULL
)
kfree
(
info
->
pba_to_lba
);
info
->
lba_to_pba
=
NULL
;
info
->
pba_to_lba
=
NULL
;
...
...
@@ -691,64 +1375,137 @@ int sddr09_read_map(struct us_data *us) {
return
0
;
}
memset
(
info
->
lba_to_pba
,
0
,
numblocks
*
sizeof
(
int
));
memset
(
info
->
pba_to_lba
,
0
,
numblocks
*
sizeof
(
int
));
for
(
i
=
0
;
i
<
numblocks
;
i
++
)
info
->
lba_to_pba
[
i
]
=
info
->
pba_to_lba
[
i
]
=
UNDEF
;
ptr
=
page_address
(
sg
[
0
].
page
)
+
sg
[
0
].
offset
;
/*
* Define lba-pba translation table
*/
// Each block is 64 bytes of control data, so block i is located in
// scatterlist block i*64/128k = i*(2^6)*(2^-17) = i*(2^-11)
#if 0
/* No translation */
for (i=0; i<numblocks; i++) {
ptr
=
page_address
(
sg
[
i
>>
11
].
page
)
+
sg
[
i
>>
11
].
offset
+
((
i
&
0x7ff
)
<<
6
);
if
(
ptr
[
0
]
!=
0xFF
||
ptr
[
1
]
!=
0xFF
||
ptr
[
2
]
!=
0xFF
||
ptr
[
3
]
!=
0xFF
||
ptr
[
4
]
!=
0xFF
||
ptr
[
5
]
!=
0xFF
)
{
US_DEBUGP
(
"PBA %04X has no logical mapping: reserved area = "
"%02X%02X%02X%02X data status %02X block status %02X
\n
"
,
i
,
ptr
[
0
],
ptr
[
1
],
ptr
[
2
],
ptr
[
3
],
ptr
[
4
],
ptr
[
5
]);
continue
;
lba = i;
info->pba_to_lba[i] = lba;
info->lba_to_pba[lba] = i;
}
if
((
ptr
[
6
]
>>
4
)
!=
0x01
)
{
US_DEBUGP
(
"PBA %04X has invalid address field %02X%02X/%02X%02X
\n
"
,
i
,
ptr
[
6
],
ptr
[
7
],
ptr
[
11
],
ptr
[
12
]);
printk("sddr09: no translation today\n");
#else
for
(
i
=
0
;
i
<
numblocks
;
i
++
)
{
ptr
=
page_address
(
sg
[
i
>>
11
].
page
)
+
sg
[
i
>>
11
].
offset
+
((
i
&
0x7ff
)
<<
6
);
if
(
i
==
0
||
i
==
1
)
{
info
->
pba_to_lba
[
i
]
=
UNUSABLE
;
continue
;
}
/* ensure even parity */
/* special PBAs have control field 0^16 */
for
(
j
=
0
;
j
<
16
;
j
++
)
if
(
ptr
[
j
]
!=
0
)
goto
nonz
;
info
->
pba_to_lba
[
i
]
=
UNUSABLE
;
printk
(
"sddr09: PBA %04X has no logical mapping
\n
"
,
i
);
continue
;
lba
=
short_pack
(
ptr
[
7
],
ptr
[
6
]);
parity
=
1
;
// the parity of 0x1000
parity
^=
fast_parity
[
lba
&
0x000F
];
parity
^=
fast_parity
[(
lba
>>
4
)
&
0x000F
];
parity
^=
fast_parity
[(
lba
>>
8
)
&
0x000F
];
nonz:
/* unwritten PBAs have control field FF^16 */
for
(
j
=
0
;
j
<
16
;
j
++
)
if
(
ptr
[
j
]
!=
0xff
)
goto
nonff
;
continue
;
if
(
parity
)
{
/* bad parity bit */
US_DEBUGP
(
"Bad parity in LBA for block %04X
\n
"
,
i
);
nonff:
/* normal PBAs start with six FFs */
if
(
j
<
6
)
{
printk
(
"sddr09: PBA %04X has no logical mapping: "
"reserved area = %02X%02X%02X%02X "
"data status %02X block status %02X
\n
"
,
i
,
ptr
[
0
],
ptr
[
1
],
ptr
[
2
],
ptr
[
3
],
ptr
[
4
],
ptr
[
5
]);
info
->
pba_to_lba
[
i
]
=
UNUSABLE
;
continue
;
}
lba
=
(
lba
&
0x07FF
)
>>
1
;
if
((
ptr
[
6
]
>>
4
)
!=
0x01
)
{
printk
(
"sddr09: PBA %04X has invalid address field "
"%02X%02X/%02X%02X
\n
"
,
i
,
ptr
[
6
],
ptr
[
7
],
ptr
[
11
],
ptr
[
12
]);
info
->
pba_to_lba
[
i
]
=
UNUSABLE
;
continue
;
}
/* Every 1024 physical blocks ("zone"), the LBA numbers
* go back to zero, but are within a higher
* block of LBA's. Also, there is a maximum of
* 1000 LBA's per zone. In other words, in PBA
* 1024-2047 you will find LBA 0-999 which are
* really LBA 1000-1999. Yes, this wastes 24
* physical blocks per zone. Go figure.
*/
/* check even parity */
if
(
parity
[
ptr
[
6
]
^
ptr
[
7
]])
{
printk
(
"sddr09: Bad parity in LBA for block %04X"
" (%02X %02X)
\n
"
,
i
,
ptr
[
6
],
ptr
[
7
]);
info
->
pba_to_lba
[
i
]
=
UNUSABLE
;
continue
;
}
lba
+=
1000
*
(
i
/
0x400
);
lba
=
short_pack
(
ptr
[
7
],
ptr
[
6
]);
lba
=
(
lba
&
0x07FF
)
>>
1
;
/*
* Every 1024 physical blocks ("zone"), the LBA numbers
* go back to zero, but are within a higher block of LBA's.
* Also, there is a maximum of 1000 LBA's per zone.
* In other words, in PBA 1024-2047 you will find LBA 0-999
* which are really LBA 1000-1999. This allows for 24 bad
* or special physical blocks per zone.
*/
if
(
lba
>=
numblocks
)
{
US_DEBUGP
(
"Bad LBA %04X for block %04X
\n
"
,
lba
,
i
);
if
(
lba
>=
1000
)
{
unsigned
long
address
;
printk
(
"sddr09: Bad LBA %04X for block %04X
\n
"
,
lba
,
i
);
info
->
pba_to_lba
[
i
]
=
UNDEF
/* UNUSABLE */
;
if
(
erase_bad_lba_entries
)
{
/* some cameras cannot erase a card if it has
bad entries, so we supply this function */
address
=
(
i
<<
(
info
->
pageshift
+
info
->
blockshift
));
sddr09_erase
(
us
,
address
>>
1
);
}
continue
;
}
if
(
lba
<
0x10
||
(
lba
>=
0x3E0
&&
lba
<
0x3EF
))
lba
+=
1000
*
(
i
/
0x400
);
if
(
lba
<
0x10
||
(
lba
>=
0x3E0
&&
lba
<
0x3EF
))
US_DEBUGP
(
"LBA %04X <-> PBA %04X
\n
"
,
lba
,
i
);
info
->
pba_to_lba
[
i
]
=
lba
;
info
->
lba_to_pba
[
lba
]
=
i
;
}
#endif
/*
* Approximate capacity. This is not entirely correct yet,
* since a zone with less than 1000 usable pages leads to
* missing LBAs. Especially if it is the last zone, some
* LBAs can be past capacity.
*/
lbact
=
0
;
for
(
i
=
0
;
i
<
numblocks
;
i
+=
1024
)
{
int
ct
=
0
;
for
(
j
=
0
;
j
<
1024
&&
i
+
j
<
numblocks
;
j
++
)
{
if
(
info
->
pba_to_lba
[
i
+
j
]
!=
UNUSABLE
)
{
if
(
ct
>=
1000
)
info
->
pba_to_lba
[
i
+
j
]
=
SPARE
;
else
ct
++
;
}
}
lbact
+=
ct
;
}
info
->
lbact
=
lbact
;
US_DEBUGP
(
"Found %d LBA's
\n
"
,
lbact
);
for
(
i
=
0
;
i
<
alloc_blocks
;
i
++
)
kfree
(
page_address
(
sg
[
i
].
page
)
+
sg
[
i
].
offset
);
...
...
@@ -756,67 +1513,74 @@ int sddr09_read_map(struct us_data *us) {
return
0
;
}
/*
static int init_sddr09(struct us_data *us) {
int result;
unsigned char data[14];
unsigned char command[8] = {
0xc1, 0x01, 0, 0, 0, 0, 0, 0
};
unsigned char command2[8] = {
0x41, 0, 0, 0, 0, 0, 0, 0
};
unsigned char tur[12] = {
0x03, 0x20, 0, 0, 0x0e, 0, 0, 0, 0, 0, 0, 0
};
static
void
sddr09_card_info_destructor
(
void
*
extra
)
{
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
extra
;
// What the hey is all this for? Doesn't seem to
// affect the device, so we won't do device inits.
if
(
!
info
)
return
;
if ( (result = sddr09_send_control(us, command, data, 2)) !=
USB_STOR_TRANSPORT_GOOD)
return result;
kfree
(
info
->
lba_to_pba
);
kfree
(
info
->
pba_to_lba
);
}
US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
static
void
sddr09_init_card_info
(
struct
us_data
*
us
)
{
if
(
!
us
->
extra
)
{
us
->
extra
=
kmalloc
(
sizeof
(
struct
sddr09_card_info
),
GFP_NOIO
);
if
(
us
->
extra
)
{
memset
(
us
->
extra
,
0
,
sizeof
(
struct
sddr09_card_info
));
us
->
extra_destructor
=
sddr09_card_info_destructor
;
}
}
}
command[1] = 0x08;
/*
* This is needed at a very early stage. If this is not listed in the
* unusual devices list but called from here then LUN 0 of the combo reader
* is not recognized. But I do not know what precisely these calls do.
*/
int
sddr09_init
(
struct
us_data
*
us
)
{
int
result
;
unsigned
char
data
[
18
];
if ( (result = sddr09_send_control(us, command, data, 2)) !=
USB_STOR_TRANSPORT_GOOD)
result
=
sddr09_send_command
(
us
,
0x01
,
USB_DIR_IN
,
data
,
2
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"sddr09_init: send_command fails
\n
"
);
return
result
;
}
US_DEBUGP("SDDR09: %02X %02X\n", data[0], data[1]);
US_DEBUGP
(
"SDDR09init: %02X %02X
\n
"
,
data
[
0
],
data
[
1
]);
// get 07 02
if ( (result = sddr09_send_control(us, command2, tur, 12)) !=
USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("
SDDR09: request sense failed
\n");
result
=
sddr09_send_command
(
us
,
0x08
,
USB_DIR_IN
,
data
,
2
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"
sddr09_init: 2nd send_command fails
\n
"
);
return
result
;
}
if ( (result = sddr09_raw_bulk(
us, SCSI_DATA_READ, data, 14)) !=
USB_STOR_TRANSPORT_GOOD) {
US_DEBUGP("SDDR09: request sense bulk in failed\n");
return result;
US_DEBUGP
(
"SDDR09init: %02X %02X
\n
"
,
data
[
0
],
data
[
1
]);
// get 07 00
result
=
sddr09_request_sense
(
us
,
data
,
sizeof
(
data
));
if
(
result
==
USB_STOR_TRANSPORT_GOOD
&&
data
[
2
]
!=
0
)
{
int
j
;
for
(
j
=
0
;
j
<
sizeof
(
data
);
j
++
)
printk
(
" %02X"
,
data
[
j
]);
printk
(
"
\n
"
);
// get 70 00 00 00 00 00 00 * 00 00 00 00 00 00
// 70: current command
// sense key 0, sense code 0, extd sense code 0
// additional transfer length * = sizeof(data) - 7
// Or: 70 00 06 00 00 00 00 0b 00 00 00 00 28 00 00 00 00 00
// sense key 06, sense code 28: unit attention,
// not ready to ready transition
}
US_DEBUGP("SDDR09: request sense worked\n");
return result;
}
*/
void
sddr09_card_info_destructor
(
void
*
extra
)
{
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)
extra
;
// test unit ready
if
(
!
extra
)
return
;
if
(
info
->
lba_to_pba
)
kfree
(
info
->
lba_to_pba
);
if
(
info
->
pba_to_lba
)
kfree
(
info
->
pba_to_lba
);
return
USB_STOR_TRANSPORT_GOOD
;
/* not result */
}
/*
...
...
@@ -824,36 +1588,53 @@ void sddr09_card_info_destructor(void *extra) {
*/
int
sddr09_transport
(
Scsi_Cmnd
*
srb
,
struct
us_data
*
us
)
{
int
result
;
int
i
;
static
unsigned
char
sensekey
=
0
,
sensecode
=
0
;
static
unsigned
char
havefakesense
=
0
;
int
result
,
i
;
unsigned
char
*
ptr
;
unsigned
long
capacity
;
unsigned
int
page
,
pages
;
char
string
[
64
];
struct
sddr09_card_info
*
info
;
unsigned
char
inquiry_response
[
36
]
=
{
0x00
,
0x80
,
0x00
,
0x02
,
0x1F
,
0x00
,
0x00
,
0x00
};
unsigned
char
mode_page_01
[
16
]
=
{
// write-protected for now
0x03
,
0x00
,
0x80
,
0x00
,
unsigned
char
mode_page_01
[
16
]
=
{
0x0F
,
0x00
,
0
,
0x00
,
0x01
,
0x0A
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
,
0x00
};
unsigned
char
*
ptr
;
unsigned
long
capacity
;
unsigned
int
lba
;
unsigned
int
pba
;
unsigned
int
page
;
unsigned
short
pages
;
struct
sddr09_card_info
*
info
=
(
struct
sddr09_card_info
*
)(
us
->
extra
);
if
(
!
us
->
extra
)
{
us
->
extra
=
kmalloc
(
sizeof
(
struct
sddr09_card_info
),
GFP_NOIO
);
if
(
!
us
->
extra
)
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
if
(
!
info
)
{
nand_init_ecc
();
sddr09_init_card_info
(
us
);
info
=
(
struct
sddr09_card_info
*
)
us
->
extra
;
if
(
!
info
)
return
USB_STOR_TRANSPORT_ERROR
;
memset
(
us
->
extra
,
0
,
sizeof
(
struct
sddr09_card_info
));
us
->
extra_destructor
=
sddr09_card_info_destructor
;
}
ptr
=
(
unsigned
char
*
)
srb
->
request_buffer
;
if
(
srb
->
cmnd
[
0
]
==
REQUEST_SENSE
&&
havefakesense
)
{
/* for a faked command, we have to follow with a faked sense */
memset
(
ptr
,
0
,
srb
->
request_bufflen
);
if
(
srb
->
request_bufflen
>
7
)
{
ptr
[
0
]
=
0x70
;
ptr
[
2
]
=
sensekey
;
ptr
[
7
]
=
srb
->
request_bufflen
-
7
;
}
if
(
srb
->
request_bufflen
>
12
)
ptr
[
12
]
=
sensecode
;
sensekey
=
sensecode
=
havefakesense
=
0
;
return
USB_STOR_TRANSPORT_GOOD
;
}
havefakesense
=
1
;
/* Dummy up a response for INQUIRY since SDDR09 doesn't
respond to INQUIRY commands */
...
...
@@ -864,43 +1645,44 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
}
if
(
srb
->
cmnd
[
0
]
==
READ_CAPACITY
)
{
struct
nand_flash_dev
*
cardinfo
;
capacity
=
sddr09_get_capacity
(
us
,
&
info
->
pagesize
,
&
info
->
blocksize
);
sddr09_get_wp
(
us
,
info
);
/* read WP bit */
if
(
!
capacity
)
cardinfo
=
sddr09_get_cardinfo
(
us
,
info
->
flags
);
if
(
!
cardinfo
)
{
/* probably no media */
sensekey
=
0x02
;
/* not ready */
sensecode
=
0x3a
;
/* medium not present */
return
USB_STOR_TRANSPORT_FAILED
;
}
info
->
capacity
=
capacity
;
for
(
info
->
pageshift
=
1
;
(
info
->
pagesize
>>
info
->
pageshift
);
info
->
pageshift
++
);
info
->
pageshift
--
;
for
(
info
->
blockshift
=
1
;
(
info
->
blocksize
>>
info
->
blockshift
);
info
->
blockshift
++
);
info
->
blockshift
--
;
info
->
blockmask
=
(
1
<<
info
->
blockshift
)
-
1
;
info
->
capacity
=
(
1
<<
cardinfo
->
chipshift
);
info
->
pageshift
=
cardinfo
->
pageshift
;
info
->
pagesize
=
(
1
<<
info
->
pageshift
);
info
->
blockshift
=
cardinfo
->
blockshift
;
info
->
blocksize
=
(
1
<<
info
->
blockshift
);
info
->
blockmask
=
info
->
blocksize
-
1
;
// map initialization, must follow get_cardinfo()
sddr09_read_map
(
us
);
//
Last page in the card
//
Report capacity
capacity
/=
info
->
pagesize
;
capacity
--
;
capacity
=
(
info
->
lbact
<<
info
->
blockshift
)
-
1
;
ptr
[
0
]
=
MSB_of
(
capacity
>>
16
);
ptr
[
1
]
=
LSB_of
(
capacity
>>
16
);
ptr
[
2
]
=
MSB_of
(
capacity
&
0xFFFF
);
ptr
[
3
]
=
LSB_of
(
capacity
&
0xFFFF
);
//
The
page size
//
Report
page size
ptr
[
4
]
=
MSB_of
(
info
->
pagesize
>>
16
);
ptr
[
5
]
=
LSB_of
(
info
->
pagesize
>>
16
);
ptr
[
6
]
=
MSB_of
(
info
->
pagesize
&
0xFFFF
);
ptr
[
7
]
=
LSB_of
(
info
->
pagesize
&
0xFFFF
);
sddr09_read_map
(
us
);
return
USB_STOR_TRANSPORT_GOOD
;
}
...
...
@@ -914,19 +1696,21 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP
(
"SDDR09: Dummy up request for mode page 1
\n
"
);
if
(
ptr
==
NULL
||
if
(
ptr
==
NULL
||
srb
->
request_bufflen
<
sizeof
(
mode_page_01
))
return
USB_STOR_TRANSPORT_ERROR
;
mode_page_01
[
0
]
=
sizeof
(
mode_page_01
)
-
1
;
mode_page_01
[
2
]
=
(
info
->
flags
&
SDDR09_WP
)
?
0x80
:
0
;
memcpy
(
ptr
,
mode_page_01
,
sizeof
(
mode_page_01
));
return
USB_STOR_TRANSPORT_GOOD
;
}
else
if
(
(
srb
->
cmnd
[
2
]
&
0x3F
)
==
0x3F
)
{
US_DEBUGP
(
"SDDR09: Dummy up request for
all mode pages
\n
"
);
US_DEBUGP
(
"SDDR09: Dummy up request for "
"
all mode pages
\n
"
);
if
(
ptr
==
NULL
||
if
(
ptr
==
NULL
||
srb
->
request_bufflen
<
sizeof
(
mode_page_01
))
return
USB_STOR_TRANSPORT_ERROR
;
...
...
@@ -935,8 +1719,6 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
}
// FIXME: sense buffer?
return
USB_STOR_TRANSPORT_ERROR
;
}
...
...
@@ -951,6 +1733,8 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
}
havefakesense
=
0
;
if
(
srb
->
cmnd
[
0
]
==
READ_10
)
{
page
=
short_pack
(
srb
->
cmnd
[
3
],
srb
->
cmnd
[
2
]);
...
...
@@ -958,61 +1742,37 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
page
|=
short_pack
(
srb
->
cmnd
[
5
],
srb
->
cmnd
[
4
]);
pages
=
short_pack
(
srb
->
cmnd
[
8
],
srb
->
cmnd
[
7
]);
// convert page to block and page-within-block
lba
=
page
>>
info
->
blockshift
;
page
=
page
&
info
->
blockmask
;
// locate physical block corresponding to logical block
if
(
lba
>=
(
info
->
capacity
>>
(
info
->
pageshift
+
info
->
blockshift
)
)
)
{
US_DEBUGP
(
"READ_10: read page %d pagect %d
\n
"
,
page
,
pages
);
US_DEBUGP
(
"Error: Requested LBA %04X exceeds maximum "
"block %04lX
\n
"
,
lba
,
(
info
->
capacity
>>
(
info
->
pageshift
+
info
->
blockshift
))
-
1
);
// FIXME: sense buffer?
return
USB_STOR_TRANSPORT_ERROR
;
return
sddr09_read_data
(
us
,
page
,
pages
,
ptr
,
srb
->
use_sg
);
}
pba
=
info
->
lba_to_pba
[
lba
];
// if pba is 0, either it's really 0, in which case
// the pba-to-lba map for pba 0 will be the lba,
// or that lba doesn't exist.
if
(
pba
==
0
&&
info
->
pba_to_lba
[
0
]
!=
lba
)
{
// FIXME: sense buffer?
US_DEBUGP
(
"Error: Requested LBA %04X has no physical block "
"mapping.
\n
"
,
lba
);
if
(
srb
->
cmnd
[
0
]
==
WRITE_10
)
{
return
USB_STOR_TRANSPORT_ERROR
;
}
page
=
short_pack
(
srb
->
cmnd
[
3
],
srb
->
cmnd
[
2
]);
page
<<=
16
;
page
|=
short_pack
(
srb
->
cmnd
[
5
],
srb
->
cmnd
[
4
]);
pages
=
short_pack
(
srb
->
cmnd
[
8
],
srb
->
cmnd
[
7
]);
US_DEBUGP
(
"READ_10: read block %04X (LBA %04X) page %01X"
" pages %d
\n
"
,
pba
,
lba
,
page
,
pages
);
US_DEBUGP
(
"WRITE_10: write page %d pagect %d
\n
"
,
page
,
pages
);
return
sddr09_read_data
(
us
,
(
(
pba
<<
info
->
blockshift
)
+
page
)
<<
info
->
pageshift
,
pages
,
ptr
,
srb
->
use_sg
);
return
sddr09_write_data
(
us
,
page
,
pages
,
ptr
,
srb
->
use_sg
);
}
// Pass TEST_UNIT_READY and REQUEST_SENSE through
if
(
srb
->
cmnd
[
0
]
!=
TEST_UNIT_READY
&&
srb
->
cmnd
[
0
]
!=
REQUEST_SENSE
)
return
USB_STOR_TRANSPORT_ERROR
;
// FIXME: sense buffer?
srb
->
cmnd
[
0
]
!=
REQUEST_SENSE
)
{
havefakesense
=
1
;
return
USB_STOR_TRANSPORT_ERROR
;
}
for
(;
srb
->
cmd_len
<
12
;
srb
->
cmd_len
++
)
srb
->
cmnd
[
srb
->
cmd_len
]
=
0
;
srb
->
cmnd
[
1
]
=
0x20
;
srb
->
cmnd
[
1
]
=
LUNBITS
;
string
[
0
]
=
0
;
for
(
i
=
0
;
i
<
12
;
i
++
)
...
...
@@ -1021,17 +1781,12 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
US_DEBUGP
(
"SDDR09: Send control for command %s
\n
"
,
string
);
if
(
(
result
=
sddr09_send_control
(
us
,
usb_sndctrlpipe
(
us
->
pusb_dev
,
0
),
0
,
0x41
,
0
,
0
,
srb
->
cmnd
,
12
))
!=
USB_STOR_TRANSPORT_GOOD
)
result
=
sddr09_send_scsi_command
(
us
,
srb
->
cmnd
,
12
);
if
(
result
!=
USB_STOR_TRANSPORT_GOOD
)
{
US_DEBUGP
(
"sddr09_transport: sddr09_send_scsi_command "
"returns %d
\n
"
,
result
);
return
result
;
US_DEBUGP
(
"SDDR09: Control for command OK
\n
"
);
}
if
(
srb
->
request_bufflen
==
0
)
return
USB_STOR_TRANSPORT_GOOD
;
...
...
@@ -1040,17 +1795,17 @@ int sddr09_transport(Scsi_Cmnd *srb, struct us_data *us)
srb
->
sc_data_direction
==
SCSI_DATA_READ
)
{
US_DEBUGP
(
"SDDR09: %s %d bytes
\n
"
,
srb
->
sc_data_direction
==
SCSI_DATA_WRITE
?
(
srb
->
sc_data_direction
==
SCSI_DATA_WRITE
)
?
"sending"
:
"receiving"
,
srb
->
request_bufflen
);
result
=
sddr09_bulk_transport
(
us
,
srb
->
sc_data_direction
,
srb
->
request_buffer
,
srb
->
request_bufflen
,
srb
->
use_sg
);
srb
->
request_bufflen
,
srb
->
use_sg
);
return
result
;
}
return
USB_STOR_TRANSPORT_GOOD
;
...
...
drivers/usb/storage/sddr09.h
View file @
4bc91a02
...
...
@@ -5,6 +5,7 @@
*
* Current development and maintenance by:
* (c) 2000 Robert Baruch (autophile@dol.net)
* (c) 2002 Andries Brouwer (aeb@cwi.nl)
*
* See sddr09.c for more explanation
*
...
...
@@ -39,6 +40,9 @@ struct sddr09_card_info {
int
blockmask
;
/* 2^blockshift - 1 */
int
*
lba_to_pba
;
/* logical to physical map */
int
*
pba_to_lba
;
/* physical to logical map */
int
lbact
;
/* number of available pages */
int
flags
;
#define SDDR09_WP 1
/* write protected */
};
#endif
drivers/usb/storage/unusual_devs.h
View file @
4bc91a02
...
...
@@ -130,14 +130,14 @@ UNUSUAL_DEV( 0x04e6, 0x0003, 0x0000, 0x9999,
"ImageMate SDDR09"
,
US_SC_SCSI
,
US_PR_EUSB_SDDR09
,
NULL
,
US_FL_SINGLE_LUN
|
US_FL_START_STOP
),
#endif
/* This entry is from Andries.Brouwer@cwi.nl */
UNUSUAL_DEV
(
0x04e6
,
0x0005
,
0x0100
,
0x0208
,
"SCM Microsystems"
,
"eUSB SmartMedia / CompactFlash Adapter"
,
US_SC_SCSI
,
US_PR_DPCM_USB
,
NULL
,
US_SC_SCSI
,
US_PR_DPCM_USB
,
sddr09_init
,
US_FL_START_STOP
),
#endif
UNUSUAL_DEV
(
0x04e6
,
0x0006
,
0x0100
,
0x0205
,
"Shuttle"
,
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment