| From 628c2893d44876ddd11602400c70606ade62e129 Mon Sep 17 00:00:00 2001 |
| From: Alan Stern <stern@rowland.harvard.edu> |
| Date: Tue, 16 May 2017 11:47:29 -0400 |
| Subject: USB: ene_usb6250: fix DMA to the stack |
| |
| From: Alan Stern <stern@rowland.harvard.edu> |
| |
| commit 628c2893d44876ddd11602400c70606ade62e129 upstream. |
| |
| 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: Alan Stern <stern@rowland.harvard.edu> |
| Reported-and-tested-by: Andreas Hartmann <andihartmann@01019freenet.de> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| drivers/usb/storage/ene_ub6250.c | 90 +++++++++++++++++++++++---------------- |
| 1 file changed, 55 insertions(+), 35 deletions(-) |
| |
| --- a/drivers/usb/storage/ene_ub6250.c |
| +++ b/drivers/usb/storage/ene_ub6250.c |
| @@ -446,6 +446,10 @@ struct ms_lib_ctrl { |
| #define SD_BLOCK_LEN 9 |
| |
| struct ene_ub6250_info { |
| + |
| + /* I/O bounce buffer */ |
| + u8 *bbuf; |
| + |
| /* for 6250 code */ |
| struct SD_STATUS SD_Status; |
| struct MS_STATUS MS_Status; |
| @@ -493,8 +497,11 @@ static int ene_load_bincode(struct us_da |
| |
| static void ene_ub6250_info_destructor(void *extra) |
| { |
| + struct ene_ub6250_info *info = (struct ene_ub6250_info *) extra; |
| + |
| if (!extra) |
| return; |
| + kfree(info->bbuf); |
| } |
| |
| 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_da |
| u8 PageNum, u32 *PageBuf, struct ms_lib_type_extdat *ExtraDat) |
| { |
| 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; |
| - u8 ExtBuf[4]; |
| u32 bn = PhyBlockAddr * 0x20 + PageNum; |
| |
| result = ene_load_bincode(us, MS_RW_PATTERN); |
| @@ -901,7 +909,7 @@ static int ms_read_readpage(struct us_da |
| bcb->CDB[2] = (unsigned char)(PhyBlockAddr>>16); |
| 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) |
| return USB_STOR_TRANSPORT_ERROR; |
| |
| @@ -910,9 +918,9 @@ static int ms_read_readpage(struct us_da |
| ExtraDat->status0 = 0x10; /* Not yet,fireware support */ |
| |
| ExtraDat->status1 = 0x00; /* Not yet,fireware support */ |
| - ExtraDat->ovrflg = ExtBuf[0]; |
| - ExtraDat->mngflg = ExtBuf[1]; |
| - ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]); |
| + ExtraDat->ovrflg = bbuf[0]; |
| + ExtraDat->mngflg = bbuf[1]; |
| + ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]); |
| |
| return USB_STOR_TRANSPORT_GOOD; |
| } |
| @@ -1332,8 +1340,9 @@ static int ms_lib_read_extra(struct us_d |
| u8 PageNum, struct ms_lib_type_extdat *ExtraDat) |
| { |
| 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; |
| - u8 ExtBuf[4]; |
| |
| memset(bcb, 0, sizeof(struct bulk_cb_wrap)); |
| bcb->Signature = cpu_to_le32(US_BULK_CB_SIGN); |
| @@ -1347,7 +1356,7 @@ static int ms_lib_read_extra(struct us_d |
| bcb->CDB[2] = (unsigned char)(PhyBlock>>16); |
| 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) |
| return USB_STOR_TRANSPORT_ERROR; |
| |
| @@ -1355,9 +1364,9 @@ static int ms_lib_read_extra(struct us_d |
| ExtraDat->intr = 0x80; /* 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->ovrflg = ExtBuf[0]; |
| - ExtraDat->mngflg = ExtBuf[1]; |
| - ExtraDat->logadr = memstick_logaddr(ExtBuf[2], ExtBuf[3]); |
| + ExtraDat->ovrflg = bbuf[0]; |
| + ExtraDat->mngflg = bbuf[1]; |
| + ExtraDat->logadr = memstick_logaddr(bbuf[2], bbuf[3]); |
| |
| return USB_STOR_TRANSPORT_GOOD; |
| } |
| @@ -1556,9 +1565,9 @@ static int ms_lib_scan_logicalblocknumbe |
| u16 PhyBlock, newblk, i; |
| u16 LogStart, LogEnde; |
| struct ms_lib_type_extdat extdat; |
| - u8 buf[0x200]; |
| u32 count = 0, index = 0; |
| struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; |
| + u8 *bbuf = info->bbuf; |
| |
| for (PhyBlock = 0; PhyBlock < info->MS_Lib.NumberOfPhyBlock;) { |
| ms_lib_phy_to_log_range(PhyBlock, &LogStart, &LogEnde); |
| @@ -1572,14 +1581,16 @@ static int ms_lib_scan_logicalblocknumbe |
| } |
| |
| if (count == PhyBlock) { |
| - ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, &buf); |
| + ms_lib_read_extrablock(us, PhyBlock, 0, 0x80, |
| + bbuf); |
| count += 0x80; |
| } |
| index = (PhyBlock % 0x80) * 4; |
| |
| - extdat.ovrflg = buf[index]; |
| - extdat.mngflg = buf[index+1]; |
| - extdat.logadr = memstick_logaddr(buf[index+2], buf[index+3]); |
| + extdat.ovrflg = bbuf[index]; |
| + extdat.mngflg = bbuf[index+1]; |
| + extdat.logadr = memstick_logaddr(bbuf[index+2], |
| + bbuf[index+3]); |
| |
| if ((extdat.ovrflg & MS_REG_OVR_BKST) != MS_REG_OVR_BKST_OK) { |
| ms_lib_setacquired_errorblock(us, PhyBlock); |
| @@ -2062,9 +2073,9 @@ static int ene_ms_init(struct us_data *u |
| { |
| struct bulk_cb_wrap *bcb = (struct bulk_cb_wrap *) us->iobuf; |
| int result; |
| - u8 buf[0x200]; |
| u16 MSP_BlockSize, MSP_UserAreaBlocks; |
| struct ene_ub6250_info *info = (struct ene_ub6250_info *) us->extra; |
| + u8 *bbuf = info->bbuf; |
| |
| printk(KERN_INFO "transport --- ENE_MSInit\n"); |
| |
| @@ -2083,13 +2094,13 @@ static int ene_ms_init(struct us_data *u |
| bcb->CDB[0] = 0xF1; |
| 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) { |
| printk(KERN_ERR "Execution MS Init Code Fail !!\n"); |
| return USB_STOR_TRANSPORT_ERROR; |
| } |
| /* 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) { |
| printk(KERN_INFO "Insert = %x\n", info->MS_Status.Insert); |
| @@ -2098,15 +2109,15 @@ static int ene_ms_init(struct us_data *u |
| printk(KERN_INFO "IsMSPHG = %x\n", info->MS_Status.IsMSPHG); |
| printk(KERN_INFO "WtP= %x\n", info->MS_Status.WtP); |
| if (info->MS_Status.IsMSPro) { |
| - MSP_BlockSize = (buf[6] << 8) | buf[7]; |
| - MSP_UserAreaBlocks = (buf[10] << 8) | buf[11]; |
| + MSP_BlockSize = (bbuf[6] << 8) | bbuf[7]; |
| + MSP_UserAreaBlocks = (bbuf[10] << 8) | bbuf[11]; |
| info->MSP_TotalBlock = MSP_BlockSize * MSP_UserAreaBlocks; |
| } else { |
| ms_card_init(us); /* Card is MS (to ms.c)*/ |
| } |
| usb_stor_dbg(us, "MS Init Code OK !!\n"); |
| } 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; |
| } |
| |
| @@ -2116,9 +2127,9 @@ static int ene_ms_init(struct us_data *u |
| static int ene_sd_init(struct us_data *us) |
| { |
| int result; |
| - u8 buf[0x200]; |
| 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; |
| |
| usb_stor_dbg(us, "transport --- ENE_SDInit\n"); |
| /* SD Init Part-1 */ |
| @@ -2152,17 +2163,17 @@ static int ene_sd_init(struct us_data *u |
| bcb->Flags = US_BULK_FLAG_IN; |
| 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) { |
| usb_stor_dbg(us, "Execution SD Init Code Fail !!\n"); |
| 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) { |
| 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, "Ready = %x\n", s->Ready); |
| usb_stor_dbg(us, "IsMMC = %x\n", s->IsMMC); |
| @@ -2170,7 +2181,7 @@ static int ene_sd_init(struct us_data *u |
| usb_stor_dbg(us, "HiSpeed = %x\n", s->HiSpeed); |
| usb_stor_dbg(us, "WtP = %x\n", s->WtP); |
| } 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_GOOD; |
| @@ -2180,13 +2191,15 @@ static int ene_sd_init(struct us_data *u |
| static int ene_init(struct us_data *us) |
| { |
| int result; |
| - u8 misc_reg03 = 0; |
| + u8 misc_reg03; |
| 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) |
| return USB_STOR_TRANSPORT_ERROR; |
| |
| + misc_reg03 = bbuf[0]; |
| if (misc_reg03 & 0x01) { |
| if (!info->SD_Status.Ready) { |
| result = ene_sd_init(us); |
| @@ -2303,8 +2316,9 @@ static int ene_ub6250_probe(struct usb_i |
| const struct usb_device_id *id) |
| { |
| int result; |
| - u8 misc_reg03 = 0; |
| + u8 misc_reg03; |
| struct us_data *us; |
| + struct ene_ub6250_info *info; |
| |
| result = usb_stor_probe1(&us, intf, id, |
| (id - ene_ub6250_usb_ids) + ene_ub6250_unusual_dev_list, |
| @@ -2313,11 +2327,16 @@ static int ene_ub6250_probe(struct usb_i |
| return result; |
| |
| /* FIXME: where should the code alloc extra buf ? */ |
| - if (!us->extra) { |
| - us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL); |
| - if (!us->extra) |
| - return -ENOMEM; |
| - us->extra_destructor = ene_ub6250_info_destructor; |
| + us->extra = kzalloc(sizeof(struct ene_ub6250_info), GFP_KERNEL); |
| + if (!us->extra) |
| + return -ENOMEM; |
| + 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"; |
| @@ -2329,12 +2348,13 @@ static int ene_ub6250_probe(struct usb_i |
| return result; |
| |
| /* 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) { |
| usb_stor_disconnect(intf); |
| return USB_STOR_TRANSPORT_ERROR; |
| } |
| |
| + misc_reg03 = info->bbuf[0]; |
| if (!(misc_reg03 & 0x01)) { |
| pr_info("ums_eneub6250: This driver only supports SD/MS cards. " |
| "It does not support SM cards.\n"); |