Commit 628c2893 authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

USB: ene_usb6250: fix DMA to the stack

The ene_usb6250 sub-driver in usb-storage does USB I/O to buffers on
the stack, which doesn't work with vmapped stacks.  This patch fixes
the problem by allocating a separate 512-byte buffer at probe time and
using it for all of the offending I/O operations.
Signed-off-by: default avatarAlan Stern <stern@rowland.harvard.edu>
Reported-and-tested-by: default avatarAndreas Hartmann <andihartmann@01019freenet.de>
CC: <stable@vger.kernel.org>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 9b31071d
...@@ -446,6 +446,10 @@ struct ms_lib_ctrl { ...@@ -446,6 +446,10 @@ struct ms_lib_ctrl {
#define SD_BLOCK_LEN 9 #define SD_BLOCK_LEN 9
struct ene_ub6250_info { struct ene_ub6250_info {
/* I/O bounce buffer */
u8 *bbuf;
/* for 6250 code */ /* for 6250 code */
struct SD_STATUS SD_Status; struct SD_STATUS SD_Status;
struct MS_STATUS MS_Status; struct MS_STATUS MS_Status;
...@@ -493,8 +497,11 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag); ...@@ -493,8 +497,11 @@ static int ene_load_bincode(struct us_data *us, unsigned char flag);
static void ene_ub6250_info_destructor(void *extra) static void ene_ub6250_info_destructor(void *extra)
{ {
struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra;
if (!extra) if (!extra)
return; return;
kfree(info->bbuf);
} }
static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg) static int ene_send_scsi_cmd(struct us_data *us, u8 fDir, void *buf, int use_sg)
...@@ -860,8 +867,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr, ...@@ -860,8 +867,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat) u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat)
{ {
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
u8 *bbuf = info->bbuf;
int result; int result;
u8 ExtBuf[4];
u32 bn = PhyBlockAddr * 0x20 + PageNum; u32 bn = PhyBlockAddr * 0x20 + PageNum;
result = ene_load_bincode(us, MS_RW_PATTERN); result = ene_load_bincode(us, MS_RW_PATTERN);
...@@ -901,7 +909,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr, ...@@ -901,7 +909,7 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16); bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16);
bcb->CDB[6] = 0x01; bcb->CDB[6] = 0x01;
result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0); result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -910,9 +918,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr, ...@@ -910,9 +918,9 @@ static int ms_read_readpage(struct us_data *us, u32 PhyBlockAddr,
ExtraDat->status0 = 0x10; /* Not yet,fireware support */ ExtraDat->status0 = 0x10; /* Not yet,fireware support */
ExtraDat->status1 = 0x00; /* Not yet,fireware support */ ExtraDat->status1 = 0x00; /* Not yet,fireware support */
ExtraDat->ovrflg = ExtBuf[0]; ExtraDat->ovrflg = bbuf[0];
ExtraDat->mngflg = ExtBuf[1]; ExtraDat->mngflg = bbuf[1];
ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]); ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]);
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
} }
...@@ -1332,8 +1340,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, ...@@ -1332,8 +1340,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
u8 PageNum, struct ms_lib_type_extdat *ExtraDat) u8 PageNum, struct ms_lib_type_extdat *ExtraDat)
{ {
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
u8 *bbuf = info->bbuf;
int result; int result;
u8 ExtBuf[4];
memset(bcb, 0, sizeof(struct bulk_cb_wrap)); memset(bcb, 0, sizeof(struct bulk_cb_wrap));
bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN);
...@@ -1347,7 +1356,7 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, ...@@ -1347,7 +1356,7 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
bcb->CDB[2] = (unsigned char)(PhyBlock>>16); bcb->CDB[2] = (unsigned char)(PhyBlock>>16);
bcb->CDB[6] = 0x01; bcb->CDB[6] = 0x01;
result = ene_send_scsi_cmd(us, FDIR_READ, &ExtBuf, 0); result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
...@@ -1355,9 +1364,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock, ...@@ -1355,9 +1364,9 @@ static int ms_lib_read_extra(struct us_data *us, u32 PhyBlock,
ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */ ExtraDat->intr = 0x80; /* Not yet, waiting for fireware support */
ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */ ExtraDat->status0 = 0x10; /* Not yet, waiting for fireware support */
ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */ ExtraDat->status1 = 0x00; /* Not yet, waiting for fireware support */
ExtraDat->ovrflg = ExtBuf[0]; ExtraDat->ovrflg = bbuf[0];
ExtraDat->mngflg = ExtBuf[1]; ExtraDat->mngflg = bbuf[1];
ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]); ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]);
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
} }
...@@ -1556,9 +1565,9 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st) ...@@ -1556,9 +1565,9 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
u16 PhyBlock, newblk, i; u16 PhyBlock, newblk, i;
u16 LogStart, LogEnde; u16 LogStart, LogEnde;
struct ms_lib_type_extdat extdat; struct ms_lib_type_extdat extdat;
u8 buf[0x200];
u32 count = 0, index = 0; u32 count = 0, index = 0;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
u8 *bbuf = info->bbuf;
for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) { for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) {
ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde); ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde);
...@@ -1572,14 +1581,16 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st) ...@@ -1572,14 +1581,16 @@ static int ms_lib_scan_logicalblocknumber(struct us_data *us, u16 btBlk1st)
} }
if (count == PhyBlock) { if (count == PhyBlock) {
ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf); ms_lib_read_extrablock(us, PhyBlock, 0, 0x80,
bbuf);
count += 0x80; count += 0x80;
} }
index = (PhyBlock % 0x80) * 4; index = (PhyBlock % 0x80) * 4;
extdat.ovrflg = buf[index]; extdat.ovrflg = bbuf[index];
extdat.mngflg = buf[index+1]; extdat.mngflg = bbuf[index+1];
extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]); extdat.logadr = memstick_logaddr(bbuf[index+2],
bbuf[index+3]);
if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) { if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) {
ms_lib_setacquired_errorblock(us, PhyBlock); ms_lib_setacquired_errorblock(us, PhyBlock);
...@@ -2062,9 +2073,9 @@ static int ene_ms_init(struct us_data *us) ...@@ -2062,9 +2073,9 @@ static int ene_ms_init(struct us_data *us)
{ {
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
int result; int result;
u8 buf[0x200];
u16 MSP_BlockSize, MSP_UserAreaBlocks; u16 MSP_BlockSize, MSP_UserAreaBlocks;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
u8 *bbuf = info->bbuf;
printk(KERN_INFO "transport --- ENE_MSInit\n"); printk(KERN_INFO "transport --- ENE_MSInit\n");
...@@ -2083,13 +2094,13 @@ static int ene_ms_init(struct us_data *us) ...@@ -2083,13 +2094,13 @@ static int ene_ms_init(struct us_data *us)
bcb->CDB[0] = 0xF1; bcb->CDB[0] = 0xF1;
bcb->CDB[1] = 0x01; bcb->CDB[1] = 0x01;
result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
printk(KERN_ERR "Execution MS Init Code Fail !!\n"); printk(KERN_ERR "Execution MS Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
/* the same part to test ENE */ /* the same part to test ENE */
info->MS_Status = *(struct MS_STATUS *)&buf[0]; info->MS_Status = *(struct MS_STATUS *) bbuf;
if (info->MS_Status.Insert && info->MS_Status.Ready) { if (info->MS_Status.Insert && info->MS_Status.Ready) {
printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert); printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert);
...@@ -2098,15 +2109,15 @@ static int ene_ms_init(struct us_data *us) ...@@ -2098,15 +2109,15 @@ static int ene_ms_init(struct us_data *us)
printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG); printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG);
printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP); printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP);
if (info->MS_Status.IsMSPro) { if (info->MS_Status.IsMSPro) {
MSP_BlockSize = (buf[6] << 8) | buf[7]; MSP_BlockSize = (bbuf[6] << 8) | bbuf[7];
MSP_UserAreaBlocks = (buf[10] << 8) | buf[11]; MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11];
info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks;
} else { } else {
ms_card_init(us); /* Card is MS (to ms.c)*/ ms_card_init(us); /* Card is MS (to ms.c)*/
} }
usb_stor_dbg(us, "MS Init Code OK !!\n"); usb_stor_dbg(us, "MS Init Code OK !!\n");
} else { } else {
usb_stor_dbg(us, "MS Card Not Ready --- %x\n", buf[0]); usb_stor_dbg(us, "MS Card Not Ready --- %x\n", bbuf[0]);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
...@@ -2116,9 +2127,9 @@ static int ene_ms_init(struct us_data *us) ...@@ -2116,9 +2127,9 @@ static int ene_ms_init(struct us_data *us)
static int ene_sd_init(struct us_data *us) static int ene_sd_init(struct us_data *us)
{ {
int result; int result;
u8 buf[0x200];
struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf;
struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra;
u8 *bbuf = info->bbuf;
usb_stor_dbg(us, "transport --- ENE_SDInit\n"); usb_stor_dbg(us, "transport --- ENE_SDInit\n");
/* SD Init Part-1 */ /* SD Init Part-1 */
...@@ -2152,17 +2163,17 @@ static int ene_sd_init(struct us_data *us) ...@@ -2152,17 +2163,17 @@ static int ene_sd_init(struct us_data *us)
bcb->Flags = US_BULK_FLAG_IN; bcb->Flags = US_BULK_FLAG_IN;
bcb->CDB[0] = 0xF1; bcb->CDB[0] = 0xF1;
result = ene_send_scsi_cmd(us, FDIR_READ, &buf, 0); result = ene_send_scsi_cmd(us, FDIR_READ, bbuf, 0);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
usb_stor_dbg(us, "Execution SD Init Code Fail !!\n"); usb_stor_dbg(us, "Execution SD Init Code Fail !!\n");
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
info->SD_Status = *(struct SD_STATUS *)&buf[0]; info->SD_Status = *(struct SD_STATUS *) bbuf;
if (info->SD_Status.Insert && info->SD_Status.Ready) { if (info->SD_Status.Insert && info->SD_Status.Ready) {
struct SD_STATUS *s = &info->SD_Status; struct SD_STATUS *s = &info->SD_Status;
ene_get_card_status(us, (unsigned char *)&buf); ene_get_card_status(us, bbuf);
usb_stor_dbg(us, "Insert = %x\n", s->Insert); usb_stor_dbg(us, "Insert = %x\n", s->Insert);
usb_stor_dbg(us, "Ready = %x\n", s->Ready); usb_stor_dbg(us, "Ready = %x\n", s->Ready);
usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC); usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC);
...@@ -2170,7 +2181,7 @@ static int ene_sd_init(struct us_data *us) ...@@ -2170,7 +2181,7 @@ static int ene_sd_init(struct us_data *us)
usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed); usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed);
usb_stor_dbg(us, "WtP = %x\n", s->WtP); usb_stor_dbg(us, "WtP = %x\n", s->WtP);
} else { } else {
usb_stor_dbg(us, "SD Card Not Ready --- %x\n", buf[0]); usb_stor_dbg(us, "SD Card Not Ready --- %x\n", bbuf[0]);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
return USB_STOR_TRANSPORT_GOOD; return USB_STOR_TRANSPORT_GOOD;
...@@ -2180,13 +2191,15 @@ static int ene_sd_init(struct us_data *us) ...@@ -2180,13 +2191,15 @@ static int ene_sd_init(struct us_data *us)
static int ene_init(struct us_data *us) static int ene_init(struct us_data *us)
{ {
int result; int result;
u8 misc_reg03 = 0; u8 misc_reg03;
struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra); struct ene_ub6250_info *info = (struct ene_ub6250_info *)(us->extra);
u8 *bbuf = info->bbuf;
result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03); result = ene_get_card_type(us, REG_CARD_STATUS, bbuf);
if (result != USB_STOR_XFER_GOOD) if (result != USB_STOR_XFER_GOOD)
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
misc_reg03 = bbuf[0];
if (misc_reg03 & 0x01) { if (misc_reg03 & 0x01) {
if (!info->SD_Status.Ready) { if (!info->SD_Status.Ready) {
result = ene_sd_init(us); result = ene_sd_init(us);
...@@ -2303,8 +2316,9 @@ static int ene_ub6250_probe(struct usb_interface *intf, ...@@ -2303,8 +2316,9 @@ static int ene_ub6250_probe(struct usb_interface *intf,
const struct usb_device_id *id) const struct usb_device_id *id)
{ {
int result; int result;
u8 misc_reg03 = 0; u8 misc_reg03;
struct us_data *us; struct us_data *us;
struct ene_ub6250_info *info;
result = usb_stor_probe1(&us, intf, id, result = usb_stor_probe1(&us, intf, id,
(id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list, (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list,
...@@ -2313,11 +2327,16 @@ static int ene_ub6250_probe(struct usb_interface *intf, ...@@ -2313,11 +2327,16 @@ static int ene_ub6250_probe(struct usb_interface *intf,
return result; return result;
/* FIXME: where should the code alloc extra buf ? */ /* FIXME: where should the code alloc extra buf ? */
if (!us->extra) {
us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL); us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL);
if (!us->extra) if (!us->extra)
return -ENOMEM; return -ENOMEM;
us->extra_destructor = ene_ub6250_info_destructor; us->extra_destructor = ene_ub6250_info_destructor;
info = (struct ene_ub6250_info *)(us->extra);
info->bbuf = kmalloc(512, GFP_KERNEL);
if (!info->bbuf) {
kfree(us->extra);
return -ENOMEM;
} }
us->transport_name = "ene_ub6250"; us->transport_name = "ene_ub6250";
...@@ -2329,12 +2348,13 @@ static int ene_ub6250_probe(struct usb_interface *intf, ...@@ -2329,12 +2348,13 @@ static int ene_ub6250_probe(struct usb_interface *intf,
return result; return result;
/* probe card type */ /* probe card type */
result = ene_get_card_type(us, REG_CARD_STATUS, &misc_reg03); result = ene_get_card_type(us, REG_CARD_STATUS, info->bbuf);
if (result != USB_STOR_XFER_GOOD) { if (result != USB_STOR_XFER_GOOD) {
usb_stor_disconnect(intf); usb_stor_disconnect(intf);
return USB_STOR_TRANSPORT_ERROR; return USB_STOR_TRANSPORT_ERROR;
} }
misc_reg03 = info->bbuf[0];
if (!(misc_reg03 & 0x01)) { if (!(misc_reg03 & 0x01)) {
pr_info("ums_eneub6250: This driver only supports SD/MS cards. " pr_info("ums_eneub6250: This driver only supports SD/MS cards. "
"It does not support SM cards.\n"); "It does not support SM cards.\n");
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment