Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+55 −35
Original line number Diff line number Diff line
@@ -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_data *us, unsigned char flag);

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_data *us, u32 PhyBlockAddr,
		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_data *us, u32 PhyBlockAddr,
	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_data *us, u32 PhyBlockAddr,
	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_data *us, u32 PhyBlock,
				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_data *us, u32 PhyBlock,
	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_data *us, u32 PhyBlock,
	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_logicalblocknumber(struct us_data *us, u16 btBlk1st)
	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_logicalblocknumber(struct us_data *us, u16 btBlk1st)
			}

			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 *us)
{
	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 *us)
	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 *us)
		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 *us)
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 *us)
	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 *us)
		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 *us)
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_interface *intf,
			 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_interface *intf,
		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;

	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_interface *intf,
		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");