Browse Source

Plan 9 from Bell Labs 2007-08-06

David du Colombier 16 years ago
parent
commit
9657741f06

+ 14 - 9
dist/replica/_plan9.db

@@ -1,8 +1,8 @@
 386 - 20000000775 sys sys 1010957353 0
 386/9load - 775 sys sys 1181763625 313856
-386/9loaddebug - 775 sys sys 1185396304 417075
+386/9loaddebug - 775 sys sys 1186291382 417075
 386/9loadlite - 775 sys sys 1176519517 137148
-386/9loadlitedebug - 775 sys sys 1176581010 202587
+386/9loadlitedebug - 775 sys sys 1186291382 202587
 386/9pc - 775 sys sys 1186023393 1937795
 386/9pc.gz - 664 sys sys 1186023393 829787
 386/9pccpu - 775 sys sys 1186023409 1657423
@@ -5469,6 +5469,7 @@ rc/bin/ape - 20000000775 sys sys 1155362042 0
 rc/bin/ape/ar89 - 775 sys sys 1139744263 240
 rc/bin/ape/c89 - 775 sys sys 945617285 39
 rc/bin/ape/chown - 775 sys sys 945617285 43
+rc/bin/ape/dircp - 775 sys sys 1186289076 186
 rc/bin/ape/false - 775 sys sys 945617285 17
 rc/bin/ape/grep - 775 sys sys 1023738308 60
 rc/bin/ape/install - 775 sys sys 1015089725 572
@@ -5490,7 +5491,7 @@ rc/bin/cpurc.local - 775 sys sys 1176827268 367
 rc/bin/delkey - 775 sys sys 1109429137 643
 rc/bin/dial - 20000000775 sys sys 1059180057 0
 rc/bin/diffy - 775 sys sys 1140694870 277
-rc/bin/dircp - 775 sys sys 1186179147 246
+rc/bin/dircp - 775 sys sys 1186289104 181
 rc/bin/diskparts - 775 sys sys 1178399618 624
 rc/bin/dmaon - 775 sys sys 1178214935 213
 rc/bin/doc2ps - 775 sys sys 1069793831 244
@@ -5508,7 +5509,7 @@ rc/bin/ipconf/lra - 775 sys sys 1058791152 1558
 rc/bin/ipconf/outside - 775 sys sys 1058790951 550
 rc/bin/ipconf/theworld - 775 sys sys 1058790940 1212
 rc/bin/ipso - 775 sys sys 1079377794 2838
-rc/bin/ipv6on - 775 sys sys 1177128625 1899
+rc/bin/ipv6on - 775 sys sys 1186362803 2047
 rc/bin/iwhois - 775 sys sys 1143979502 1637
 rc/bin/juke - 775 sys sys 1105565140 1131
 rc/bin/kill - 775 sys sys 1143389260 142
@@ -7645,7 +7646,7 @@ sys/man/3/ether - 664 sys sys 1178597986 2890
 sys/man/3/floppy - 664 sys sys 954378905 881
 sys/man/3/fs - 664 sys sys 1175145095 3147
 sys/man/3/i82365 - 664 sys sys 954378906 884
-sys/man/3/ip - 664 sys sys 1186036896 26203
+sys/man/3/ip - 664 sys sys 1186348061 26244
 sys/man/3/kbmap - 664 sys sys 1131110122 1732
 sys/man/3/kprof - 664 sys sys 1018029972 1377
 sys/man/3/loopback - 664 sys sys 964662153 1995
@@ -8018,7 +8019,7 @@ sys/src/9/mtx/trap.c - 664 sys sys 1105030157 15882
 sys/src/9/mtx/uarti8250.c - 664 sys sys 1018721288 11590
 sys/src/9/pc - 20000000775 sys sys 1161233143 0
 sys/src/9/pc/a100p.cp - 444 sys sys 1159735144 21984
-sys/src/9/pc/ahci.h - 664 sys sys 1181155864 6287
+sys/src/9/pc/ahci.h - 664 sys sys 1186366009 6314
 sys/src/9/pc/apbootstrap.s - 664 sys sys 1131293655 3037
 sys/src/9/pc/apic.c - 664 sys sys 1174415344 8991
 sys/src/9/pc/apm.c - 664 sys sys 1131290210 3723
@@ -8116,11 +8117,11 @@ sys/src/9/pc/screen.h - 664 sys sys 1147023549 4256
 sys/src/9/pc/sd53c8xx.c - 664 sys sys 1170456695 55276
 sys/src/9/pc/sd53c8xx.n - 664 sys sys 1131290556 12657
 sys/src/9/pc/sd63xxesb.c - 664 sys sys 1184467400 35975
-sys/src/9/pc/sdata.c - 664 sys sys 1175564140 52809
+sys/src/9/pc/sdata.c - 664 sys sys 1186361525 52991
 sys/src/9/pc/sdmv50xx.c - 664 sys sys 1184467229 33837
 sys/src/9/pc/sdmylex.c - 664 sys sys 1171321627 28237
 sys/src/9/pc/sdscsi.c - 664 sys sys 1158889425 7241
-sys/src/9/pc/trap.c - 664 sys sys 1184466909 21852
+sys/src/9/pc/trap.c - 664 sys sys 1186361997 21898
 sys/src/9/pc/uartaxp.c - 664 sys sys 1166247784 18879
 sys/src/9/pc/uarti8250.c - 664 sys sys 1177676872 13957
 sys/src/9/pc/uartisa.c - 664 sys sys 1127126907 1777
@@ -9091,6 +9092,7 @@ sys/src/boot/bitsy/uart.c - 664 sys sys 1173299930 1495
 sys/src/boot/mkfile - 664 sys sys 1173300033 192
 sys/src/boot/pc - 20000000775 sys sys 1144961189 0
 sys/src/boot/pc/8250.c - 664 sys sys 1015007947 5727
+sys/src/boot/pc/ahci.h - 664 sys sys 1186366104 6318
 sys/src/boot/pc/alarm.c - 664 sys sys 1015007947 1668
 sys/src/boot/pc/apm.c - 664 sys sys 1015007947 289
 sys/src/boot/pc/bcom.c - 664 sys sys 1032215919 6421
@@ -9168,6 +9170,7 @@ sys/src/boot/pc/queue.c - 664 sys sys 1015007954 566
 sys/src/boot/pc/sd.h - 664 sys sys 1153333456 2244
 sys/src/boot/pc/sd53c8xx.c - 664 sys sys 1186031515 52082
 sys/src/boot/pc/sd53c8xx.i - 664 sys sys 1015007955 27245
+sys/src/boot/pc/sd63xxesb.c - 664 sys sys 1186368565 26990
 sys/src/boot/pc/sdata.c - 664 sys sys 1175564193 38846
 sys/src/boot/pc/sdmylex.c - 664 sys sys 1171783051 28694
 sys/src/boot/pc/sdscsi.c - 664 sys sys 1144961224 7006
@@ -15360,7 +15363,7 @@ sys/src/libgeometry/tstack.c - 664 sys sys 944961726 4716
 sys/src/libhtml - 20000000775 sys sys 1039727689 0
 sys/src/libhtml/build.c - 664 sys sys 1166796404 94558
 sys/src/libhtml/impl.h - 664 sys sys 1166796404 4598
-sys/src/libhtml/lex.c - 664 sys sys 1166796404 28136
+sys/src/libhtml/lex.c - 664 sys sys 1186360650 28187
 sys/src/libhtml/mkfile - 664 sys sys 1035389778 246
 sys/src/libhtml/strinttab.c - 664 sys sys 1016902547 1285
 sys/src/libhtml/utils.c - 664 sys sys 1166796403 9579
@@ -15844,3 +15847,5 @@ usr/glenda/lib/profile - 664 glenda glenda 1105128663 890
 usr/glenda/readme.acme - 664 glenda glenda 1019860628 4753
 usr/glenda/readme.rio - 664 glenda glenda 1019860628 6370
 usr/glenda/tmp - 20000000775 glenda glenda 1018802620 0
+386/bin/htmlfmt - 775 sys sys 1186370974 163412
+386/lib/libhtml.a - 664 sys sys 1186370975 229202

+ 14 - 11
dist/replica/plan9.db

@@ -1,8 +1,8 @@
 386 - 20000000775 sys sys 1010957353 0
 386/9load - 775 sys sys 1181763625 313856
-386/9loaddebug - 775 sys sys 1185396304 417075
+386/9loaddebug - 775 sys sys 1186291382 417075
 386/9loadlite - 775 sys sys 1176519517 137148
-386/9loadlitedebug - 775 sys sys 1176581010 202587
+386/9loadlitedebug - 775 sys sys 1186291382 202587
 386/9pc - 775 sys sys 1186023393 1937795
 386/9pc.gz - 664 sys sys 1186023393 829787
 386/9pccpu - 775 sys sys 1186023409 1657423
@@ -277,7 +277,7 @@
 386/bin/history - 775 sys sys 1178568279 74241
 386/bin/hoc - 775 sys sys 1172808058 100101
 386/bin/html2ms - 775 sys sys 1168402315 66321
-386/bin/htmlfmt - 775 sys sys 1181507267 163401
+386/bin/htmlfmt - 775 sys sys 1186370974 163412
 386/bin/htmlroff - 775 sys sys 1178568280 146978
 386/bin/ico - 775 sys sys 1179372092 162180
 386/bin/iconv - 775 sys sys 1168402316 113629
@@ -560,7 +560,7 @@
 386/lib/libflate.a - 664 sys sys 1168402366 76726
 386/lib/libframe.a - 664 sys sys 1184529910 66398
 386/lib/libgeometry.a - 664 sys sys 1168402366 50470
-386/lib/libhtml.a - 664 sys sys 1184529911 229152
+386/lib/libhtml.a - 664 sys sys 1186370975 229202
 386/lib/libhttpd.a - 664 sys sys 1181332906 99734
 386/lib/libip.a - 664 sys sys 1185420496 34710
 386/lib/libl.a - 664 sys sys 1168402367 5372
@@ -5469,6 +5469,7 @@ rc/bin/ape - 20000000775 sys sys 1155362042 0
 rc/bin/ape/ar89 - 775 sys sys 1139744263 240
 rc/bin/ape/c89 - 775 sys sys 945617285 39
 rc/bin/ape/chown - 775 sys sys 945617285 43
+rc/bin/ape/dircp - 775 sys sys 1186289076 186
 rc/bin/ape/false - 775 sys sys 945617285 17
 rc/bin/ape/grep - 775 sys sys 1023738308 60
 rc/bin/ape/install - 775 sys sys 1015089725 572
