diff -r 36b38b32b8b1 sys/src/9/bcm/emmc.c
--- a/sys/src/9/bcm/emmc.c	Sat Oct 17 19:27:21 2020 -0700
+++ b/sys/src/9/bcm/emmc.c	Sat Oct 17 21:44:11 2020 -0700
@@ -141,6 +141,7 @@
 
 static int cmdinfo[64] = {
 [0]  Ixchken,
+[1]  Resp48,
 [2]  Resp136,
 [3]  Resp48 | Ixchken | Crcchken,
 [5]  Resp48,
@@ -299,11 +300,17 @@
 	r = (u32int*)EMMCREGS;
 	assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
 	c = (cmd << Indexshift) | cmdinfo[cmd];
+	if(0)print("emmc: cmd%d %8.8ux arg %8.8ux\n", cmd, c, arg);
 	/*
 	 * CMD6 may be Setbuswidth or Switchfunc depending on Appcmd prefix
 	 */
 	if(cmd == Switchfunc && !emmc.appcmd)
 		c |= Isdata|Card2host;
+	/*
+	 * CMD8 can be SD_SEND_IF_COND or SEND_EXT_CSD depending on arg
+	 */
+	if(cmd == 8 && arg == 0)
+		c |= Isdata|Card2host;
 	if(cmd == IORWextended){
 		if(arg & (1<<31))
 			c |= Host2card;
@@ -319,8 +326,7 @@
 		WR(Control0, r[Control0] & ~(Dwidth4|Hispeed));
 		emmcclk(Initfreq);
 	}
-	if((r[Status] & Datinhibit) &&
-	   ((c & Isdata) || (c & Respmask) == Resp48busy)){
+	if(r[Status] & Cmdinhibit){
 		print("emmccmd: need to reset Cmdinhibit intr %ux stat %ux\n",
 			r[Interrupt], r[Status]);
 		WR(Control1, r[Control1] | Srstcmd);
@@ -352,7 +358,7 @@
 			break;
 	if((i&(Cmddone|Err)) != Cmddone){
 		if((i&~(Err|Cardintr)) != Ctoerr)
-			print("emmc: cmd %ux arg %ux error intr %ux stat %ux\n", c, arg, i, r[Status]);
+			print("emmc: cmd%d %ux arg %ux error intr %ux stat %ux\n", cmd, c, arg, i, r[Status]);
 		WR(Interrupt, i);
 		if(r[Status]&Cmdinhibit){
 			WR(Control1, r[Control1]|Srstcmd);
diff -r 36b38b32b8b1 sys/src/9/bcm64/sdhc.c
--- a/sys/src/9/bcm64/sdhc.c	Sat Oct 17 19:27:21 2020 -0700
+++ b/sys/src/9/bcm64/sdhc.c	Sat Oct 17 21:44:11 2020 -0700
@@ -150,6 +150,7 @@
 
 static int cmdinfo[64] = {
 [0]  Ixchken,
+[1]  Resp48,
 [2]  Resp136,
 [3]  Resp48 | Ixchken | Crcchken,
 [5]  Resp48,
@@ -358,6 +359,8 @@
 	 */
 	if(cmd == Switchfunc && !emmc.appcmd)
 		c |= Isdata|Card2host;
+	if(cmd == 8 && arg == 0)
+		c |= Isdata|Card2host;
 	if(c & Isdata)
 		c |= Dmaen;
 	if(cmd == IORWextended){
diff -r 36b38b32b8b1 sys/src/9/pc/pmmc.c
--- a/sys/src/9/pc/pmmc.c	Sat Oct 17 19:27:21 2020 -0700
+++ b/sys/src/9/pc/pmmc.c	Sat Oct 17 21:44:11 2020 -0700
@@ -145,6 +145,7 @@
 
 static int cmdinfo[64] = {
 [0]  Ixchken,
+[1]  Resp48,
 [2]  Resp136,
 [3]  Resp48 | Ixchken | Crcchken,
 [6]  Resp48 | Ixchken | Crcchken,
@@ -424,6 +425,8 @@
 		error(Egreg);
 	mode = cmdinfo[cmd] >> 8;
 	cmd = (cmd << 8) | (cmdinfo[cmd] & 0xFF);
+	if((cmd >> 8) == 8 && arg == 0)
+		cmd |= Isdata|Card2host;
 
 	c = pmmc;
 
diff -r 36b38b32b8b1 sys/src/9/port/sdmmc.c
--- a/sys/src/9/port/sdmmc.c	Sat Oct 17 19:27:21 2020 -0700
+++ b/sys/src/9/port/sdmmc.c	Sat Oct 17 21:44:11 2020 -0700
@@ -23,6 +23,8 @@
 enum {
 	Inittimeout	= 15,
 	Multiblock	= 1,
+	MMC_TYPE_MMC = 0,
+	MMC_TYPE_SD = 1,
 
 	/* Commands */
 	GO_IDLE_STATE	= 0,
@@ -31,6 +33,7 @@
 	SWITCH_FUNC	= 6,
 	SELECT_CARD	= 7,
 	SD_SEND_IF_COND	= 8,
+	SEND_EXT_CSD = 8,
 	SEND_CSD	= 9,
 	STOP_TRANSMISSION= 12,
 	SEND_STATUS	= 13,
@@ -42,6 +45,7 @@
 	APP_CMD		= 55,	/* prefix for following app-specific commands */
 	SET_BUS_WIDTH	= 6,
 	SD_SEND_OP_COND	= 41,
+	MMC_SEND_OP_COND = 1,
 
 	/* Command arguments */
 	/* SD_SEND_IF_COND */
@@ -79,8 +83,12 @@
 	u32int	ocr;
 	u32int	cid[4];
 	u32int	csd[4];
+	/* SD or MMC */
+	uchar	type;
 };
 
+SDio *sdcardlink;
+
 extern SDifc sdmmcifc;
 extern SDio sdio;
 
@@ -102,9 +110,14 @@
 }
 
 static void
-identify(SDunit *unit, u32int *csd)
+identify(SDunit *unit)
 {
 	uint csize, mult;
+	Ctlr *ctl = unit->dev->ctlr;
+	u32int *csd = ctl->csd;
+	SDio *io = ctl->io;
+	uchar *buf;
+	u32int r[4];
 
 	unit->secsize = 1 << CSD(83, 80);
 	switch(CSD(127, 126)){
@@ -117,11 +130,30 @@
 		csize = CSD(69, 48);
 		unit->sectors = (csize+1) * 0x80000LL / unit->secsize;
 		break;
+	case 3:
+		if(CSD(125, 122) < 4) { /* no EXT_CSD */
+			print("no ext_csd\n");
+			return;
+		}
+		buf = sdmalloc(512);
+		if(waserror()){
+			print("SEND_EXT_CSD error\n");
+			sdfree(buf);
+			nexterror();
+		}
+		io->iosetup(0, buf, 512, 1);
+		io->cmd(SEND_EXT_CSD, 0, r);
+		io->io(0, buf, 512);
+		unit->sectors = buf[212] | (buf[213]<<8) | (buf[214]<<16) | (buf[215]<<24);
+		sdfree(buf);
+		poperror();
+		break;
 	}
 	if(unit->secsize == 1024){
 		unit->sectors <<= 1;
 		unit->secsize = 512;
 	}
+	if(0)print("CSD version: %d, sectors: %llud, secsize: %lud\n", CSD(127, 126), unit->sectors, unit->secsize);
 }
 
 static SDev*
@@ -130,7 +162,9 @@
 	SDev *sdev;
 	Ctlr *ctl;
 
-	if(sdio.init() < 0)
+	if(sdcardlink == nil)
+		sdcardlink = &sdio;
+	if(sdcardlink->init() < 0)
 		return nil;
 	sdev = malloc(sizeof(SDev));
 	if(sdev == nil)
@@ -145,7 +179,7 @@
 	sdev->nunit = 1;
 	sdev->ctlr = ctl;
 	ctl->dev = sdev;
-	ctl->io = &sdio;
+	ctl->io = sdcardlink;
 	return sdev;
 }
 
@@ -225,12 +259,29 @@
 			hcs = Hcs;
 		poperror();
 	}
-	for(i = 0; i < Inittimeout; i++){
-		delay(100);
-		io->cmd(APP_CMD, 0, r);
-		io->cmd(SD_SEND_OP_COND, hcs|V3_3, r);
-		if(r[0] & Powerup)
-			break;
+	if(!waserror()){
+		for(i = 0; i < Inittimeout; i++){
+			delay(100);
+			io->cmd(APP_CMD, 0, r);
+			io->cmd(SD_SEND_OP_COND, hcs|V3_3, r);
+			if(r[0] & Powerup){
+				ctl->type = MMC_TYPE_SD;
+				break;
+			}
+		}
+		poperror();
+	}else{
+		io->cmd(GO_IDLE_STATE, 0, r);
+		ctl->ocr = (1 << 30);
+		for(i = 0; i < Inittimeout; i++){
+			delay(100);
+			io->cmd(MMC_SEND_OP_COND, ctl->ocr, r);
+			if(r[0] & Powerup){
+				ctl->type = MMC_TYPE_MMC;
+				break;
+			}
+			ctl->ocr = r[0] | (1 << 30);
+		}
 	}
 	if(i == Inittimeout){
 		print("sdmmc: card won't power up\n");
@@ -240,19 +291,26 @@
 	ctl->ocr = r[0];
 	io->cmd(ALL_SEND_CID, 0, r);
 	memmove(ctl->cid, r, sizeof ctl->cid);
-	io->cmd(SEND_RELATIVE_ADDR, 0, r);
-	ctl->rca = r[0]>>16;
+	if(ctl->type == MMC_TYPE_SD){
+		io->cmd(SEND_RELATIVE_ADDR, 0, r);
+		ctl->rca = r[0]>>16;
+	}else{
+		ctl->rca = 1;
+		io->cmd(SEND_RELATIVE_ADDR, ctl->rca<<Rcashift, r);
+	}
 	io->cmd(SEND_CSD, ctl->rca<<Rcashift, r);
 	memmove(ctl->csd, r, sizeof ctl->csd);
-	identify(unit, ctl->csd);
 	io->cmd(SELECT_CARD, ctl->rca<<Rcashift, r);
+	identify(unit);
 	io->cmd(SET_BLOCKLEN, unit->secsize, r);
-	io->cmd(APP_CMD, ctl->rca<<Rcashift, r);
-	io->cmd(SET_BUS_WIDTH, Width4, r);
-	if(io->highspeed){
-		if(!waserror()){
-			mmcswitchfunc(io, Hispeed|Setfunc);
-			poperror();
+	if(ctl->type == MMC_TYPE_SD){
+		io->cmd(APP_CMD, ctl->rca<<Rcashift, r);
+		io->cmd(SET_BUS_WIDTH, Width4, r);
+		if(io->highspeed){
+			if(!waserror()){
+				mmcswitchfunc(io, Hispeed|Setfunc);
+				poperror();
+			}
 		}
 	}
 	poperror();
diff -r 36b38b32b8b1 sys/src/9/zynq/emmc.c
--- a/sys/src/9/zynq/emmc.c	Sat Oct 17 19:27:21 2020 -0700
+++ b/sys/src/9/zynq/emmc.c	Sat Oct 17 21:44:11 2020 -0700
@@ -118,6 +118,7 @@
 
 static int cmdinfo[64] = {
 [0]  Ixchken,
+[1]  Resp48,
 [2]  Resp136,
 [3]  Resp48 | Ixchken | Crcchken,
 [6]  Resp48 | Ixchken | Crcchken,
@@ -236,6 +237,8 @@
 
 	assert(cmd < nelem(cmdinfo) && cmdinfo[cmd] != 0);
 	c = (cmd << Indexshift) | cmdinfo[cmd];
+	if(cmd == 8 && arg == 0)
+		c |= Isdata|Card2host|Dmaen;
 
 	r = emmc.regs;
 	if(r[Status] & Cmdinhibit){