@@ -5490,7 +5491,7 @@ rc/bin/cpurc.local - 775 sys sys 1176827268 367
 rc/bin/delkey - 775 sys sys 1109429137 643
 rc/bin/dial - 20000000775 sys sys 1059180057 0
 rc/bin/diffy - 775 sys sys 1140694870 277
-rc/bin/dircp - 775 sys sys 1186179147 246
+rc/bin/dircp - 775 sys sys 1186289104 181
 rc/bin/diskparts - 775 sys sys 1178399618 624
 rc/bin/dmaon - 775 sys sys 1178214935 213
 rc/bin/doc2ps - 775 sys sys 1069793831 244
@@ -5508,7 +5509,7 @@ rc/bin/ipconf/lra - 775 sys sys 1058791152 1558
 rc/bin/ipconf/outside - 775 sys sys 1058790951 550
 rc/bin/ipconf/theworld - 775 sys sys 1058790940 1212
 rc/bin/ipso - 775 sys sys 1079377794 2838
-rc/bin/ipv6on - 775 sys sys 1177128625 1899
+rc/bin/ipv6on - 775 sys sys 1186362803 2047
 rc/bin/iwhois - 775 sys sys 1143979502 1637
 rc/bin/juke - 775 sys sys 1105565140 1131
 rc/bin/kill - 775 sys sys 1143389260 142
@@ -7645,7 +7646,7 @@ sys/man/3/ether - 664 sys sys 1178597986 2890
 sys/man/3/floppy - 664 sys sys 954378905 881
 sys/man/3/fs - 664 sys sys 1175145095 3147
 sys/man/3/i82365 - 664 sys sys 954378906 884
-sys/man/3/ip - 664 sys sys 1186036896 26203
+sys/man/3/ip - 664 sys sys 1186348061 26244
 sys/man/3/kbmap - 664 sys sys 1131110122 1732
 sys/man/3/kprof - 664 sys sys 1018029972 1377
 sys/man/3/loopback - 664 sys sys 964662153 1995
@@ -8018,7 +8019,7 @@ sys/src/9/mtx/trap.c - 664 sys sys 1105030157 15882
 sys/src/9/mtx/uarti8250.c - 664 sys sys 1018721288 11590
 sys/src/9/pc - 20000000775 sys sys 1161233143 0
 sys/src/9/pc/a100p.cp - 444 sys sys 1159735144 21984
-sys/src/9/pc/ahci.h - 664 sys sys 1181155864 6287
+sys/src/9/pc/ahci.h - 664 sys sys 1186366009 6314
 sys/src/9/pc/apbootstrap.s - 664 sys sys 1131293655 3037
 sys/src/9/pc/apic.c - 664 sys sys 1174415344 8991
 sys/src/9/pc/apm.c - 664 sys sys 1131290210 3723
@@ -8116,11 +8117,11 @@ sys/src/9/pc/screen.h - 664 sys sys 1147023549 4256
 sys/src/9/pc/sd53c8xx.c - 664 sys sys 1170456695 55276
 sys/src/9/pc/sd53c8xx.n - 664 sys sys 1131290556 12657
 sys/src/9/pc/sd63xxesb.c - 664 sys sys 1184467400 35975
-sys/src/9/pc/sdata.c - 664 sys sys 1175564140 52809
+sys/src/9/pc/sdata.c - 664 sys sys 1186361525 52991
 sys/src/9/pc/sdmv50xx.c - 664 sys sys 1184467229 33837
 sys/src/9/pc/sdmylex.c - 664 sys sys 1171321627 28237
 sys/src/9/pc/sdscsi.c - 664 sys sys 1158889425 7241
-sys/src/9/pc/trap.c - 664 sys sys 1184466909 21852
+sys/src/9/pc/trap.c - 664 sys sys 1186361997 21898
 sys/src/9/pc/uartaxp.c - 664 sys sys 1166247784 18879
 sys/src/9/pc/uarti8250.c - 664 sys sys 1177676872 13957
 sys/src/9/pc/uartisa.c - 664 sys sys 1127126907 1777
@@ -9091,6 +9092,7 @@ sys/src/boot/bitsy/uart.c - 664 sys sys 1173299930 1495
 sys/src/boot/mkfile - 664 sys sys 1173300033 192
 sys/src/boot/pc - 20000000775 sys sys 1144961189 0
 sys/src/boot/pc/8250.c - 664 sys sys 1015007947 5727
+sys/src/boot/pc/ahci.h - 664 sys sys 1186366104 6318
 sys/src/boot/pc/alarm.c - 664 sys sys 1015007947 1668
 sys/src/boot/pc/apm.c - 664 sys sys 1015007947 289
 sys/src/boot/pc/bcom.c - 664 sys sys 1032215919 6421
@@ -9168,6 +9170,7 @@ sys/src/boot/pc/queue.c - 664 sys sys 1015007954 566
 sys/src/boot/pc/sd.h - 664 sys sys 1153333456 2244
 sys/src/boot/pc/sd53c8xx.c - 664 sys sys 1186031515 52082
 sys/src/boot/pc/sd53c8xx.i - 664 sys sys 1015007955 27245
+sys/src/boot/pc/sd63xxesb.c - 664 sys sys 1186368565 26990
 sys/src/boot/pc/sdata.c - 664 sys sys 1175564193 38846
 sys/src/boot/pc/sdmylex.c - 664 sys sys 1171783051 28694
 sys/src/boot/pc/sdscsi.c - 664 sys sys 1144961224 7006
@@ -15360,7 +15363,7 @@ sys/src/libgeometry/tstack.c - 664 sys sys 944961726 4716
 sys/src/libhtml - 20000000775 sys sys 1039727689 0
 sys/src/libhtml/build.c - 664 sys sys 1166796404 94558
 sys/src/libhtml/impl.h - 664 sys sys 1166796404 4598
-sys/src/libhtml/lex.c - 664 sys sys 1166796404 28136
+sys/src/libhtml/lex.c - 664 sys sys 1186360650 28187
 sys/src/libhtml/mkfile - 664 sys sys 1035389778 246
 sys/src/libhtml/strinttab.c - 664 sys sys 1016902547 1285
 sys/src/libhtml/utils.c - 664 sys sys 1166796403 9579

+ 14 - 0
dist/replica/plan9.log

@@ -49851,3 +49851,17 @@
 1186210804 0 c sys/src/cmd/ip/6in4.c - 664 sys sys 1186210033 8811
 1186259407 0 c 386/bin/ip/6in4 - 775 sys sys 1186257752 90935
 1186259407 1 c 386/bin/ip/ping - 775 sys sys 1186257752 93159
+1186290005 0 a rc/bin/ape/dircp - 775 sys sys 1186289076 186
+1186290005 1 c rc/bin/dircp - 775 sys sys 1186289104 181
+1186291804 0 c 386/9loaddebug - 775 sys sys 1186291382 417075
+1186291804 1 c 386/9loadlitedebug - 775 sys sys 1186291382 202587
+1186349407 0 c sys/man/3/ip - 664 sys sys 1186348061 26244
+1186362005 0 c sys/src/9/pc/sdata.c - 664 sys sys 1186361525 52991
+1186362005 1 c sys/src/9/pc/trap.c - 664 sys sys 1186361997 21898
+1186362005 2 c sys/src/libhtml/lex.c - 664 sys sys 1186360650 28187
+1186363806 0 c rc/bin/ipv6on - 775 sys sys 1186362803 2047
+1186367404 0 c sys/src/9/pc/ahci.h - 664 sys sys 1186366009 6314
+1186367404 1 a sys/src/boot/pc/ahci.h - 664 sys sys 1186366104 6318
+1186369204 0 a sys/src/boot/pc/sd63xxesb.c - 664 sys sys 1186368565 26990
+1186371003 0 c 386/bin/htmlfmt - 775 sys sys 1186370974 163412
+1186371003 1 c 386/lib/libhtml.a - 664 sys sys 1186370975 229202

+ 9 - 0
rc/bin/ape/dircp

@@ -0,0 +1,9 @@
+#!/bin/rc
+# dircp src dest - copy a tree with ape's tar
+switch($#*){
+case 2
+	@{cd $1 && tar cf /fd/1 .} | @{cd $2 && tar xf /fd/0}
+case *
+	echo usage: dircp from to >[1=2]
+	exit usage
+}

+ 0 - 1
rc/bin/dircp

@@ -2,7 +2,6 @@
 # dircp src dest - copy a tree with tar
 switch($#*){
 case 2
-	# explicitly mention /fd/* to work with both plan 9 and ape tar
 	@{cd $1 && tar cf /fd/1 .} | @{cd $2 && tar xTf /fd/0}
 case *
 	echo usage: dircp from to >[1=2]

+ 18 - 12
rc/bin/ipv6on

@@ -1,6 +1,6 @@
 #!/bin/rc
-# ipv6on [netdir ndbfile [gwv4]] - configure an interface for v6,
-#	once v4 is configured.
+# ipv6on [netdir ndbfile [gwv4]] - configure an interface for ipv6,
+#	once ipv4 is configured.
 if (! ~ $#* 0 2 3) {
 	echo usage: $0 '[netdir ndbfile [gw-v4-name]]' >[1=2]
 	exit usage
@@ -29,11 +29,15 @@ if not {
 	xdir=(-x $netdir)
 }
 
-fn nonnil {	# name ip
-	if (~ $#2 0) {
+fn nonnil {		# variable
+	if (~ $#$1 0) {
 		echo no ip for $1
 		exit no-ip
 	}
+	if (! ~ $#$1 1) {
+		echo multiple ips for $1
+		exit multiple-ips
+	}
 }
 
 #
@@ -44,11 +48,13 @@ if (! ip/ipconfig -6 $xdir ether $netdir/ether?)
 ip/ipconfig $xdir ether $netdir/ether? ra6 recvra 1
 
 mev6=`{ndb/query -f $ndbf sys $sysname ipv6}
-mev4=`{ndb/query -f $ndbf sys $sysname ip}
+if (~ $#sysname 0 || ~ $sysname '')
+	mev6=`{ndb/query -f $ndbf sys $sysname ip | grep :}
+# mev4=`{ndb/query -f $ndbf sys $sysname ip | grep -v :}
 
 # for testing
 mylnk=`{ip/linklocal `{cat $netdir/ether?/addr}}
-nonnil mylnk $mylnk
+nonnil mylnk
 
 if (~ $#gw 1) {
 	if (~ $gw [0-9]*.[0-9]*.[0-9]*.[0-9]*)
@@ -58,18 +64,18 @@ if (~ $#gw 1) {
 	gwv6=`{ndb/query -f $ndbf sys $gw ipv6}
 
 	if (! ~ $#gwv4 0) {
-		echo ping gw $gwv4...
+		# echo ping gw $gwv4...
 		# load arp cache with gw mac
 		ip/ping -qn 3 $netdir/icmp!$gwv4 >/dev/null >[2=1] &
-		sleep 3					# wait for ping
+		sleep 1					# wait for ping
 
 		gweth=`{grep '* '^$gwv4^' ' $netdir/arp | awk '{print $4}' }
-		nonnil gweth $gweth
+		nonnil gweth
 		gwlnk=`{ip/linklocal $gweth}
-		nonnil gwlnk $gwlnk
+		nonnil gwlnk
 	}
 }
-nonnil mev6 $mev6
+nonnil mev6
 #
 # configure my global v6 addresses
 #
@@ -79,7 +85,7 @@ ip/ipconfig $xdir loopback /dev/null	add $mev6 /128
 if (~ $#gw 1) {
 	if (~ $#gwv6 0 || ~ $gwv6 '')
 		gwv6=`{ip/linklocal $gweth}
-	nonnil gwv6 $gwv6
+	nonnil gwv6
 	#
 	# add default v6 route to v6 addr of v4 gw
 	#

+ 2 - 1
sys/man/3/ip

@@ -870,7 +870,8 @@ in the connect message.
 .PP
 ESP is the Encapsulating Security Payload (RFC 1827, obsoleted by RFC 4303)
 for IPsec (RFC 4301).
-We currently implement ESP only over IPv4.
+We currently implement ESP only over IPv4 and
+only tunnel mode, not transport mode.
 It is used to set up an encrypted tunnel between machines.
 Like GRE, ESP has no port numbers.  Instead, the
 port number in the

+ 27 - 27
sys/src/9/pc/ahci.h

@@ -4,7 +4,7 @@
  */
 
 /* ata errors */
-enum{
+enum {
 	Emed	= 1<<0,		/* media error */
 	Enm	= 1<<1,		/* no media */
 	Eabrt	= 1<<2,		/* abort */
@@ -19,7 +19,7 @@ enum{
 };
 
 /* ata status */
-enum{
+enum {
 	ASerr	= 1<<0,		/* error */
 	ASdrq	= 1<<3,		/* request */
 	ASdf	= 1<<5,		/* fault */
@@ -30,7 +30,7 @@ enum{
 };
 
 /* pci configuration */
-enum{
+enum {
 	Abar	= 5,
 };
 
@@ -46,7 +46,7 @@ enum{
  */
 
 /* cap bits: supported features */
-enum{
+enum {
 	Hs64a	= 1<<31,	/* 64-bit addressing */
 	Hsncq	= 1<<30,	/* ncq */
 	Hssntf	= 1<<29,	/* snotification reg. */
@@ -71,13 +71,13 @@ enum{
 };
 
 /* ghc bits */
-enum{
+enum {
 	Hae	= 1<<31,	/* enable ahci */
 	Hie	= 1<<1,		/* " interrupts */
 	Hhr	= 1<<0,		/* hba reset */
 };
 
-typedef struct{
+typedef struct {
 	u32int	cap;
 	u32int	ghc;
 	u32int	isr;
@@ -89,7 +89,7 @@ typedef struct{
 	u32int	emctl;
 } Ahba;
 
-enum{
+enum {
 	Acpds	= 1<<31,	/* cold port detect status */
 	Atfes	= 1<<30,	/* task file error status */
 	Ahbfs	= 1<<29,	/* hba fatal */
@@ -114,7 +114,7 @@ enum{
 };
 
 /* serror bits */
-enum{
+enum {
 	SerrX	= 1<<26,	/* exchanged */
 	SerrF	= 1<<25,	/* unknown fis */
 	SerrT	= 1<<24,	/* transition error */
@@ -141,7 +141,7 @@ enum{
 };
 
 /* cmd register bits */
-enum{
+enum {
 	Aicc	= 1<<28,	/* interface communcations control. 4 bits */
 	Aasp	= 1<<27,	/* agressive slumber & partial sleep */
 	Aalpe 	= 1<<26,	/* agressive link pm enable */
@@ -167,7 +167,7 @@ enum{
 };
 
 /* ctl register bits */
-enum{
+enum {
 	Aipm	= 1<<8,		/* interface power mgmt. 3=off */
 	Aspd	= 1<<4,
 	Adet	= 1<<0,		/* device detection */
@@ -178,7 +178,7 @@ enum{
 #define	serror	scr1
 #define	sactive	scr3
 
-typedef struct{
+typedef struct {
 	u32int	list;		/* PxCLB must be 1kb aligned. */
 	u32int	listhi;
 	u32int	fis;		/* 256-byte aligned */
@@ -197,19 +197,19 @@ typedef struct{
 	u32int	ntf;
 	uchar	res2[8];
 	u32int	vendor;
-}Aport;
+} Aport;
 
 /* in host's memory; not memory mapped */
-typedef struct{
+typedef struct {
 	uchar	*base;
 	uchar	*d;
 	uchar	*p;
 	uchar	*r;
 	uchar	*u;
 	u32int	*devicebits;
-}Afis;
+} Afis;
 
-enum{
+enum {
 	Lprdtl	= 1<<16,	/* physical region descriptor table len */
 	Lpmp	= 1<<12,	/* port multiplier port */
 	Lclear	= 1<<10,	/* clear busy on R_OK */
@@ -222,34 +222,34 @@ enum{
 };
 
 /* in hosts memory; memory mapped */
-typedef struct{
+typedef struct {
 	u32int	flags;
 	u32int	len;
 	u32int	ctab;
 	u32int	ctabhi;
 	uchar	reserved[16];
-}Alist;
+} Alist;
 
-typedef struct{
+typedef struct {
 	u32int	dba;
 	u32int	dbahi;
 	u32int	pad;
 	u32int	count;
-}Aprdt;
+} Aprdt;
 
-typedef struct{
+typedef struct {
 	uchar	cfis[0x40];
 	uchar	atapi[0x10];
 	uchar	pad[0x30];
 	Aprdt	prdt;
-}Actab;
+} Actab;
 
-enum{
+enum {
 	Ferror	= 1,
 	Fdone	= 2,
 };
 
-enum{
+enum {
 	Dllba 	= 1,
 	Dsmart	= 1<<1,
 	Dpower	= 1<<2,
@@ -258,7 +258,7 @@ enum{
 	Datapi16= 1<<5,
 };
 
-typedef struct{
+typedef struct {
 	QLock;
 	Rendez;
 	uchar	flag;
@@ -267,9 +267,9 @@ typedef struct{
 	Afis	fis;
 	Alist	*list;
 	Actab	*ctab;
-}Aportm;
+} Aportm;
 
-typedef struct{
+typedef struct {
 	Aport	*p;
 	Aportm	*m;
-}Aportc;
+} Aportc;

+ 4 - 1
sys/src/9/pc/sdata.c

@@ -1970,7 +1970,10 @@ atapnp(void)
 		case (0x0054<<16)|0x10DE:	/* nVidia nForce4 SATA */
 		case (0x0055<<16)|0x10DE:	/* nVidia nForce4 SATA */
 		case (0x0266<<16)|0x10DE:	/* nVidia nForce4 430 SATA */
-		case (0x0267<<16)|0x10DE:	/* nVidia nForce4 430 SATA */
+		case (0x0267<<16)|0x10DE:	/* nVidia nForce 55 MCP SATA */
+		case (0x03EC<<16)|0x10DE:	/* nVidia nForce 61 MCP SATA */
+		case (0x0448<<16)|0x10DE:	/* nVidia nForce 65 MCP SATA */
+		case (0x0560<<16)|0x10DE:	/* nVidia nForce 69 MCP SATA */
 			/*
 			 * Ditto, although it may have a different base
 			 * address for the registers (0x50?).

+ 2 - 1
sys/src/9/pc/trap.c

@@ -518,8 +518,9 @@ _dumpstack(Ureg *ureg)
 	uintptr l, v, i, estack;
 	extern ulong etext;
 	int x;
+	char *s;
 
-	if(getconf("*nodumpstack")){
+	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
 		iprint("dumpstack disabled\n");
 		return;
 	}

+ 275 - 0
sys/src/boot/pc/ahci.h

@@ -0,0 +1,275 @@
+/*
+ * advanced host controller interface (sata)
+ * © 2007  coraid, inc
+ */
+
+/* ata errors */
+enum {
+	Emed	= 1<<0,		/* media error */
+	Enm	= 1<<1,		/* no media */
+	Eabrt	= 1<<2,		/* abort */
+	Emcr	= 1<<3,		/* media change request */
+	Eidnf	= 1<<4,		/* no user-accessible address */
+	Emc	= 1<<5,		/* media change */
+	Eunc	= 1<<6,		/* data error */
+	Ewp	= 1<<6,		/* write protect */
+	Eicrc	= 1<<7,		/* interface crc error */
+
+	Efatal	= Eidnf|Eicrc,	/* must sw reset */
+};
+
+/* ata status */
+enum {
+	ASerr	= 1<<0,		/* error */
+	ASdrq	= 1<<3,		/* request */
+	ASdf	= 1<<5,		/* fault */
+	ASdrdy	= 1<<6,		/* ready */
+	ASbsy	= 1<<7,		/* busy */
+
+	ASobs	= 1<<1|1<<2|1<<4,
+};
+
+/* pci configuration */
+enum {
+	Abar	= 5,
+};
+
+/*
+ * ahci memory configuration
+ *
+ * 0000-0023	generic host control
+ * 0024-009f	reserved
+ * 00a0-00ff	vendor specific.
+ * 0100-017f	port 0
+ * ...
+ * 1080-1100	port 31
+ */
+
+/* cap bits: supported features */
+enum {
+	Hs64a	= 1<<31,	/* 64-bit addressing */
+	Hsncq	= 1<<30,	/* ncq */
+	Hssntf	= 1<<29,	/* snotification reg. */
+	Hsmps	= 1<<28,	/* mech pres switch */
+	Hsss	= 1<<27,	/* staggered spinup */
+	Hsalp	= 1<<26,	/* aggressive link pm */
+	Hsal	= 1<<25,	/* activity led */
+	Hsclo	= 1<<24,	/* command-list override */
+	Hiss	= 1<<20,	/* for interface speed */
+//	Hsnzo	= 1<<19,
+	Hsam	= 1<<18,	/* ahci-mode only */
+	Hspm	= 1<<17,	/* port multiplier */
+//	Hfbss	= 1<<16,
+	Hpmb	= 1<<15,	/* multiple-block pio */
+	Hssc	= 1<<14,	/* slumber state */
+	Hpsc	= 1<<13,	/* partial-slumber state */
+	Hncs	= 1<<8,		/* n command slots */
+	Hcccs	= 1<<7,		/* coal */
+	Hems	= 1<<6,		/* enclosure mgmt. */
+	Hsxs	= 1<<5,		/* external sata */
+	Hnp	= 1<<0,		/* n ports */
+};
+
+/* ghc bits */
+enum {
+	Hae	= 1<<31,	/* enable ahci */
+	Hie	= 1<<1,		/* " interrupts */
+	Hhr	= 1<<0,		/* hba reset */
+};
+
+typedef struct {
+	u32int	cap;
+	u32int	ghc;
+	u32int	isr;
+	u32int	pi;		/* ports implemented */
+	u32int	ver;
+	u32int	ccc;		/* coaleasing control */
+	u32int	cccports;
+	u32int	emloc;
+	u32int	emctl;
+} Ahba;
+
+enum {
+	Acpds	= 1<<31,	/* cold port detect status */
+	Atfes	= 1<<30,	/* task file error status */
+	Ahbfs	= 1<<29,	/* hba fatal */
+	Ahbds	= 1<<28,	/* hba error (parity error) */
+	Aifs	= 1<<27,	/* interface fatal  §6.1.2 */
+	Ainfs	= 1<<26,	/* interface error (recovered) */
+	Aofs	= 1<<24,	/* too many bytes from disk */
+	Aipms	= 1<<23,	/* incorrect prt mul status */
+	Aprcs	= 1<<22,	/* PhyRdy change status Pxserr.diag.n */
+	Adpms	= 1<<7,		/* mechanical presence status */
+	Apcs 	= 1<<6,		/* port connect  diag.x */
+	Adps 	= 1<<5,		/* descriptor processed */
+	Aufs 	= 1<<4,		/* unknown fis diag.f */
+	Asdbs	= 1<<3,		/* set device bits fis received w/ i bit set */
+	Adss	= 1<<2,		/* dma setup */
+	Apio	= 1<<1,		/* pio setup fis */
+	Adhrs	= 1<<0,		/* device to host register fis */
+
+	IEM	= Acpds|Atfes|Ahbds|Ahbfs|Ahbds|Aifs|Ainfs|Aprcs|Apcs|Adps|
+			Aufs|Asdbs|Adss|Adhrs,
+	Ifatal	= Atfes|Ahbfs|Ahbds|Aifs,
+};
+
+/* serror bits */
+enum {
+	SerrX	= 1<<26,	/* exchanged */
+	SerrF	= 1<<25,	/* unknown fis */
+	SerrT	= 1<<24,	/* transition error */
+	SerrS	= 1<<23,	/* link sequence */
+	SerrH	= 1<<22,	/* handshake */
+	SerrC	= 1<<21,	/* crc */
+	SerrD	= 1<<20,	/* not used by ahci */
+	SerrB	= 1<<19,	/* 10-tp-8 decode */
+	SerrW	= 1<<18,	/* comm wake */
+	SerrI	= 1<<17,	/* phy internal */
+	SerrN	= 1<<16,	/* phyrdy change */
+
+	ErrE	= 1<<11,	/* internal */
+	ErrP	= 1<<10,	/* ata protocol violation */
+	ErrC	= 1<<9,		/* communication */
+	ErrT	= 1<<8,		/* transient */
+	ErrM	= 1<<1,		/* recoverd comm */
+	ErrI	= 1<<0,		/* recovered data integrety */
+
+	ErrAll	= ErrE|ErrP|ErrC|ErrT|ErrM|ErrI,
+	SerrAll	= SerrX|SerrF|SerrT|SerrS|SerrH|SerrC|SerrD|SerrB|SerrW|
+			SerrI|SerrN|ErrAll,
+	SerrBad	= 0x7f<<19,
+};
+
+/* cmd register bits */
+enum {
+	Aicc	= 1<<28,	/* interface communcations control. 4 bits */
+	Aasp	= 1<<27,	/* agressive slumber & partial sleep */
+	Aalpe 	= 1<<26,	/* agressive link pm enable */
+	Adlae	= 1<<25,	/* drive led on atapi */
+	Aatapi	= 1<<24,	/* device is atapi */
+	Aesp	= 1<<21,	/* external sata port */
+	Acpd	= 1<<20,	/* cold presence detect */
+	Ampsp	= 1<<19,	/* mechanical pres. */
+	Ahpcp	= 1<<18,	/* hot plug capable */
+	Apma	= 1<<17,	/* pm attached */
+	Acps	= 1<<16,	/* cold presence state */
+	Acr	= 1<<15,	/* cmdlist running */
+	Afr	= 1<<14,	/* fis running */
+	Ampss	= 1<<13,	/* mechanical presence switch state */
+	Accs	= 1<<8,		/* current command slot 12:08 */
+	Afre	= 1<<4,		/* fis enable receive */
+	Aclo	= 1<<3,		/* command list override */
+	Apod	= 1<<2,		/* power on dev (requires cold-pres. detect) */
+	Asud	= 1<<1,		/* spin-up device;  requires ss capability */
+	Ast	= 1<<0,		/* start */
+
+	Arun	= Ast|Acr|Afre|Afr,
+};
+
+/* ctl register bits */
+enum {
+	Aipm	= 1<<8,		/* interface power mgmt. 3=off */
+	Aspd	= 1<<4,
+	Adet	= 1<<0,		/* device detection */
+};
+
+#define	sstatus	scr0
+#define	sctl	scr2
+#define	serror	scr1
+#define	sactive	scr3
+
+typedef struct {
+	u32int	list;		/* PxCLB must be 1kb aligned. */
+	u32int	listhi;
+	u32int	fis;		/* 256-byte aligned */
+	u32int	fishi;
+	u32int	isr;
+	u32int	ie;		/* interrupt enable */
+	u32int	cmd;
+	u32int	res1;
+	u32int	task;
+	u32int	sig;
+	u32int	scr0;
+	u32int	scr2;
+	u32int	scr1;
+	u32int	scr3;
+	u32int	ci;		/* command issue */
+	u32int	ntf;
+	uchar	res2[8];
+	u32int	vendor;
+} Aport;
+
+/* in host's memory; not memory mapped */
+typedef struct {
+	uchar	*base;
+	uchar	*d;
+	uchar	*p;
+	uchar	*r;
+	uchar	*u;
+	u32int	*devicebits;
+} Afis;
+
+enum {
+	Lprdtl	= 1<<16,	/* physical region descriptor table len */
+	Lpmp	= 1<<12,	/* port multiplier port */
+	Lclear	= 1<<10,	/* clear busy on R_OK */
+	Lbist	= 1<<9,
+	Lreset	= 1<<8,
+	Lpref	= 1<<7,		/* prefetchable */
+	Lwrite	= 1<<6,
+	Latapi	= 1<<5,
+	Lcfl	= 1<<0,		/* command fis length in double words */
+};
+
+/* in hosts memory; memory mapped */
+typedef struct {
+	u32int	flags;
+	u32int	len;
+	u32int	ctab;
+	u32int	ctabhi;
+	uchar	reserved[16];
+} Alist;
+
+typedef struct {
+	u32int	dba;
+	u32int	dbahi;
+	u32int	pad;
+	u32int	count;
+} Aprdt;
+
+typedef struct {
+	uchar	cfis[0x40];
+	uchar	atapi[0x10];
+	uchar	pad[0x30];
+	Aprdt	prdt;
+} Actab;
+
+enum {
+	Ferror	= 1,
+	Fdone	= 2,
+};
+
+enum {
+	Dllba 	= 1,
+	Dsmart	= 1<<1,
+	Dpower	= 1<<2,
+	Dnop	= 1<<3,
+	Datapi	= 1<<4,
+	Datapi16= 1<<5,
+};
+
+typedef struct {
+//	QLock;
+//	Rendez;
+	uchar	flag;
+	uchar	feat;
+	uchar	smart;
+	Afis	fis;
+	Alist	*list;
+	Actab	*ctab;
+} Aportm;
+
+typedef struct {
+	Aport	*p;
+	Aportm	*m;
+} Aportc;

+ 1631 - 0
sys/src/boot/pc/sd63xxesb.c

@@ -0,0 +1,1631 @@
+/*
+ * intel 63[12]xesb ahci (advanced host controller interface)
+ * bootstrap sata controller driver
+ * copyright © 2007 coraid, inc.
+ */
+
+#include "u.h"
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "error.h"
+#include "sd.h"
+#include "ahci.h"
+
+#define	dprint(...)	if(debug == 1)	print(__VA_ARGS__); else USED(debug)
+#define	idprint(...)	if(prid == 1)	print(__VA_ARGS__); else USED(prid)
+#define	aprint(...)	if(datapi == 1)	print(__VA_ARGS__); else USED(datapi);
+
+enum {
+	NCtlr	= 2,
+	NCtlrdrv= 8,
+	NDrive	= NCtlr*NCtlrdrv,
+
+	Read	= 0,
+	Write
+};
+
+/* pci space configurtion */
+enum {
+	Pmap	= 0x90,
+	Ppcs	= 0x91,
+	Prev	= 0xa8,
+};
+
+enum {
+	Dnull,
+	Dmissing,
+	Dnew,
+	Dready,
+	Derror,
+	Dreset,
+	Doffline,
+	Dportreset,
+	Dlast
+};
+
+static char *diskstates[Dlast] = {
+	"null",
+	"missing",
+	"new",
+	"ready",
+	"error",
+	"reset",
+	"offline",
+	"portreset",
+};
+
+extern SDifc sd63xxesbifc;
+typedef struct Ctlr Ctlr;
+
+enum {
+	DMautoneg,
+	DMsatai,
+	DMsataii,
+};
+
+static char *modename[] = {
+	"auto",
+	"satai",
+	"sataii",
+};
+
+static char *flagname[] = {
+	"llba",
+	"smart",
+	"power",
+	"nop",
+	"atapi",
+	"atapi16",
+};
+
+typedef struct {
+	Lock;
+
+	Ctlr	*ctlr;
+	SDunit	*unit;
+	char	name[10];
+	Aport	*port;
+	Aportm	portm;
+	Aportc	portc;		/* redundant ptr to port and portm. */
+
+	uchar	mediachange;
+	uchar	state;
+	uchar	smartrs;
+
+	uvlong	sectors;
+	ulong	intick;
+	int	wait;
+	uchar	mode;		/* DMautoneg, satai or sataii. */
+	uchar	active;
+
+	char	serial[20+1];
+	char	firmware[8+1];
+	char	model[40+1];
+
+	ushort	info[0x200];
+
+	int	driveno;	/* ctlr*NCtlrdrv + unit */
+	int	portno;	/* ctlr port # != drive # when not all ports enabled. */
+} Drive;
+
+struct Ctlr {
+	Lock;
+
+	int	irq;
+	int	tbdf;
+	int	enabled;
+	SDev	*sdev;
+	Pcidev	*pci;
+
+	uchar	*mmio;
+	ulong	*lmmio;
+	Ahba	*hba;
+
+	Drive	rawdrive[NCtlrdrv];
+	Drive*	drive[NCtlrdrv];
+	int	ndrive;
+};
+
+static	Ctlr	iactlr[NCtlr];
+static	SDev	sdevs[NCtlr];
+static	int	niactlr;
+
+static	Drive	*iadrive[NDrive];
+static	int	niadrive;
+
+static	int	prid = 0;
+static	int	datapi = 0;
+
+static char stab[] = {
+[0]	'i', 'm',
+[8]	't', 'c', 'p', 'e',
+[16]	'N', 'I', 'W', 'B', 'D', 'C', 'H', 'S', 'T', 'F', 'X'
+};
+
+static void
+serrstr(ulong r, char *s, char *e)
+{
+	int i;
+
+	e -= 3;
+	for(i = 0; i < nelem(stab) && s < e; i++)
+		if((r & (1<<i)) && stab[i]){
+			*s++ = stab[i];
+			if(SerrBad & (1<<i))
+				*s++ = '*';
+		}
+	*s = 0;
+}
+
+static char ntab[] = "0123456789abcdef";
+
+static void
+preg(uchar *reg, int n)
+{
+	int i;
+	char buf[25*3+1], *e;
+
+	e = buf;
+	for(i = 0; i < n; i++){
+		*e++ = ntab[reg[i]>>4];
+		*e++ = ntab[reg[i]&0xf];
+		*e++ = ' ';
+	}
+	*e++ = '\n';
+	*e = 0;
+	dprint(buf);
+}
+
+static void
+dreg(char *s, Aport *p)
+{
+	dprint("%stask=%ux; cmd=%ux; ci=%ux; is=%ux\n",
+		s, p->task, p->cmd, p->ci, p->isr);
+}
+
+static void
+esleep(int ms)
+{
+	delay(ms);
+}
+
+typedef struct {
+	Aport	*p;
+	int	i;
+} Asleep;
+
+static int
+ahciclear(void *v)
+{
+	Asleep *s;
+
+	s = v;
+	return (s->p->ci & s->i) == 0;
+}
+
+static void
+aesleep(Aportm *, Asleep *a, int ms)
+{
+	ulong start;
+
+	start = m->ticks;
+	while((a->p->ci & a->i) != 0)
+		if(TK2MS(m->ticks-start) >= ms)
+			break;
+}
+
+static int
+ahciwait(Aportc *c, int ms)
+{
+	Asleep as;
+	Aport *p;
+
+	p = c->p;
+	p->ci = 1;
+	as.p = p;
+	as.i = 1;
+	aesleep(c->m, &as, ms);
+	if((p->task&1) == 0 && p->ci == 0)
+		return 0;
+	dreg("ahciwait timeout ", c->p);
+	return -1;
+}
+
+static int
+nop(Aportc *pc)
+{
+	uchar *c;
+	Actab *t;
+	Alist *l;
+
+	if((pc->m->feat&Dnop) == 0)
+		return -1;
+
+	t = pc->m->ctab;
+	c = t->cfis;
+
+	memset(c, 0, 0x20);
+	c[0] = 0x27;
+	c[1] = 0x80;
+	c[2] = 0x00;
+	c[7] = 0xa0;		/* obsolete device bits */
+
+	l = pc->m->list;
+	l->flags = Lwrite | 0x5;
+	l->len = 0;
+	l->ctab = PCIWADDR(t);
+	l->ctabhi = 0;
+
+	return ahciwait(pc, 3*1000);
+}
+
+static int
+setfeatures(Aportc *pc, uchar f)
+{
+	uchar *c;
+	Actab *t;
+	Alist *l;
+
+	t = pc->m->ctab;
+	c = t->cfis;
+
+	memset(c, 0, 0x20);
+	c[0] = 0x27;
+	c[1] = 0x80;
+	c[2] = 0xef;
+	c[3] = f;
+	c[7] = 0xa0;		/* obsolete device bits */
+
+	l = pc->m->list;
+	l->flags = Lwrite | 0x5;
+	l->len = 0;
+	l->ctab = PCIWADDR(t);
+	l->ctabhi = 0;
+
+	return ahciwait(pc, 3*1000);
+}
+
+static int
+setudmamode(Aportc *pc, uchar f)
+{
+	uchar *c;
+	Actab *t;
+	Alist *l;
+
+	t = pc->m->ctab;
+	c = t->cfis;
+
+	memset(c, 0, 0x20);
+	c[0] = 0x27;
+	c[1] = 0x80;
+	c[2] = 0xef;
+	c[3] = 3;		/* set transfer mode */
+	c[7] = 0xa0;		/* obsolete device bits */
+	c[12] = 0x40 | f;	/* sector count */
+
+	l = pc->m->list;
+	l->flags = Lwrite | 0x5;
+	l->len = 0;
+	l->ctab = PCIWADDR(t);
+	l->ctabhi = 0;
+
+	return ahciwait(pc, 3*1000);
+}
+
+static void
+asleep(int ms)
+{
+	delay(ms);
+}
+
+static int
+ahciportreset(Aportc *c)
+{
+	u32int *cmd, i;
+	Aport *p;
+
+	p = c->p;
+	cmd = &p->cmd;
+	*cmd &= ~(Afre|Ast);
+	for(i = 0; i < 500; i += 25){
+		if((*cmd & Acr) == 0)
+			break;
+		asleep(25);
+	}
+	p->sctl = 1 | (p->sctl & ~7);
+	delay(1);
+	p->sctl &= ~7;
+	return 0;
+}
+
+static ushort
+gbit16(void *a)
+{
+	uchar *i;
+
+	i = a;
+	return i[1]<<8 | i[0];
+}
+
+static u32int
+gbit32(void *a)
+{
+	u32int j;
+	uchar *i;
+
+	i = a;
+	j  = i[3] << 24;
+	j |= i[2] << 16;
+	j |= i[1] << 8;
+	j |= i[0];
+	return j;
+}
+
+static uvlong
+gbit64(void *a)
+{
+	uchar *i;
+
+	i = a;
+	return (uvlong)gbit32(i+4)<<32 | gbit32(a);
+}
+
+static int
+ahciidentify0(Aportc *pc, void *id, int atapi)
+{
+	uchar *c;
+	Actab *t;
+	Alist *l;
+	Aprdt *p;
+	static uchar tab[] = { 0xec, 0xa1 };
+
+	t = pc->m->ctab;
+	c = t->cfis;
+
+	memset(c, 0, 0x20);
+	c[0] = 0x27;
+	c[1] = 0x80;
+	c[2] = tab[atapi];
+	c[7] = 0xa0;		/* obsolete device bits */
+
+	l = pc->m->list;
+	l->flags = 1<<16 | 0x5;
+	l->len = 0;
+	l->ctab = PCIWADDR(t);
+	l->ctabhi = 0;
+
+	memset(id, 0, 0x100);
+	p = &t->prdt;
+	p->dba = PCIWADDR(id);
+	p->dbahi = 0;
+	p->count = 1<<31 | (0x200-2) | 1;
+
+	return ahciwait(pc, 3*1000);
+}
+
+static vlong
+ahciidentify(Aportc *pc, ushort *id)
+{
+	int i, sig;
+	vlong s;
+	Aportm *m;
+
+	m = pc->m;
+	m->feat = 0;
+	m->smart = 0;
+	i = 0;
+	sig = pc->p->sig >> 16;
+	if(sig == 0xeb14){
+		m->feat |= Datapi;
+		i = 1;
+	}
+	if(ahciidentify0(pc, id, i) == -1)
+		return -1;
+
+	i = gbit16(id+83) | gbit16(id+86);
+	if(i & (1<<10)){
+		m->feat |= Dllba;
+		s = gbit64(id+100);
+	}else
+		s = gbit32(id+60);
+
+	if(m->feat&Datapi){
+		i = gbit16(id+0);
+		if(i & 1)
+			m->feat |= Datapi16;
+	}
+
+	i = gbit16(id+83);
+	if((i>>14) != 1)
+		return s;
+	if(i & (1<<3))
+		m->feat |= Dpower;
+	i = gbit16(id+82);
+	if(i & 1)
+		m->feat |= Dsmart;
+	if(i & (1<<14))
+		m->feat |= Dnop;
+	return s;
+}
+
+static int
+ahciquiet(Aport *a)
+{
+	u32int *p, i;
+
+	p = &a->cmd;
+	*p &= ~Ast;
+	for(i = 0; i < 500; i += 50){
+		if((*p & Acr) == 0)
+			goto stop;
+		asleep(50);
+	}
+	return -1;
+stop:
+	if((a->task & (ASdrq|ASbsy)) == 0){
+		*p |= Ast;
+		return 0;
+	}
+
+	*p |= Aclo;
+	for(i = 0; i < 500; i += 50){
+		if((*p & Aclo) == 0)
+			goto stop1;
+		asleep(50);
+	}
+	return -1;
+stop1:
+	/* extra check */
+	dprint("clo clear %x\n", a->task);
+	if(a->task&ASbsy)
+		return -1;
+	*p |= Ast;
+	return 0;
+}
+
+static int
+ahciidle(Aport *port)
+{
+	u32int *p, i, r;
+
+	p = &port->cmd;
+	if((*p & Arun) == 0)
+		return 0;
+	*p &= ~Ast;
+	r = 0;
+	for(i = 0; i < 500; i += 25){
+		if((*p & Acr) == 0)
+			goto stop;
+		asleep(25);
+	}
+	r = -1;
+stop:
+	if((*p & Afre) == 0)
+		return r;
+	*p &= ~Afre;
+	for(i = 0; i < 500; i += 25){
+		if((*p & Afre) == 0)
+			return 0;
+		asleep(25);
+	}
+	return -1;
+}
+
+/*
+ * § 6.2.2.1  first part; comreset handled by reset disk.
+ *	- remainder is handled by configdisk.
+ *	- ahcirecover is a quick recovery from a failed command.
+ */
+int
+ahciswreset(Aportc *pc)
+{
+	int i;
+
+	i = ahciidle(pc->p);
+	pc->p->cmd |= Afre;
+	if(i == -1)
+		return -1;
+	if(pc->p->task & (ASdrq|ASbsy))
+		return -1;
+	return 0;
+}
+
+int
+ahcirecover(Aportc *pc)
+{
+	ahciswreset(pc);
+	pc->p->cmd |= Ast;
+	if(setudmamode(pc, 5) == -1)
+		return -1;
+	return 0;
+}
+
+static void*
+malign(int size, int align)
+{
+	void *v;
+
+	v = xspanalloc(size, align, 0);
+	memset(v, 0, size);
+	return v;
+}
+
+static void
+setupfis(Afis *f)
+{
+	f->base = malign(0x100, 0x100);
+	f->d = f->base + 0;
+	f->p = f->base + 0x20;
+	f->r = f->base + 0x40;
+	f->u = f->base + 0x60;
+	f->devicebits = (u32int*)(f->base + 0x58);
+}
+
+static int
+ahciconfigdrive(Ahba *h, Aportc *c, int mode)
+{
+	Aportm *m;
+	Aport *p;
+
+	p = c->p;
+	m = c->m;
+
+	if(m->list == 0){
+		setupfis(&m->fis);
+		m->list = malign(sizeof *m->list, 1024);
+		m->ctab = malign(sizeof *m->ctab, 128);
+	}
+
+	if(p->sstatus & 3 && h->cap & Hsss){
+		dprint("configdrive:  spinning up ... [%ux]\n", p->sstatus);
+		p->cmd |= Apod|Asud;
+		asleep(1400);
+	}
+
+	p->serror = SerrAll;
+
+	p->list = PCIWADDR(m->list);
+	p->listhi = 0;
+	p->fis = PCIWADDR(m->fis.base);
+	p->fishi = 0;
+	p->cmd |= Afre | Ast;
+
+	/* disable power managment sequence from book. */
+	p->sctl = (3*Aipm) | (mode*Aspd) | (0*Adet);
+	p->cmd &= ~Aalpe;
+
+	p->ie = IEM;
+
+	return 0;
+}
+
+static int
+ahcienable(Ahba *h)
+{
+	h->ghc |= Hie;
+	return 0;
+}
+
+static int
+ahcidisable(Ahba *h)
+{
+	h->ghc &= ~Hie;
+	return 0;
+}
+
+static int
+countbits(ulong u)
+{
+	int i, n;
+
+	n = 0;
+	for(i = 0; i < 32; i++)
+		if(u & (1<<i))
+			n++;
+	return n;
+}
+
+static int
+ahciconf(Ctlr *c)
+{
+	u32int u;
+	Ahba *h;
+
+	h = c->hba = (Ahba*)c->mmio;
+	u = h->cap;
+
+	if((u&Hsam) == 0)
+		h->ghc |= Hae;
+
+	print("ahci hba sss %d; ncs %d; coal %d; mports %d; led %d; clo %d; ems %d;\n",
+		(u>>27) & 1, (u>>8) & 0x1f, (u>>7) & 1,	u & 0x1f, (u>>25) & 1,
+		(u>>24) & 1, (u>>6) & 1);
+	return countbits(h->pi);
+}
+
+static int
+ahcihbareset(Ahba *h)
+{
+	int wait;
+
+	h->ghc |= 1;
+	for(wait = 0; wait < 1000; wait += 100){
+		if(h->ghc == 0)
+			return 0;
+		delay(100);
+	}
+	return -1;
+}
+
+static void
+idmove(char *p, ushort *a, int n)
+{
+	int i;
+	char *op, *e;
+
+	op = p;
+	for(i = 0; i < n/2; i++){
+		*p++ = a[i] >> 8;
+		*p++ = a[i];
+	}
+	*p = 0;
+	while(p > op && *--p == ' ')
+		*p = 0;
+	e = p;
+	p = op;
+	while(*p == ' ')
+		p++;
+	memmove(op, p, n - (e - p));
+}
+
+static int
+identify(Drive *d)
+{
+	u16int *id;
+	vlong osectors, s;
+	uchar oserial[21];
+	SDunit *u;
+
+	id = d->info;
+	s = ahciidentify(&d->portc, id);
+	if(s == -1){
+		d->state = Derror;
+		return -1;
+	}
+	osectors = d->sectors;
+	memmove(oserial, d->serial, sizeof d->serial);
+
+	d->sectors = s;
+	d->smartrs = 0;
+
+	idmove(d->serial, id+10, 20);
+	idmove(d->firmware, id+23, 8);
+	idmove(d->model, id+27, 40);
+
+	u = d->unit;
+	memset(u->inquiry, 0, sizeof u->inquiry);
+	u->inquiry[2] = 2;
+	u->inquiry[3] = 2;
+	u->inquiry[4] = sizeof u->inquiry - 4;
+	memmove(u->inquiry+8, d->model, 40);
+
+	if((osectors == 0 || osectors != s) &&
+	    memcmp(oserial, d->serial, sizeof oserial) != 0){
+		d->mediachange = 1;
+		u->sectors = 0;
+	}
+
+	return 0;
+}
+
+static void
+clearci(Aport *p)
+{
+	if((p->cmd & Ast) == 0)
+		return;
+	p->cmd &= ~Ast;
+	p->cmd |= Ast;
+}
+
+static void
+updatedrive(Drive *d)
+{
+	u32int cause, serr, s0, pr, ewake;
+	char *name;
+	Aport *p;
+	static u32int last;
+
+	pr = 1;
+	ewake = 0;
+	p = d->port;
+	cause = p->isr;
+	serr = p->serror;
+	p->isr = cause;
+	name = "??";
+	if(d->unit && d->unit->name)
+		name = d->unit->name;
+
+	if(p->ci == 0){
+		d->portm.flag |= Fdone;
+		pr = 0;
+	} else if(cause&Adps)
+		pr = 0;
+	if(cause&Ifatal){
+		ewake = 1;
+		dprint("Fatal\n");
+	}
+	if(cause&Adhrs){
+		if(p->task&33){
+			dprint("Adhrs cause = %ux; serr = %ux; task=%ux\n",
+				cause, serr, p->task);
+			d->portm.flag |= Ferror;
+			ewake = 1;
+		}
+		pr = 0;
+	}
+
+	if(pr)
+		dprint("%s: upd %ux ta %ux\n", name, cause, p->task);
+	if(cause & (Aprcs|Aifs)){
+		s0 = d->state;
+		switch(p->sstatus & 7){
+		case 0:
+			d->state = Dmissing;
+			break;
+		case 1:
+			d->state = Derror;
+			break;
+		case 3:
+			/* power mgmt crap for surprise removal */
+			p->ie |= Aprcs|Apcs;	/* is this required? */
+			d->state = Dreset;
+			break;
+		case 4:
+			d->state = Doffline;
+			break;
+		}
+		dprint("%s: %s → %s [Apcrs] %ux\n", name, diskstates[s0],
+			diskstates[d->state], p->sstatus);
+		/* print pulled message here. */
+		if(s0 == Dready && d->state != Dready)
+			idprint("%s: pulled\n", name);
+		if(d->state != Dready)
+			d->portm.flag |= Ferror;
+		ewake = 1;
+	}
+	p->serror = serr;
+	if(ewake)
+		clearci(p);
+	last = cause;
+}
+
+static void
+pstatus(Drive *d, ulong s)
+{
+	/*
+	 * bogus code because the first interrupt is currently dropped.
+	 * likely my fault.  serror may be cleared at the wrong time.
+	 */
+	switch(s){
+	case 0:
+		d->state = Dmissing;
+		break;
+	case 2:			/* should this be missing?  need testcase. */
+		dprint("pstatus 2\n");
+	case 3:
+		d->wait = 0;
+		d->state = Dnew;
+		break;
+	case 4:
+		d->state = Doffline;
+		break;
+	}
+}
+
+static int
+configdrive(Drive *d)
+{
+	if(ahciconfigdrive(d->ctlr->hba, &d->portc, d->mode) == -1)
+		return -1;
+	ilock(d);
+	pstatus(d, d->port->sstatus & 7);
+	iunlock(d);
+	return 0;
+}
+
+static void
+resetdisk(Drive *d)
+{
+	uint state, det, stat;
+	Aport *p;
+
+	p = d->port;
+	det = p->sctl & 7;
+	stat = p->sstatus & 7;
+	state = (p->cmd>>28) & 0xf;
+	dprint("resetdisk: icc %ux  det %d sdet %d\n", state, det, stat);
+	if(stat != 3){
+		ilock(d);
+		d->state = Dportreset;
+		iunlock(d);
+		return;
+	}
+	ilock(d);
+	state = d->state;
+	if(d->state != Dready || d->state != Dnew)
+		d->portm.flag |= Ferror;
+	clearci(p);			/* satisfy sleep condition. */
+	iunlock(d);
+
+	qlock(&d->portm);
+
+	if(p->cmd & Ast && ahciswreset(&d->portc) == -1){
+		ilock(d);
+		d->state = Dportreset;	/* get a bigger stick. */
+		iunlock(d);
+	} else {
+		ilock(d);
+		d->state = Dmissing;
+		iunlock(d);
+
+		configdrive(d);
+	}
+	dprint("resetdisk: %s → %s\n", diskstates[state], diskstates[d->state]);
+	qunlock(&d->portm);
+}
+
+static int
+newdrive(Drive *d)
+{
+	char *name, *s;
+	Aportc *c;
+	Aportm *m;
+
+	c = &d->portc;
+	m = &d->portm;
+
+	name = d->unit->name;
+	if(name == 0)
+		name = "??";
+
+	if(d->port->task == 0x80)
+		return -1;
+	qlock(c->m);
+	if(setudmamode(c, 5) == -1){
+		dprint("%s: can't set udma mode\n", name);
+		goto lose;
+	}
+	if(identify(d) == -1){
+		dprint("%s: identify failure\n", name);
+		goto lose;
+	}
+	if(m->feat & Dpower && setfeatures(c, 0x85) == -1){
+		m->feat &= ~Dpower;
+		if(ahcirecover(c) == -1)
+			goto lose;
+	}
+
+	ilock(d);
+	d->state = Dready;
+	iunlock(d);
+
+	qunlock(c->m);
+
+	s = "";
+	if(m->feat & Dllba)
+		s = "L";
+	idprint("%s: %sLBA %lld sectors\n", d->unit->name, s, d->sectors);
+	idprint("  %s %s %s %s\n", d->model, d->firmware, d->serial,
+		d->mediachange?"[mediachange]":"");
+	return 0;
+
+lose:
+	qunlock(&d->portm);
+	return -1;
+}
+
+enum {
+	Nms		= 256,
+	Mphywait	=  2*1024/Nms-1,
+	Midwait		= 16*1024/Nms-1,
+	Mcomrwait	= 64*1024/Nms-1,
+};
+
+static void
+westerndigitalhung(Drive *d)
+{
+	if((d->portm.feat&Datapi) == 0 && d->active &&
+	    TK2MS(m->ticks-d->intick) > 5000){
+		dprint("%s: drive hung; resetting [%ux] ci=%x\n", d->unit->name,
+			d->port->task, d->port->ci);
+		d->state = Dreset;
+	}
+}
+
+static ushort olds[NCtlr*NCtlrdrv];
+
+static int
+doportreset(Drive *d)
+{
+	int i;
+
+	i = -1;
+	qlock(&d->portm);
+	if(ahciportreset(&d->portc) == -1)
+		dprint("ahciportreset fails\n");
+	else
+		i = 0;
+	qunlock(&d->portm);
+	dprint("portreset → %s  [task %ux]\n", diskstates[d->state],
+		d->port->task);
+	return i;
+}
+
+static void
+checkdrive(Drive *d, int i)
+{
+	ushort s;
+	char *name;
+
+	ilock(d);
+	name = d->unit->name;
+	s = d->port->sstatus;
+	if(s != olds[i]){
+		dprint("%s: status: %04ux -> %04ux: %s\n", name, olds[i],
+			s, diskstates[d->state]);
+		olds[i] = s;
+		d->wait = 0;
+	}
+	westerndigitalhung(d);
+	switch(d->state){
+	case Dnull:
+	case Dready:
+		break;
+	case Dmissing:
+	case Dnew:
+		switch(s & 0x107){
+		case 0:
+		case 1:
+			break;
+		default:
+			dprint("%s: unknown status %04ux\n", name, s);
+		case 0x100:
+			if(++d->wait&Mphywait)
+				break;
+reset:
+			if(++d->mode > DMsataii)
+				d->mode = 0;
+			if(d->mode == DMsatai){	/* we tried everything */
+				d->state = Dportreset;
+				goto portreset;
+			}
+			dprint("%s: reset; new mode %s\n", name,
+				modename[d->mode]);
+			iunlock(d);
+			resetdisk(d);
+			ilock(d);
+			break;
+		case 0x103:
+			if((++d->wait&Midwait) == 0){
+				dprint("%s: slow reset %04ux task=%ux; %d\n",
+					name, s, d->port->task, d->wait);
+				goto reset;
+			}
+			s = d->port->task&0xff;
+			if(s == 0x7f || ((d->port->sig>>16) != 0xeb14 &&
+			    (s & ~0x17) != (1<<6)))
+				break;
+			iunlock(d);
+			newdrive(d);
+			ilock(d);
+			break;
+		}
+		break;
+	case Doffline:
+		if(d->wait++&Mcomrwait)
+			break;
+	case Derror:
+	case Dreset:
+		dprint("%s: reset [%s]: mode %d; status %04ux\n",
+			name, diskstates[d->state], d->mode, s);
+		iunlock(d);
+		resetdisk(d);
+		ilock(d);
+		break;
+	case Dportreset:
+portreset:
+		if(d->wait++ & 0xff && (s & 0x100) == 0)
+			break;
+		dprint("%s: portreset [%s]: mode %d; status %04ux\n",
+			name, diskstates[d->state], d->mode, s);
+		d->portm.flag |= Ferror;
+		clearci(d->port);
+		if((s & 7) == 0){
+			d->state = Dmissing;
+			break;
+		}
+		iunlock(d);
+		doportreset(d);
+		ilock(d);
+		break;
+	}
+	iunlock(d);
+}
+
+static void
+iainterrupt(Ureg*, void *a)
+{
+	int i;
+	ulong cause, m;
+	Ctlr *c;
+	Drive *d;
+
+	c = a;
+	ilock(c);
+	/* check drive here! */
+	cause = c->hba->isr;
+	for(i = 0; i < c->ndrive; i++){
+		m = 1 << i;
+		if((cause & m) == 0)
+			continue;
+		d = c->rawdrive + i;
+		ilock(d);
+		if(d->port->isr && c->hba->pi & m)
+			updatedrive(d);
+		c->hba->isr = m;
+		iunlock(d);
+	}
+	iunlock(c);
+}
+
+static int
+iaverify(SDunit *u)
+{
+	Ctlr *c;
+	Drive *d;
+
+	c = u->dev->ctlr;
+	d = c->drive[u->subno];
+	ilock(c);
+	ilock(d);
+	d->unit = u;
+	iunlock(d);
+	iunlock(c);
+	checkdrive(d, d->driveno);
+	return 1;
+}
+
+static int
+iaenable(SDev *s)
+{
+	Ctlr *c;
+
+	c = s->ctlr;
+	ilock(c);
+	if(!c->enabled) {
+		pcisetbme(c->pci);
+		setvec(c->irq + VectorPIC, iainterrupt, c);
+		/* supposed to squelch leftover interrupts here. */
+		ahcienable(c->hba);
+	}
+	c->enabled = 1;
+	iunlock(c);
+	return 1;
+}
+
+static int
+iadisable(SDev *s)
+{
+	Ctlr *c;
+
+	c = s->ctlr;
+	ilock(c);
+	ahcidisable(c->hba);
+//	intrdisable(c->irq, iainterrupt, c, c->tbdf, name);
+	c->enabled = 0;
+	iunlock(c);
+	return 1;
+}
+
+static int
+iaonline(SDunit *unit)
+{
+	Ctlr *c;
+	Drive *d;
+	int r;
+
+	c = unit->dev->ctlr;
+	d = c->drive[unit->subno];
+	r = 0;
+
+	if(d->portm.feat & Datapi && d->mediachange){
+		r = scsionline(unit);
+		if(r > 0)
+			d->mediachange = 0;
+		return r;
+	}
+
+	ilock(d);
+	if(d->mediachange){
+		r = 2;
+		d->mediachange = 0;
+		/* devsd rests this after online is called; why? */
+		unit->sectors = d->sectors;
+		unit->secsize = 512;
+	} else if(d->state == Dready)
+		r = 1;
+	iunlock(d);
+
+	return r;
+}
+
+/* returns locked list! */
+static Alist*
+ahcibuild(Aportm *m, uchar *cmd, void *data, int n, vlong lba)
+{
+	uchar *c, acmd, dir, llba;
+	Alist *l;
+	Actab *t;
+	Aprdt *p;
+	static uchar tab[2][2] = { 0xc8, 0x25, 0xca, 0x35 };
+
+	dir = *cmd != 0x28;
+	llba = m->feat&Dllba? 1: 0;
+	acmd = tab[dir][llba];
+	qlock(m);
+	l = m->list;
+	t = m->ctab;
+	c = t->cfis;
+
+	c[0] = 0x27;
+	c[1] = 0x80;
+	c[2] = acmd;
+	c[3] = 0;
+
+	c[4] = lba;		/* sector	lba low	7:0 */
+	c[5] = lba >> 8;	/* cylinder low	lba mid	15:8 */
+	c[6] = lba >> 16;	/* cylinder hi	lba hi	23:16 */
+	c[7] = 0xa0 | 0x40;	/* obsolete device bits + lba */
+	if(llba == 0)
+		c[7] |= (lba>>24) & 7;
+
+	c[8] = lba >> 24;	/* sector (exp)		lba 	31:24 */
+	c[9] = lba >> 32;	/* cylinder low (exp)	lba	39:32	 */
+	c[10] = lba >> 48;	/* cylinder hi (exp)	lba	48:40 */
+	c[11] = 0;		/* features (exp); */
+
+	c[12] = n;		/* sector count */
+	c[13] = n >> 8;		/* sector count (exp) */
+	c[14] = 0;		/* r */
+	c[15] = 0;		/* control */
+
+	*(ulong*)(c+16) = 0;
+
+	l->flags = 1<<16 | Lpref | 0x5;	/* Lpref ?? */
+	if(dir == Write)
+		l->flags |= Lwrite;
+	l->len = 0;
+	l->ctab = PCIWADDR(t);
+	l->ctabhi = 0;
+
+	p = &t->prdt;
+	p->dba = PCIWADDR(data);
+	p->dbahi = 0;
+	p->count = 1<<31 | (512*n - 2) | 1;
+
+	return l;
+}
+
+static Alist*
+ahcibuildpkt(Aportm *m, SDreq *r, void *data, int n)
+{
+	int fill, len;
+	uchar *c;
+	Actab *t;
+	Alist *l;
+	Aprdt *p;
+
+	qlock(m);
+	l = m->list;
+	t = m->ctab;
+	c = t->cfis;
+
+	fill = m->feat&Datapi16? 16: 12;
+	if((len = r->clen) > fill)
+		len = fill;
+	memmove(t->atapi, r->cmd, len);
+	memset(t->atapi + len, 0, fill - len);
+
+	c[0] = 0x27;
+	c[1] = 0x80;
+	c[2] = 0xa0;
+	if(n != 0)
+		c[3] = 1;	/* dma */
+	else
+		c[3] = 0;	/* features (exp); */
+
+	c[4] = 0;		/* sector	lba low	7:0 */
+	c[5] = n;		/* cylinder low	lba mid	15:8 */
+	c[6] = n >> 8;		/* cylinder hi	lba hi	23:16 */
+	c[7] = 0xa0;		/* obsolete device bits */
+
+	*(ulong*)(c+8) = 0;
+	*(ulong*)(c+12) = 0;
+	*(ulong*)(c+16) = 0;
+
+	l->flags = 1<<16 | Lpref | Latapi | 0x5;
+	if(r->write != 0 && data)
+		l->flags |= Lwrite;
+	l->len = 0;
+	l->ctab = PCIWADDR(t);
+	l->ctabhi = 0;
+
+	if(data == 0)
+		return l;
+
+	p = &t->prdt;
+	p->dba = PCIWADDR(data);
+	p->dbahi = 0;
+	p->count = 1<<31 | (n - 2) | 1;
+
+	return l;
+}
+
+static int
+waitready(Drive *d)
+{
+	u32int s, t, i;
+
+	for(i = 0; i < 120; i++){
+		ilock(d);
+		s = d->port->sstatus;
+		t = d->port->task;
+		iunlock(d);
+		if((s & 0x100) == 0)
+			return -1;
+		if(d->state == Dready && (s & 7) == 3)
+			return 0;
+		if((i+1) % 30 == 0)
+			print("%s: waitready: [%s] task=%ux sstat=%ux\n",
+				d->unit->name, diskstates[d->state], t, s);
+		esleep(1000);
+	}
+	print("%s: not responding; offline\n", d->unit->name);
+	ilock(d);
+	d->state = Doffline;
+	iunlock(d);
+	return -1;
+}
+
+static int
+iariopkt(SDreq *r, Drive *d)
+{
+	int n, count, try, max, flag, task;
+	char *name;
+	uchar *cmd, *data;
+	Aport *p;
+	Asleep as;
+
+	cmd = r->cmd;
+	name = d->unit->name;
+	p = d->port;
+
+	aprint("%02ux %02ux %c %d %p\n", cmd[0], cmd[2], "rw"[r->write],
+		r->dlen, r->data);
+//	if(cmd[0] == 0x5a && (cmd[2] & 0x3f) == 0x3f)
+//		return sdmodesense(r, cmd, d->info, sizeof d->info);
+	r->rlen = 0;
+	count = r->dlen;
+	max = 65536;
+
+	try = 0;
+retry:
+	if(waitready(d) == -1)
+		return SDeio;
+	data = r->data;
+	n = count;
+	if(n > max)
+		n = max;
+	d->active++;
+	ahcibuildpkt(&d->portm, r, data, n);
+	ilock(d);
+	d->portm.flag = 0;
+	iunlock(d);
+	p->ci = 1;
+
+	as.p = p;
+	as.i = 1;
+	d->intick = m->ticks;
+
+	while(ahciclear(&as) == 0)
+		;
+
+	ilock(d);
+	flag = d->portm.flag;
+	task = d->port->task;
+	iunlock(d);
+
+	if(task & (Efatal<<8) || task & (ASbsy|ASdrq) && d->state == Dready){
+		d->port->ci = 0;		/* @? */
+		ahcirecover(&d->portc);
+		task = d->port->task;
+	}
+	d->active--;
+	qunlock(&d->portm);
+	if(flag == 0){
+		if(++try == 10){
+			print("%s: bad disk\n", name);
+			r->status = SDcheck;
+			return SDcheck;
+		}
+		print("%s: retry\n", name);
+		esleep(1000);
+		goto retry;
+	}
+	if(flag & Ferror){
+		print("%s: i/o error %ux\n", name, task);
+		r->status = SDcheck;
+		return SDcheck;
+	}
+
+	data += n;
+
+	r->rlen = data - (uchar*)r->data;
+	r->status = SDok;
+	return SDok;
+}
+
+static int
+iario(SDreq *r)
+{
+	int n, count, max, flag, task;
+	vlong lba;
+	char *name;
+	uchar *cmd, *data;
+	Aport *p;
+	Asleep as;
+	Ctlr *c;
+	Drive *d;
+	SDunit *unit;
+
+	unit = r->unit;
+	c = unit->dev->ctlr;
+	d = c->drive[unit->subno];
+	if(d->portm.feat & Datapi)
+		return iariopkt(r, d);
+	cmd = r->cmd;
+	name = d->unit->name;
+	p = d->port;
+
+//	if((i = sdfakescsi(r, d->info, sizeof d->info)) != SDnostatus){
+//		r->status = i;
+//		return i;
+//	}
+
+	if(*cmd != 0x28 && *cmd != 0x2a){
+		print("%s: bad cmd 0x%.2ux\n", name, cmd[0]);
+		r->status = SDcheck;
+		return SDcheck;
+	}
+
+	lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
+	count = cmd[7]<<8 | cmd[8];
+	if(r->data == nil)
+		return SDok;
+	if(r->dlen < count*unit->secsize)
+		count = r->dlen/unit->secsize;
+	max = 128;
+
+	if(waitready(d) == -1)
+		return SDeio;
+	data = r->data;
+	while(count > 0){
+		n = count;
+		if(n > max)
+			n = max;
+		d->active++;
+		ahcibuild(&d->portm, cmd, data, n, lba);
+		ilock(d);
+		d->portm.flag = 0;
+		iunlock(d);
+		p->ci = 1;
+
+		as.p = p;
+		as.i = 1;
+		d->intick = m->ticks;
+
+		while(ahciclear(&as) == 0)
+			;
+
+		ilock(d);
+		flag = d->portm.flag;
+		task = d->port->task;
+		iunlock(d);
+
+		if(task & (Efatal<<8) ||
+		    task & (ASbsy|ASdrq) && d->state == Dready){
+			d->port->ci = 0;		/* @? */
+			ahcirecover(&d->portc);
+			task = d->port->task;
+		}
+		d->active--;
+		qunlock(&d->portm);
+		if(flag == 0 || flag & Ferror){
+			print("%s: i/o error %ux @%lld\n", name, task, lba);
+			r->status = SDeio;
+			return SDeio;
+		}
+
+		count -= n;
+		lba += n;
+		data += n * unit->secsize;
+	}
+	r->rlen = data - (uchar*)r->data;
+	r->status = SDok;
+	return SDok;
+}
+
+/*
+ * configure drives 0-5 as ahci sata  (c.f. errata)
+ */
+static int
+iaahcimode(Pcidev *p)
+{
+	dprint("iaahcimode %ux %ux %ux\n", pcicfgr8(p, 0x91),
+		pcicfgr8(p, 92), pcicfgr8(p, 93));
+	pcicfgw16(p, 0x92, pcicfgr32(p, 0x92) | 0xf);	/* ports 0-3 */
+//	pcicfgw8(p, 0x93, pcicfgr32(p, 9x93) | 3);	/* ports 4-5 */
+	return 0;
+}
+
+static void
+iasetupahci(Ctlr *c)
+{
+	/* disable cmd block decoding. */
+	pcicfgw16(c->pci, 0x40, pcicfgr16(c->pci, 0x40) & ~(1<<15));
+	pcicfgw16(c->pci, 0x42, pcicfgr16(c->pci, 0x42) & ~(1<<15));
+
+	c->lmmio[0x4/4] |= 1 << 31;	/* enable ahci mode (ghc register) */
+	c->lmmio[0xc/4] = (1<<6) - 1;	/* five ports (supposedly ro pi reg) */
+
+	/* enable ahci mode. */
+//	pcicfgw8(c->pci, 0x90, 0x40);
+//	pcicfgw16(c->pci, 0x90, 1<<6 | 1<<5);	/* pedanticly proper for ich9 */
+	pcicfgw8(c->pci, 0x90, 1<<6 | 1<<5);	/* pedanticly proper for ich9 */
+}
+
+static SDev*
+iapnp(void)
+{
+	int i, n, nunit;
+	ulong io;
+	Ctlr *c;
+	Drive *d;
+	Pcidev *p;
+	SDev *head, *tail, *s;
+	static int done;
+
+	if(done++)
+		return nil;
+	p = nil;
+	head = nil;
+	tail = nil;
+loop:
+	while((p = pcimatch(p, 0x8086, 0)) != nil){
+		if((p->did & 0xfffc) != 0x2680 &&	/* esb */
+		    (p->did & 0xfffa) != 0x27c0)	/* 82801g[bh]m */
+			continue;
+		if(niactlr == NCtlr){
+			print("iapnp: too many controllers\n");
+			break;
+		}
+		c = iactlr + niactlr;
+		s = sdevs + niactlr;
+		memset(c, 0, sizeof *c);
+		memset(s, 0, sizeof *s);
+		io = p->mem[Abar].bar & ~0xf;
+		c->mmio = (uchar*)upamalloc(io, p->mem[0].size, 0);
+		if(c->mmio == 0){
+			print("iapnp: address 0x%luX in use did=%x\n", io, p->did);
+			continue;
+		}
+		c->lmmio = (ulong*)c->mmio;
+		c->pci = p;
+		if(p->did != 0x2681)
+			iasetupahci(c);
+		nunit = ahciconf(c);
+//		ahcihbareset((Ahba*)c->mmio);
+		if(iaahcimode(p) == -1)
+			break;
+		if(nunit < 1){
+//			vunmap(c->mmio, p->mem[0].size);
+			continue;
+		}
+		niactlr++;
+		i = (c->hba->cap>>21) & 1;
+		print("intel 63[12]xesb: sata-%s ports with %d ports\n",
+			"I\0II" + i*2, nunit);
+		s->ifc = &sd63xxesbifc;
+		s->ctlr = c;
+		s->nunit = nunit;
+		s->idno = 'E';
+		c->sdev = s;
+		c->irq = p->intl;
+		c->tbdf = p->tbdf;
+		c->ndrive = nunit;
+
+		/* map the drives -- they don't all need to be enabled. */
+		memset(c->rawdrive, 0, sizeof c->rawdrive);
+		n = 0;
+		for(i = 0; i < NCtlrdrv; i++) {
+			d = c->rawdrive+i;
+			d->portno = i;
+			d->driveno = -1;
+			d->sectors = 0;
+			d->ctlr = c;
+			if((c->hba->pi & (1<<i)) == 0)
+				continue;
+			d->port = (Aport*)(c->mmio + 0x80*i + 0x100);
+			d->portc.p = d->port;
+			d->portc.m = &d->portm;
+			d->driveno = n++;
+			c->drive[i] = d;
+			iadrive[d->driveno] = d;
+		}
+		for(i = 0; i < n; i++)
+			if(ahciidle(c->drive[i]->port) == -1){
+				dprint("intel 63[12]xesb: port %d wedged; abort\n", i);
+				goto loop;
+			}
+		for(i = 0; i < n; i++){
+			c->drive[i]->mode = DMsatai;
+			configdrive(c->drive[i]);
+		}
+
+		niadrive += nunit;
+		if(head)
+			tail->next = s;
+		else
+			head = s;
+		tail = s;
+	}
+	return head;
+}
+
+static SDev*
+iaid(SDev* sdev)
+{
+	Ctlr *c;
+	int i;
+
+	for(; sdev; sdev = sdev->next){
+		if(sdev->ifc != &sd63xxesbifc)
+			continue;
+		c = sdev->ctlr;
+		for(i = 0; i < NCtlr; i++)
+			if(c == iactlr + i)
+				sdev->idno = 'E' + i;
+	}
+	return nil;
+}
+
+SDifc sd63xxesbifc = {
+	"iahci",
+
+	iapnp,
+	nil,			/* legacy */
+	iaid,
+	iaenable,
+	iadisable,
+
+	iaverify,
+	iaonline,
+	iario,
+	nil,
+	nil,
+
+	scsibio,
+};

+ 4 - 2
sys/src/libhtml/lex.c

@@ -610,7 +610,7 @@ _gettoks(uchar* data, int datalen, int chset, int mtype, int* plen)
 	a = 0;
 	if(ts->mtype == TextHtml) {
 		for(;;) {
-			if(ai == alen) {
+			if(alen - ai < ToksChunk/32) {
 				alen += ToksChunk;
 				a = erealloc(a, alen*sizeof *a);
 			}
@@ -638,7 +638,7 @@ _gettoks(uchar* data, int datalen, int chset, int mtype, int* plen)
 	else {
 		// plain text (non-html) tokens
 		for(;;) {
-			if(ai == alen) {
+			if(alen - ai < ToksChunk/32) {
 				alen += ToksChunk;
 				a = erealloc(a, alen*sizeof *a);
 			}
@@ -1334,6 +1334,8 @@ getchar(TokenSource* ts)
 			c = -1;
 		}
 		break;
+	default:
+		return -1;
 	}
 	return c;
 }