Browse Source

Plan 9 from Bell Labs 2007-10-24

David du Colombier 16 years ago
parent
commit
0379447707

+ 17 - 13
dist/replica/_plan9.db

@@ -7625,7 +7625,7 @@ sys/man/2/rune - 664 sys sys 1143079849 3086
 sys/man/2/runestrcat - 664 sys sys 969499889 1086
 sys/man/2/scribble - 664 sys sys 985638584 3847
 sys/man/2/scsi - 664 sys sys 1170885103 3203
-sys/man/2/sechash - 664 sys sys 1188328413 3537
+sys/man/2/sechash - 664 sys sys 1193174822 3558
 sys/man/2/seek - 664 sys sys 944959696 671
 sys/man/2/segattach - 664 sys sys 1135487945 4166
 sys/man/2/segbrk - 664 sys sys 1165622575 1211
@@ -7674,7 +7674,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 1186946771 3159
 sys/man/3/i82365 - 664 sys sys 954378906 884
-sys/man/3/ip - 664 sys sys 1188581755 25468
+sys/man/3/ip - 664 sys sys 1193163728 26241
 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
@@ -7803,7 +7803,7 @@ sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/8 - 20000000775 sys sys 1162240005 0
 sys/man/8/0intro - 664 sys sys 944959679 247
 sys/man/8/6in4 - 664 sys sys 1186182195 2330
-sys/man/8/9load - 664 sys sys 1191355906 9162
+sys/man/8/9load - 664 sys sys 1193175486 9717
 sys/man/8/9pcon - 664 sys sys 1145881850 2234
 sys/man/8/INDEX - 664 sys sys 1183260468 2773
 sys/man/8/INDEX.html - 664 sys sys 1183240488 8619
@@ -7816,7 +7816,7 @@ sys/man/8/booting - 664 sys sys 1015024984 4136
 sys/man/8/cpurc - 664 sys sys 1187227584 1522
 sys/man/8/cron - 664 sys sys 1063858596 1867
 sys/man/8/dhcpd - 664 sys sys 1191306105 5575
-sys/man/8/disksim - 664 sys sys 1193091432 1701
+sys/man/8/disksim - 664 sys sys 1193174817 1700
 sys/man/8/drawterm - 664 sys sys 1181675938 1921
 sys/man/8/fossilcons - 664 sys sys 1187134504 18542
 sys/man/8/fs - 664 sys sys 1172956177 15086
@@ -7846,7 +7846,7 @@ sys/man/8/ping - 664 sys sys 1169105315 3650
 sys/man/8/plan9.ini - 664 sys sys 1190241912 23835
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
 sys/man/8/ppp - 664 sys sys 1187046045 4430
-sys/man/8/prep - 664 sys sys 1152729153 14013
+sys/man/8/prep - 664 sys sys 1193181551 14162
 sys/man/8/qer - 664 sys sys 1067723129 4909
 sys/man/8/reboot - 664 sys sys 1162423006 443
 sys/man/8/replica - 664 sys sys 1138479158 6383
@@ -9141,7 +9141,8 @@ sys/src/boot/pc/clock.c - 664 sys sys 1103641772 6425
 sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
 sys/src/boot/pc/console.c - 664 sys sys 1094674483 3388
 sys/src/boot/pc/dat.h - 664 sys sys 1190921443 3637
-sys/src/boot/pc/devbios.h - 664 sys sys 1190921600 453
+sys/src/boot/pc/devbios.c - 664 sys sys 1193171393 9376
+sys/src/boot/pc/devbios.h - 664 sys sys 1193167027 493
 sys/src/boot/pc/devfloppy.c - 664 sys sys 1032215913 15505
 sys/src/boot/pc/devfloppy.h - 664 sys sys 1032409559 4081
 sys/src/boot/pc/devi82365.c - 664 sys sys 1144961189 15051
@@ -9176,7 +9177,7 @@ sys/src/boot/pc/etherigbe.c - 664 sys sys 1191446222 41284
 sys/src/boot/pc/ethermii.c - 664 sys sys 1103641771 4413
 sys/src/boot/pc/ethermii.h - 664 sys sys 1071175087 3259
 sys/src/boot/pc/etherrhine.c - 664 sys sys 1144961190 12383
-sys/src/boot/pc/fns.h - 664 sys sys 1153333456 4667
+sys/src/boot/pc/fns.h - 664 sys sys 1193171343 4880
 sys/src/boot/pc/fs.c - 664 sys sys 1094674483 1509
 sys/src/boot/pc/fs.h - 664 sys sys 1094674488 653
 sys/src/boot/pc/ilock.c - 664 sys sys 1015007952 303
@@ -9186,13 +9187,13 @@ sys/src/boot/pc/ip.h - 664 sys sys 1094674489 2461
 sys/src/boot/pc/kbd.c - 664 sys sys 1015007952 10188
 sys/src/boot/pc/kfs.h - 664 sys sys 1032215924 861
 sys/src/boot/pc/kfsboot.c - 664 sys sys 1032215914 4788
-sys/src/boot/pc/l.s - 664 sys sys 1130887225 18115
+sys/src/boot/pc/l.s - 664 sys sys 1193167045 18213
 sys/src/boot/pc/lib.h - 664 sys sys 1190921452 2847
-sys/src/boot/pc/load.c - 664 sys sys 1191886855 9463
+sys/src/boot/pc/load.c - 664 sys sys 1193171385 9602
 sys/src/boot/pc/mbr.s - 664 sys sys 1015007953 6234
 sys/src/boot/pc/mem.h - 664 sys sys 1190921475 3437
 sys/src/boot/pc/memory.c - 664 sys sys 1019533021 10272
-sys/src/boot/pc/mkfile - 664 sys sys 1191886702 3180
+sys/src/boot/pc/mkfile - 664 sys sys 1193171361 3193
 sys/src/boot/pc/noether.c - 664 sys sys 1094674488 358
 sys/src/boot/pc/part.c - 664 sys sys 1114697151 7153
 sys/src/boot/pc/pbs.s - 664 sys sys 1143465387 8291
@@ -9211,7 +9212,7 @@ sys/src/boot/pc/sdata.c - 664 sys sys 1175564193 38846
 sys/src/boot/pc/sdiahci.c - 664 sys sys 1191886818 27133
 sys/src/boot/pc/sdmylex.c - 664 sys sys 1171783051 28694
 sys/src/boot/pc/sdscsi.c - 664 sys sys 1144961224 7006
-sys/src/boot/pc/trap.c - 664 sys sys 1144961191 7499
+sys/src/boot/pc/trap.c - 664 sys sys 1193167011 7497
 sys/src/boot/pc/ureg.h - 664 sys sys 1015007955 550
 sys/src/boot/pc/x16.h - 664 sys sys 1015007955 5265
 sys/src/cmd - 20000000775 sys sys 1157679436 0
@@ -10350,7 +10351,7 @@ sys/src/cmd/fax/receiverc - 775 sys sys 944960990 581
 sys/src/cmd/fax/send.c - 664 sys sys 944960990 923
 sys/src/cmd/fax/subr.c - 664 sys sys 1015090401 1245
 sys/src/cmd/fcp.c - 664 sys sys 1136651872 3799
-sys/src/cmd/file.c - 664 sys sys 1191472670 28522
+sys/src/cmd/file.c - 664 sys sys 1193181267 28836
 sys/src/cmd/fmt.c - 664 sys sys 1137603598 4078
 sys/src/cmd/fortune.c - 664 sys sys 1072729222 1779
 sys/src/cmd/fossil - 20000000775 sys sys 1087005595 0
@@ -14243,6 +14244,9 @@ sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1172764045 10358
 sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1140695062 1889
 sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1172764044 18825
 sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1140695062 618
+sys/src/cmd/usb/disk - 20000000775 sys sys 1193181450 0
+sys/src/cmd/usb/disk/disk.c - 664 sys sys 1193181450 19997
+sys/src/cmd/usb/disk/mkfile - 664 sys sys 1193181450 359
 sys/src/cmd/usb/lib - 20000000775 sys sys 1091204979 0
 sys/src/cmd/usb/lib/device.c - 664 sys sys 1168308464 3284
 sys/src/cmd/usb/lib/dump.c - 664 sys sys 1168308417 13122
@@ -14256,7 +14260,7 @@ sys/src/cmd/usb/misc/mkfile - 664 sys sys 1167255850 374
 sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1178824856 3755
 sys/src/cmd/usb/misc/usbprint - 775 sys sys 1167253831 314
 sys/src/cmd/usb/misc/usbprobe - 775 sys sys 1167253836 173
-sys/src/cmd/usb/mkfile - 664 sys sys 1091327562 354
+sys/src/cmd/usb/mkfile - 664 sys sys 1193181446 361
 sys/src/cmd/usb/usbd - 20000000775 sys sys 1091204979 0
 sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1091204979 675
 sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1091204979 495

+ 17 - 13
dist/replica/plan9.db

@@ -7625,7 +7625,7 @@ sys/man/2/rune - 664 sys sys 1143079849 3086
 sys/man/2/runestrcat - 664 sys sys 969499889 1086
 sys/man/2/scribble - 664 sys sys 985638584 3847
 sys/man/2/scsi - 664 sys sys 1170885103 3203
-sys/man/2/sechash - 664 sys sys 1188328413 3537
+sys/man/2/sechash - 664 sys sys 1193174822 3558
 sys/man/2/seek - 664 sys sys 944959696 671
 sys/man/2/segattach - 664 sys sys 1135487945 4166
 sys/man/2/segbrk - 664 sys sys 1165622575 1211
@@ -7674,7 +7674,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 1186946771 3159
 sys/man/3/i82365 - 664 sys sys 954378906 884
-sys/man/3/ip - 664 sys sys 1188581755 25468
+sys/man/3/ip - 664 sys sys 1193163728 26241
 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
@@ -7803,7 +7803,7 @@ sys/man/7/scat - 664 sys sys 970069855 8904
 sys/man/8 - 20000000775 sys sys 1162240005 0
 sys/man/8/0intro - 664 sys sys 944959679 247
 sys/man/8/6in4 - 664 sys sys 1186182195 2330
-sys/man/8/9load - 664 sys sys 1191355906 9162
+sys/man/8/9load - 664 sys sys 1193175486 9717
 sys/man/8/9pcon - 664 sys sys 1145881850 2234
 sys/man/8/INDEX - 664 sys sys 1183260468 2773
 sys/man/8/INDEX.html - 664 sys sys 1183240488 8619
@@ -7816,7 +7816,7 @@ sys/man/8/booting - 664 sys sys 1015024984 4136
 sys/man/8/cpurc - 664 sys sys 1187227584 1522
 sys/man/8/cron - 664 sys sys 1063858596 1867
 sys/man/8/dhcpd - 664 sys sys 1191306105 5575
-sys/man/8/disksim - 664 sys sys 1193091432 1701
+sys/man/8/disksim - 664 sys sys 1193174817 1700
 sys/man/8/drawterm - 664 sys sys 1181675938 1921
 sys/man/8/fossilcons - 664 sys sys 1187134504 18542
 sys/man/8/fs - 664 sys sys 1172956177 15086
@@ -7846,7 +7846,7 @@ sys/man/8/ping - 664 sys sys 1169105315 3650
 sys/man/8/plan9.ini - 664 sys sys 1190241912 23835
 sys/man/8/pop3 - 664 sys sys 1063854676 2720
 sys/man/8/ppp - 664 sys sys 1187046045 4430
-sys/man/8/prep - 664 sys sys 1152729153 14013
+sys/man/8/prep - 664 sys sys 1193181551 14162
 sys/man/8/qer - 664 sys sys 1067723129 4909
 sys/man/8/reboot - 664 sys sys 1162423006 443
 sys/man/8/replica - 664 sys sys 1138479158 6383
@@ -9141,7 +9141,8 @@ sys/src/boot/pc/clock.c - 664 sys sys 1103641772 6425
 sys/src/boot/pc/conf.c - 664 sys sys 1094674484 10217
 sys/src/boot/pc/console.c - 664 sys sys 1094674483 3388
 sys/src/boot/pc/dat.h - 664 sys sys 1190921443 3637
-sys/src/boot/pc/devbios.h - 664 sys sys 1190921600 453
+sys/src/boot/pc/devbios.c - 664 sys sys 1193171393 9376
+sys/src/boot/pc/devbios.h - 664 sys sys 1193167027 493
 sys/src/boot/pc/devfloppy.c - 664 sys sys 1032215913 15505
 sys/src/boot/pc/devfloppy.h - 664 sys sys 1032409559 4081
 sys/src/boot/pc/devi82365.c - 664 sys sys 1144961189 15051
@@ -9176,7 +9177,7 @@ sys/src/boot/pc/etherigbe.c - 664 sys sys 1191446222 41284
 sys/src/boot/pc/ethermii.c - 664 sys sys 1103641771 4413
 sys/src/boot/pc/ethermii.h - 664 sys sys 1071175087 3259
 sys/src/boot/pc/etherrhine.c - 664 sys sys 1144961190 12383
-sys/src/boot/pc/fns.h - 664 sys sys 1153333456 4667
+sys/src/boot/pc/fns.h - 664 sys sys 1193171343 4880
 sys/src/boot/pc/fs.c - 664 sys sys 1094674483 1509
 sys/src/boot/pc/fs.h - 664 sys sys 1094674488 653
 sys/src/boot/pc/ilock.c - 664 sys sys 1015007952 303
@@ -9186,13 +9187,13 @@ sys/src/boot/pc/ip.h - 664 sys sys 1094674489 2461
 sys/src/boot/pc/kbd.c - 664 sys sys 1015007952 10188
 sys/src/boot/pc/kfs.h - 664 sys sys 1032215924 861
 sys/src/boot/pc/kfsboot.c - 664 sys sys 1032215914 4788
-sys/src/boot/pc/l.s - 664 sys sys 1130887225 18115
+sys/src/boot/pc/l.s - 664 sys sys 1193167045 18213
 sys/src/boot/pc/lib.h - 664 sys sys 1190921452 2847
-sys/src/boot/pc/load.c - 664 sys sys 1191886855 9463
+sys/src/boot/pc/load.c - 664 sys sys 1193171385 9602
 sys/src/boot/pc/mbr.s - 664 sys sys 1015007953 6234
 sys/src/boot/pc/mem.h - 664 sys sys 1190921475 3437
 sys/src/boot/pc/memory.c - 664 sys sys 1019533021 10272
-sys/src/boot/pc/mkfile - 664 sys sys 1191886702 3180
+sys/src/boot/pc/mkfile - 664 sys sys 1193171361 3193
 sys/src/boot/pc/noether.c - 664 sys sys 1094674488 358
 sys/src/boot/pc/part.c - 664 sys sys 1114697151 7153
 sys/src/boot/pc/pbs.s - 664 sys sys 1143465387 8291
@@ -9211,7 +9212,7 @@ sys/src/boot/pc/sdata.c - 664 sys sys 1175564193 38846
 sys/src/boot/pc/sdiahci.c - 664 sys sys 1191886818 27133
 sys/src/boot/pc/sdmylex.c - 664 sys sys 1171783051 28694
 sys/src/boot/pc/sdscsi.c - 664 sys sys 1144961224 7006
-sys/src/boot/pc/trap.c - 664 sys sys 1144961191 7499
+sys/src/boot/pc/trap.c - 664 sys sys 1193167011 7497
 sys/src/boot/pc/ureg.h - 664 sys sys 1015007955 550
 sys/src/boot/pc/x16.h - 664 sys sys 1015007955 5265
 sys/src/cmd - 20000000775 sys sys 1157679436 0
@@ -10350,7 +10351,7 @@ sys/src/cmd/fax/receiverc - 775 sys sys 944960990 581
 sys/src/cmd/fax/send.c - 664 sys sys 944960990 923
 sys/src/cmd/fax/subr.c - 664 sys sys 1015090401 1245
 sys/src/cmd/fcp.c - 664 sys sys 1136651872 3799
-sys/src/cmd/file.c - 664 sys sys 1191472670 28522
+sys/src/cmd/file.c - 664 sys sys 1193181267 28836
 sys/src/cmd/fmt.c - 664 sys sys 1137603598 4078
 sys/src/cmd/fortune.c - 664 sys sys 1072729222 1779
 sys/src/cmd/fossil - 20000000775 sys sys 1087005595 0
@@ -14243,6 +14244,9 @@ sys/src/cmd/usb/audio/usbaudio.c - 664 sys sys 1172764045 10358
 sys/src/cmd/usb/audio/usbaudio.h - 664 sys sys 1140695062 1889
 sys/src/cmd/usb/audio/usbaudioctl.c - 664 sys sys 1172764044 18825
 sys/src/cmd/usb/audio/usbaudioctl.h - 664 sys sys 1140695062 618
+sys/src/cmd/usb/disk - 20000000775 sys sys 1193181450 0
+sys/src/cmd/usb/disk/disk.c - 664 sys sys 1193181450 19997
+sys/src/cmd/usb/disk/mkfile - 664 sys sys 1193181450 359
 sys/src/cmd/usb/lib - 20000000775 sys sys 1091204979 0
 sys/src/cmd/usb/lib/device.c - 664 sys sys 1168308464 3284
 sys/src/cmd/usb/lib/dump.c - 664 sys sys 1168308417 13122
@@ -14256,7 +14260,7 @@ sys/src/cmd/usb/misc/mkfile - 664 sys sys 1167255850 374
 sys/src/cmd/usb/misc/usbmouse.c - 664 sys sys 1178824856 3755
 sys/src/cmd/usb/misc/usbprint - 775 sys sys 1167253831 314
 sys/src/cmd/usb/misc/usbprobe - 775 sys sys 1167253836 173
-sys/src/cmd/usb/mkfile - 664 sys sys 1091327562 354
+sys/src/cmd/usb/mkfile - 664 sys sys 1193181446 361
 sys/src/cmd/usb/usbd - 20000000775 sys sys 1091204979 0
 sys/src/cmd/usb/usbd/dat.h - 664 sys sys 1091204979 675
 sys/src/cmd/usb/usbd/fns.h - 664 sys sys 1091204979 495

+ 19 - 0
dist/replica/plan9.log

@@ -53094,3 +53094,22 @@
 1192811405 0 m rc/bin/dpost - 775 sys sys 1192741346 220
 1192824005 0 c 386/bin/upas/deliver - 775 sys sys 1192823253 99212
 1193092204 0 c sys/man/8/disksim - 664 sys sys 1193091432 1701
+1193112004 0 c sys/man/3/ip - 664 sys sys 1193111561 26033
+1193164206 0 c sys/man/3/ip - 664 sys sys 1193163728 26241
+1193167805 0 c sys/src/boot/pc/l.s - 664 sys sys 1193167045 18213
+1193167805 1 c sys/src/boot/pc/trap.c - 664 sys sys 1193167011 7497
+1193167805 2 c sys/src/boot/pc/devbios.h - 664 sys sys 1193167027 493
+1193171407 0 c sys/src/boot/pc/fns.h - 664 sys sys 1193171343 4880
+1193171407 1 c sys/src/boot/pc/load.c - 664 sys sys 1193171385 9602
+1193171407 2 c sys/src/boot/pc/mkfile - 664 sys sys 1193171361 3193
+1193171407 3 a sys/src/boot/pc/devbios.c - 664 sys sys 1193171393 9376
+1193175004 0 c sys/man/2/sechash - 664 sys sys 1193174822 3558
+1193175004 1 c sys/man/8/disksim - 664 sys sys 1193174817 1700
+1193176805 0 c sys/man/8/9load - 664 sys sys 1193175486 9717
+1193176805 1 c sys/man/8/prep - 664 sys sys 1193175453 14208
+1193182203 0 c sys/man/8/prep - 664 sys sys 1193181551 14162
+1193182203 1 a sys/src/cmd/usb/disk - 20000000775 sys sys 1193181450 0
+1193182203 2 a sys/src/cmd/usb/disk/disk.c - 664 sys sys 1193181450 19997
+1193182203 3 a sys/src/cmd/usb/disk/mkfile - 664 sys sys 1193181450 359
+1193182203 4 c sys/src/cmd/usb/mkfile - 664 sys sys 1193181446 361
+1193182203 5 c sys/src/cmd/file.c - 664 sys sys 1193181267 28836

+ 4 - 3
sys/man/2/sechash

@@ -1,6 +1,6 @@
 .TH SECHASH 2
 .SH NAME
-md4, md5, sha1, aes, hmac_md5, hmac_sha1, hmac_aes, md5pickle, md5unpickle, sha1pickle, sha1unpickle \- cryptographically secure hashes
+md4, md5, sha1, aes, hmac_x, hmac_md5, hmac_sha1, hmac_aes, md5pickle, md5unpickle, sha1pickle, sha1unpickle \- cryptographically secure hashes
 .SH SYNOPSIS
 .de Ti
 .in +0.5i
@@ -81,7 +81,7 @@ differ only in the length of the resulting digest
 and in the security of the hash.  Usage for each is the same.
 The first call to the routine should have
 .B nil
-as the 
+as the
 .I state
 parameter.  This call returns a state which can be used to chain
 subsequent calls.
@@ -95,8 +95,9 @@ This last call will free the state and copy the result into
 The constants
 .IR MD4dlen ,
 .IR MD5dlen ,
+.IR SHA1dlen ,
 and
-.I SHA1dlen
+.I AESdlen
 define the lengths of the digests.
 .PP
 .IR Hmac_md5 ,

+ 7 - 1
sys/man/3/ip

@@ -667,7 +667,7 @@ ends.
 TCP
 .B ctl
 files support the following additional messages:
-.TF keepaliven
+.TF checksumnn
 .PD
 .TP
 .B hangup
@@ -702,6 +702,12 @@ picks a TCP sequence number at random for keepalives.
 If that number gets acked by the other end,
 .I ip
 shuts down the connection.
+Some firewalls,
+notably ones that perform stateful inspection,
+discard such out-of-specification keepalives,
+so connections through such firewalls
+will be killed after five minutes
+by the lack of keepalives.
 .
 .SS UDP
 UDP connections carry unreliable and unordered datagrams.  A read from

+ 72 - 53
sys/man/8/9load

@@ -1,14 +1,10 @@
 .TH 9LOAD 8
 .SH NAME
-9load, ld, 9pxeload \- PC bootstrap program
+9load, 9pxeload, ld \- PC bootstrap program
 .SH SYNOPSIS
 .I "(Under MS-DOS)
 .br
-[
-.I drive
-:][
-.I path
-.RB ] ld
+.RI [ drive\f(CW:\fP ][ path ] ld
 [
 .I 9load
 ]
@@ -26,6 +22,11 @@ if DOS is running.
 .I 9load
 is run automatically by the boot procedures described below;
 it cannot be run directly by hand.
+.I 9pxeload
+is a version of
+.I 9load
+that can be booted using the PXE download
+found in some ethernet card BIOSes.
 There are three bootstrap sequences:
 .IP \-
 BIOS, MBR, disk partition PBS,
@@ -60,9 +61,10 @@ and then only if the machine's BIOS supports
 linear block addressing (LBA) mode for disk transfers.
 .PP
 When booting from floppy or hard disk, the BIOS loads the
-first sector of the medium at location 0x7C00.  In the
-case of a floppy, this is the PBS.  In the case of a hard
-disk it it the master boot record (MBR).
+first sector of the medium at location
+.BR 0x7C00 .
+In the case of a floppy, this is the PBS.
+In the case of a hard disk, it is the master boot record (MBR).
 The MBR copies itself to address
 .BR 0x600 ,
 finds the active partition and loads its PBS at address
@@ -112,23 +114,16 @@ and
 are compiled from the same source.
 .PP
 .I 9load
-begins execution at address
+begins execution at virtual address
 .B 0x80010000
 (64K) and
 loads the
 .I bootfile
 at the entry address specified by the header,
-usually
+usually virtual
 .BR 0xF0100020 .
 After loading, control is passed to the entry location.
 .PP
-Finally,
-.I 9pxeload
-is a version of
-.I 9load
-that can be booted using the PXE download
-found on some ethernet card BIOSs.
-.PP
 In summary,
 Plan 9 can be booted on a PC three different ways:
 either by booting MS-DOS and using
@@ -146,7 +141,7 @@ to install the appropriate files and bootstrap sectors
 or by using a PXE capable BIOS to boot
 .I 9pxeload
 directly over the ethernet.
-.PP
+.SS Bootfile
 The
 .IR bootfile ,
 which may be compressed with
@@ -182,6 +177,7 @@ Supported
 .I devices
 are
 .TF \fLethern
+.PD
 .TP
 .BI fd n
 An MS-DOS floppy disk.
@@ -231,16 +227,52 @@ FAT file system for configuration.
 By convention, this partition is called
 .BR 9fat .
 There is no default partition or pathname.
-.PD
-.PP
+.TP
+.B bios0
+(Not in
+.IR 9pxeload .)
+.I 9load
+reads the first LBA device
+in the BIOS's list of devices to try to boot from,
+using the BIOS INT 13 calls also used by
+.IR pbslba .
+It currently does not understand any form of partition table;
+see the EXAMPLES in
+.IR prep (8)
+for how to format such a device.
+This is mostly useful for booting from USB devices so far.
+.SS Kernel loading
 When
 .I 9load
-starts running at physical address 0x10000,
+starts running at physical address
+.BR 0x10000 ,
 it switches to 32-bit mode.
 It then double maps the first 16Mb of physical memory to
-virtual addresses 0 and 0x80000000.
-Physical memory from 0x300000 upwards is used as data
-space.
+virtual addresses
+.B 0
+and
+.BR 0x80000000 .
+Physical memory from
+.B 0x300000
+upwards is used as data space.
+.PP
+.I 9pxeload
+differs slightly in operation from
+.IR 9load .
+It is initially loaded by the PXE BIOS at physical address
+.BR 0x7C00 .
+Only devices which can be automatically configured,
+e.g. most PCI ethernet adapters,
+will be recognised.
+If the file
+.BI /cfg/pxe/ XXXXXXXXXXXX
+can be located via a DHCP server,
+where
+.I XXXXXXXXXXXX
+is the MAC address of a recognised ethernet adapter,
+the contents are obtained and used as a
+.IR plan9.ini .
+.PP
 Next, in order to find configuration information,
 .I 9load
 searches all units on devices
@@ -258,7 +290,8 @@ on a partition named
 or
 .BR 9fat .
 If one is found, searching stops and the file is read into memory
-at physical address 0x1200
+at physical address
+.B 0x1200
 where it can be found later by any loaded
 .IR bootfile .
 Some options in
@@ -342,7 +375,7 @@ a
 in response to the
 .L "Boot from:
 prompt.
-.PP
+.SS Other facilities and caveats
 .I 9load
 parses the master boot record and Plan 9 partition tables
 (see
@@ -355,6 +388,8 @@ for the
 This is used by
 .IR sd (3)
 to initialize partitions so that
+.IR fossil (4)
+or
 .IR kfs (4)
 file systems can be mounted as the root file system.
 A more extensive partitioning is typically done by
@@ -383,36 +418,16 @@ the disk.
 See
 .IR dossrv (4)
 for information on ensuring this.
-.PP
-.I 9pxeload
-differs slightly in operation from
-.IR 9load .
-It is initially loaded by the PXE BIOS at physical address 0x7C00.
-Only devices which can be automatically configured,
-e.g. most PCI ethernet adapters,
-will be recognised.
-If the file
-.IB /cfg/pxe/ XXXXXXXXXXXX
-can be located via a DHCP server,
-where
-.B XXXXXXXXXXXX
-is the MAC address of a recognised ethernet adapter,
-the contents are obtained and used as a
-.IR plan9.ini .
 .SH FILES
-.RI [ drive :]
-[
-.I path
-.RB ] 9load
+.RI [ drive\f(CW:\fP ][ path ]\c
+.B 9load
 .br
-.RI [ drive :]
-[
-.I path
-.RB ] ld
+.RI [ drive\f(CW:\fP ][ path ]\c
+.B ld
 .br
-.IB "FAT filesystem" :\eplan9\eplan9.ini
+.IB "FAT-filesystem" :\eplan9\eplan9.ini
 .br
-.IB "FAT filesystem" :\eplan9.ini
+.IB "FAT-filesystem" :\eplan9.ini
 .SH SOURCE
 .B /sys/src/boot/pc
 .SH "SEE ALSO"
@@ -438,3 +453,7 @@ obtains the information normally found in a disc
 file,
 and thereby the kernel to load and boot,
 is not ideal and may change in the future.
+.PP
+The
+.B bios
+device should understand partition tables, if present.

+ 1 - 1
sys/man/8/disksim

@@ -47,7 +47,7 @@ option causes
 to use
 .I file
 as the initial contents of the disk rather than a zeroed image.
-Changes made to the disk are written back to 
+Changes made to the disk are written back to
 .I file
 unless the
 .B -r

+ 46 - 38
sys/man/8/prep

@@ -11,7 +11,7 @@ prep, fdisk, format, mbr \- prepare hard and floppy diskettes, flashes
 .I name
 ]...
 [
-.B -s 
+.B -s
 .I sectorsize
 ]
 .I plan9partition
@@ -31,7 +31,7 @@ prep, fdisk, format, mbr \- prepare hard and floppy diskettes, flashes
 .B -dfvx
 ]
 [
-.B -b 
+.B -b
 .I bootblock
 ]
 [
@@ -100,10 +100,10 @@ The Plan 9 partition often contains a number of
 conventionally named subpartitions.
 They include:
 .TF arenas
-.TP 
+.TP
 .B 9fat
 A small FAT file system used to hold
-configuration information 
+configuration information
 (such as
 .B plan9.ini
 and
@@ -156,7 +156,7 @@ A non-archived
 file system.
 .TP
 .B swap
-A 
+A
 .IR swap (8)
 swap partition.
 .PD
@@ -164,7 +164,7 @@ swap partition.
 .I Fdisk
 edits the PC partition table and is usually
 invoked with a disk like
-.B /dev/sdC0/data 
+.B /dev/sdC0/data
 as its argument, while
 .I prep
 edits the Plan 9 partition table
@@ -199,7 +199,7 @@ will mark the new partition active.
 flag takes the name of a partition to create.
 (See the list above for partition names.)
 It can be repeated to specify a list of partitions to create.
-If the disk is currently unpartitioned, 
+If the disk is currently unpartitioned,
 .I prep
 will create the named partitions on the disk,
 attempting to use the entire disk in a sensible manner.
@@ -210,12 +210,12 @@ Start with a blank disk, ignoring any extant partition table.
 .TP
 .B -p
 Print a sequence of commands that when sent to the disk device's
-.B ctl 
-file 
+.B ctl
+file
 will bring the partition
 table information kept by
-the 
-.IR sd (3) 
+the
+.IR sd (3)
 driver up to date.
 Then exit.
 .I Prep
@@ -223,7 +223,7 @@ will check to see if it is being called with a disk partition
 (rather than an entire disk) as its argument; if so, it
 will translate the printed sectors by the partition's offset
 within the disk.
-Since 
+Since
 .I fdisk
 operates on a table of unnamed partitions,
 it assigns names based on the partition type
@@ -240,16 +240,16 @@ and resolves collisions by appending a numbered suffix.
 .BR dos.2 ).
 .TP
 .B -r
-In the absence of the 
+In the absence of the
 .B -p
 and
 .B -w
-flags, 
+flags,
 .I prep
 and
 .I fdisk
 enter an interactive partition editor;
-the 
+the
 .B -r
 flag runs the editor in read-only mode.
 .TP
@@ -355,22 +355,22 @@ is set to one past the last disk sector.
 When evaluating
 .IR end ,
 .B $
-is set to the maximum value that 
+is set to the maximum value that
 .I end
 can take on without running off the disk
 or into another partition.
 Finally, the expression
 .IB n %
-evaluates to 
+evaluates to
 .RI ( n × disksize )/100.
-As an example, 
+As an example,
 .B a
 .B .
 .B .+20%
 creates a new partition starting at
 .B .
 that takes up a fifth of the disk,
-and 
+and
 .B a
 .B 1000
 .B $
@@ -400,13 +400,13 @@ Unpartitioned regions are also listed.
 The table consists of a number of lines containing
 partition name, beginning and ending sectors,
 and total size.
-A 
+A
 .B '
 is prefixed to the names of partitions
 whose entries have been modified but not written to disk.
 .I Fdisk
 adds to the end of each line a textual partition type,
-and places a 
+and places a
 .B *
 next to the name of the active partition
 (see the
@@ -455,7 +455,7 @@ Print the names of empty slots in the partition table, i.e., the
 valid names to use when creating a new partition.
 .TP
 .BI t " \fR[\fI type \fR]
-Set the partition type.  If it is not given, 
+Set the partition type.  If it is not given,
 .I fdisk
 will display a list of choices and then prompt for it.
 .PD
@@ -464,7 +464,7 @@ will display a list of choices and then prompt for it.
 prepares for use the floppy diskette or hard disk partition in the file named
 .IR disk ,
 for example
-.B /dev/fd0disk 
+.B /dev/fd0disk
 or
 .BR /dev/sdC0/9fat .
 The options are:
@@ -502,15 +502,15 @@ fixed disk
 The default when
 .I disk
 is a floppy drive is the highest possible on the device.
-When 
+When
 .I disk
 is a regular file, the default is
 .BR 3½HD .
-When 
+When
 .I disk
 is an
 .IR sd (3)
-device, the default is 
+device, the default is
 .BR hard .
 .RE
 .TP
@@ -540,7 +540,7 @@ add a
 when creating the FAT file system.
 .TP
 .BI -r
-mark the first 
+mark the first
 .I nresrv
 sectors of the partition as ``reserved''.
 Since the first sector always contains the
@@ -550,7 +550,7 @@ the
 sectors starting at sector 1 as ``reserved''.
 When formatting the
 .B 9fat
-partition, 
+partition,
 .B -r
 .B 2
 should be used to jump over the partition table sector.
@@ -569,17 +569,17 @@ If a file is named
 it will be created with the
 .B SYSTEM
 attribute set so that
-.IR dossrv (4) 
+.IR dossrv (4)
 keeps it contiguous when modifying it.
 .PP
 .I Format
 checks for a number of common mistakes; in particular,
-it will refuse to format a 
+it will refuse to format a
 .B 9fat
-partition unless 
+partition unless
 .B -r
-is specified with 
-.I nresrv 
+is specified with
+.I nresrv
 larger than two.
 It also refuses to format a raw
 .IR sd (3)
@@ -603,9 +603,9 @@ to make the disk a boot disk.
 It gets loaded by the BIOS at 0x7C00,
 reads the first sector of the
 root directory into address 0x7E00, and looks for
-a directory entry named 
+a directory entry named
 .BR 9LOAD .
-If it finds such an entry, 
+If it finds such an entry,
 it uses
 single sector reads to load the file into address 0x10000 and then
 jumps to the loaded file image.
@@ -624,7 +624,7 @@ contains more than one sector of `boot block',
 the rest will be copied into the first track of the
 disk, if it fits.
 This boot block should not be confused with the
-boot block used by 
+boot block used by
 .IR format ,
 which goes in sector 0 of a partition.
 Typically, the boot block in the master boot record
@@ -638,9 +638,9 @@ which then loads the operating system.
 If MS-DOS or Windows 9[58] is already installed
 on your hard disk, the master boot record
 already has a suitable boot block.
-Otherwise, 
+Otherwise,
 .B /386/mbr
-is an appropriate 
+is an appropriate
 .IR mbrfile .
 It detects and uses LBA addressing when available
 from the BIOS (the same could not
@@ -690,6 +690,14 @@ disk/format -b /386/pbslba -d -r 2 /dev/sdC0/9fat \e
 	/386/9load /386/9pcf /tmp/plan9.ini
 .EE
 .PP
+Create a bootable USB disk or flash-memory device to be loaded
+via the BIOS:
+.IP
+.EX
+usb/disk
+disk/format -b /386/pbslba -df /n/disk/0/data \e
+	/386/9load /386/9pcf.gz /tmp/plan9.ini
+.EE
 .SH SOURCE
 .B /sys/src/cmd/disk/prep
 .br

+ 434 - 0
sys/src/boot/pc/devbios.c

@@ -0,0 +1,434 @@
+/*
+ * boot driver for BIOS devices
+ *
+ * BUGS:
+ *	doesn't understand disk partitions at all; convert to sdbios.c?
+ */
+#include <u.h>
+#include "lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "fs.h"
+
+typedef uvlong Devbytes, Devsects;
+
+typedef struct Biosdrive Biosdrive;	/* 1 drive -> ndevs */
+typedef struct Biosdev Biosdev;
+
+enum {
+	Debug = 0,
+	Maxdevs = 4,
+
+	CF = 1,
+	Flopid = 0,			/* first floppy */
+	Baseid = 0x80,			/* first disk */
+	Sectsize = 512,
+
+	/* bios calls: int 13 disk services */
+	Biosinit	= 0,		/* initialise disk & floppy ctlrs */
+	Biosdrvsts,
+	Bioschsrdsects,
+	Biosdrvparam	= 8,
+	Biosctlrinit,
+	Biosreset	=  0xd,		/* reset disk */
+	Biosdrvrdy	= 0x10,
+	Biosdrvtype	= 0x15,
+	Biosckext	= 0x41,
+	Biosrdsect,
+	Biosedrvparam	= 0x48,
+
+	/* disk types */
+	Typenone = 0,
+	Typedisk = 3,
+};
+
+struct Biosdrive {
+	int	ndevs;
+};
+struct Biosdev {
+	Devbytes size;
+	Devbytes offset;
+	uchar	id;
+	char	type;
+};
+
+void	realmode(int intr, Ureg *ureg);		/* from trap.c */
+
+static Biosdev bdev[Maxdevs];
+static Biosdrive bdrive;
+static Ureg regs;
+
+static int	dreset(uchar drive);
+static Devbytes	extgetsize(uchar drive);
+static Devbytes	getsize(uchar drive, char *type);
+static int	islba(uchar drive);
+
+static int
+biosdiskcall(Ureg *rp, uchar op, ulong bx, ulong dx, ulong si)
+{
+	memset(rp, 0, sizeof *rp);
+	rp->ax = op << 8;
+	rp->bx = bx;
+	rp->dx = dx;			/* often drive id */
+	rp->si = si;
+	/* pass command in *rp, get results from there */
+	realmode(0x13, rp);
+	if (rp->flags & CF) {
+//		print("biosdiskcall: int 13 op 0x%ux drive 0x%lux failed, "
+//			"ah error code 0x%ux\n", op, dx, (uchar)(rp->ax >> 8));
+		return -1;
+	}
+	return 0;
+}
+
+/*
+ * Find out what the bios knows about devices.
+ * our boot device could be usb; ghod only knows where it will appear.
+ */
+int
+biosinit(void)
+{
+	int devid, lba, mask, lastbit;
+	Devbytes size;
+	char type;
+	Biosdev *bdp;
+
+	mask = lastbit = 0;
+
+	/* 9pxeload can't use bios int 13 calls; they wedge the machine */
+	if (pxe)
+		return mask;
+	for (devid = 0; devid < (1 << 8) && bdrive.ndevs < Maxdevs; devid++) {
+		lba = islba(devid);
+		if(!lba /* || devid != Baseid && dreset(devid) < 0 */ )
+			continue;
+		type = Typedisk;		/* HACK */
+		if (getsize(devid, &type) == 0) { /* no device, end of range */
+			devid &= ~0xf;
+			devid += 0x10;
+			devid--;
+			continue;
+		}
+		size = extgetsize(devid);
+		print("bios%d: drive 0x%ux: %llud bytes, type %d\n",
+			bdrive.ndevs, devid, size, type);
+		lastbit = 1 << bdrive.ndevs;
+		mask |= lastbit;
+		bdp = &bdev[bdrive.ndevs++];
+		bdp->id = devid;
+		bdp->type = type;
+		bdp->size = size;
+	}
+	/*
+	 * bioses seem to only be able to read from drive number 0x80
+	 * and certainly can't read from the highest drive number, even if
+	 * there is only one.  attempting to read from the last drive number
+	 * yields a hung machine or a two-minute pause.
+	 */
+	if (bdrive.ndevs > 0) {
+		if (bdrive.ndevs == 1)
+			print("biosinit: sorry, only one bios drive; "
+				"can't read last one\n");
+		bdrive.ndevs--;	/* omit last drive number; it can't be read */
+		mask &= ~lastbit;
+	}
+	return mask;
+}
+
+void
+biosinitdev(int i, char *name)
+{
+	if(i >= bdrive.ndevs)
+		panic("biosinitdev");
+	sprint(name, "bios%d", i);
+}
+
+void
+biosprintdevs(int i)
+{
+	if(i >= bdrive.ndevs){
+		print("got a print for %d, only got %d\n", i, bdrive.ndevs);
+		panic("biosprintdevs");
+	}
+	print(" bios%d", i);
+}
+
+int
+biosboot(int dev, char *file, Boot *b)
+{
+	Fs *fs;
+
+	if(strncmp(file, "dos!", 4) == 0)
+		file += 4;
+	if(strchr(file, '!') != nil || strcmp(file, "") == 0) {
+		print("syntax is bios0!file\n");
+		return -1;
+	}
+
+	fs = biosgetfspart(dev, "9fat", 1);
+	if(fs == nil)
+		return -1;
+	return fsboot(fs, file, b);
+}
+
+// void
+// biosprintbootdevs(int dev)
+// {
+// 	print(" bios%d: %ux, %lld", dev, bdev[dev].id, bdev[dev].size);
+// }
+
+typedef struct Extread {
+	uchar	size;
+	uchar	unused1;
+	uchar	nsects;
+	uchar	unused2;
+	ulong	addr;		/* segment:offset */
+	uvlong	stsect;		/* starting sector */
+} Extread;
+
+/* read n bytes at sector offset into a from drive id */
+long
+sectread(void *a, long n, Devsects offset, uchar id)
+{
+	uchar *biosparam, *cp;
+	Extread *erp;
+
+	if(n < 0 || n > Sectsize)
+		return -1;
+	if(Debug)
+		memset((uchar *)BIOSXCHG, 'r', Sectsize); /* preclean the buffer. */
+
+	biosdiskcall(&regs, Biosdrvrdy, 0, id, 0);
+
+	/* space for a BIG sector, just in case... */
+	biosparam = (uchar *)BIOSXCHG + 2*1024;
+
+	/* read into BIOSXCHG */
+	erp = (Extread *)biosparam;
+	memset(erp, 0, sizeof *erp);
+	erp->size = sizeof *erp;
+	erp->nsects = 1;
+	erp->addr = PADDR(BIOSXCHG);
+	erp->stsect = offset;
+	if (biosdiskcall(&regs, Biosrdsect, 0, id, PADDR(erp)) < 0) {
+		print("sectread: bios failed to read %ld @ off %lld from %ux\n",
+			n, offset, id);
+		return -1;
+	}
+
+	/* copy into caller's buffer */
+	memmove(a, (char *)BIOSXCHG, n);
+	if(Debug){
+		cp = (uchar *)BIOSXCHG;
+		print("-%ux %ux %ux %ux--%16.16s-\n",
+			cp[0], cp[1], cp[2], cp[3], (char *)cp + 480);
+	}
+	return n;
+}
+
+/* not tested yet. */
+static int
+dreset(uchar drive)
+{
+if (0) {
+print("devbios: resetting disk controllers...");
+	biosdiskcall(&regs, Biosinit, 0, drive, 0);
+print("\n");
+}
+	return regs.ax? -1: 0;		/* ax!=0 on error */
+}
+
+static int
+islba(uchar drive)
+{
+	if (biosdiskcall(&regs, Biosckext, 0x55aa, drive, 0) < 0) {
+//		print("islba: failed\n");
+		return 0;
+	}
+	if(regs.bx != 0xaa55){
+		print("islba: buggy bios\n");
+		return 0;
+	}
+	if (Debug)
+		print("islba: drive %ux extensions version %d.%d cx 0x%lux\n",
+			drive, (uchar)(regs.ax >> 8),
+			(uchar)regs.ax, regs.cx); /* cx: 4=edd, 1=use dap */
+	if(!(regs.cx & 1)){
+		print("islba: drive %ux: no dap bit in extensions cx\n", drive);
+		return 0;
+	}
+//	dreset(drive);		/* pbslba does this, but it wedges here */
+	return 1;
+}
+
+/*
+ * works so so... some floppies are 0x80+x when they shouldn't be,
+ * and report lba even if they cannot...
+ */
+static Devbytes
+getsize(uchar drive, char *typep)
+{
+	int dtype;
+	Devsects size;
+
+	if (biosdiskcall(&regs, Biosdrvtype, 0x55aa, drive, 0) < 0)
+		return 0;
+
+	dtype = (ushort)regs.ax >> 8;
+	size = (ushort)regs.cx | regs.dx << 16;
+	if(dtype == Typenone){
+		print("no such device %ux of type %ux\n", drive, dtype);
+		return 0;
+	}
+	*typep = dtype;
+	if(dtype != Typedisk){
+		print("non-disk device %ux of type %ux\n", drive, dtype);
+		return 0;
+	}
+	return (Devbytes)size * Sectsize; /* size is in sectors; return bytes */
+}
+
+typedef struct Edrvparam {
+	/* from edd 1.1 spec */
+	ushort	size;			/* max. buffer size */
+	ushort	flags;
+	ulong	physcyls;
+	ulong	physheads;
+	ulong	phystracksects;
+	uvlong	physsects;
+	ushort	sectsz;
+	void	*dpte;			/* ~0ull: invalid */
+
+	/* remainder from edd 3.0 spec */
+	ushort	key;			/* 0xbedd if present */
+	uchar	dpilen;
+	uchar	unused1;
+	ushort	unused2;
+	char	bustype[4];		/* "PCI" or "ISA" */
+	char	ifctype[8]; /* "ATA", "ATAPI", "SCSI", "USB", "1394", "FIBRE" */
+	uvlong	ifcpath;
+	uvlong	devpath;
+	uchar	unused3;
+	uchar	dpicksum;
+} Edrvparam;
+
+/* extended get size */
+static Devbytes
+extgetsize(uchar drive)
+{
+	Edrvparam *edp;
+
+	edp = (Edrvparam *)BIOSXCHG;
+	memset(edp, 0, sizeof *edp);
+	edp->size = sizeof *edp;
+	edp->dpilen = 36;
+	if (biosdiskcall(&regs, Biosedrvparam, 0, drive, PADDR(edp)) < 0) {
+//		print("extgetsize: Biosedrvparam failed\n");
+		return 0;
+	}
+	if(Debug) {
+		print("extgetsize: drive %ux info flags 0x%ux",
+			drive, edp->flags);
+		if (edp->key == 0xbedd)
+			print(" %s %s", edp->bustype, edp->ifctype);
+		print("\n");
+	}
+	return edp->physsects * edp->sectsz;
+}
+
+long
+biosread(Fs *fs, void *a, long n)
+{
+	int want, got, part;
+	long totnr, stuck;
+	Devbytes offset;
+	uchar id;
+	Biosdev *bdp;
+
+	if(fs->dev > bdrive.ndevs)
+		return -1;
+	if (n <= 0)
+		return n;
+	bdp = &bdev[fs->dev];
+	id = bdp->id;
+	offset = bdp->offset;
+	stuck = 0;
+	for (totnr = 0; totnr < n && stuck < 4; totnr += got) {
+		want = Sectsize;
+		if (totnr + want > n)
+			want = n - totnr;
+		if(Debug)
+			print("bios%d, read: %ld @ off %lld, want: %d, id: %ux\n",
+				fs->dev, n, offset, want, id);
+		part = offset % Sectsize;
+		if (part != 0) {	/* back up to start of sector */
+			offset -= part;
+			totnr  -= part;
+			if (totnr < 0) {
+				print("biosread: negative count %ld\n", totnr);
+				return -1;
+			}
+		}
+		if ((vlong)offset < 0) {
+			print("biosread: negative offset %lld\n", offset);
+			return -1;
+		}
+		got = sectread((char *)a + totnr, want, offset/Sectsize, id);
+		if(got <= 0){
+			print("biosread: failed to read %ld @ off %lld of %ux, "
+				"want %d got %d\n", n, offset, id, want, got);
+			return -1;
+		}
+		offset += got;
+		bdp->offset = offset;
+		if (got < Sectsize)
+			stuck++;	/* we'll have to re-read this sector */
+		else
+			stuck = 0;
+	}
+	return totnr;
+}
+
+vlong
+biosseek(Fs *fs, vlong off)
+{
+	if (off < 0) {
+		print("biosseek(fs, %lld) is illegal\n", off);
+		return -1;
+	}
+	if(fs->dev > bdrive.ndevs) {
+		print("biosseek: fs->dev %d > bdrive.ndevs %d\n",
+			fs->dev, bdrive.ndevs);
+		return -1;
+	}
+	bdev[fs->dev].offset = off;	/* do not know size... (yet) */
+	return off;
+}
+
+void *
+biosgetfspart(int i, char *name, int chatty)
+{
+	static Fs fs;
+
+	if(strcmp(name, "9fat") != 0){
+		if(chatty)
+			print("unknown partition bios%d!%s (use bios%d!9fat)\n",
+				i, name, i);
+		return nil;
+	}
+
+	fs.dev = i;
+	fs.diskread = biosread;
+	fs.diskseek = biosseek;
+
+	if(dosinit(&fs) < 0){
+		if(chatty)
+			print("bios%d!%s does not contain a FAT file system\n",
+				i, name);
+		return nil;
+	}
+	return &fs;
+}

+ 4 - 2
sys/src/boot/pc/devbios.h

@@ -1,3 +1,5 @@
+typedef uvlong Devbytes, Devsects;
+
 typedef struct Biosdrive Biosdrive;	/* 1 drive -> ndevs */
 typedef struct Biosdev Biosdev;
 
@@ -5,8 +7,8 @@ struct Biosdrive {
 	int	ndevs;
 };
 struct Biosdev {
-	uvlong	size;
-	uvlong	offset;
+	Devbytes size;
+	Devbytes offset;
 	uchar	id;
 	char	type;
 };

+ 6 - 0
sys/src/boot/pc/fns.h

@@ -4,6 +4,12 @@ Alarm*	alarm(int, void (*)(Alarm*), void*);
 void	alarminit(void);
 Block*	allocb(int);
 void	apminit(void);
+int	biosboot(int dev, char *file, Boot *b);
+void*	biosgetfspart(int i, char *name, int chatty);
+void	biosinitdev(int i, char *name);
+int	biosinit(void);
+void	biosprintbootdevs(int dev);
+void	biosprintdevs(int i);
 int	bootpboot(int, char*, Boot*);
 int	bootpass(Boot*, void*, int);
 void	cancel(Alarm*);

+ 5 - 0
sys/src/boot/pc/l.s

@@ -837,6 +837,10 @@ TEXT hello(SB), $0
 	BYTE $'B'; BYTE $'e'; BYTE $'l'; BYTE $'l';
 	BYTE $' '; BYTE $'L'; BYTE $'a'; BYTE $'b';
 	BYTE $'s'; 
+#ifdef PXE
+	BYTE $' '; BYTE $'b'; BYTE $'y'; BYTE $' ';
+	BYTE $'P'; BYTE $'X'; BYTE $'E';
+#endif
 	BYTE $'\r';
 	BYTE $'\n';
 	BYTE $'\z';
@@ -1002,6 +1006,7 @@ TEXT now16real(SB), $0
 TEXT realmodeintrinst(SB), $0
 	INT $0x00
 
+
 	/* save the registers after the call */
 
 	LWI(0x7bfc, rSP)

+ 14 - 7
sys/src/boot/pc/load.c

@@ -4,7 +4,7 @@
 #include "dat.h"
 #include "fns.h"
 #include "io.h"
-
+#include "sd.h"
 #include "fs.h"
 
 /*
@@ -62,6 +62,14 @@ Type types[] = {
 		diskparts,
 		diskinis,
 	},
+	{	Tbios,
+		Fini|Ffs,
+		biosinit, biosinitdev,
+		biosgetfspart, nil, biosboot,
+		biosprintdevs,
+		diskparts,
+		diskinis,
+	},
 	{	Tnil,
 		0,
 		nil, nil, nil, nil, nil, nil,
@@ -72,8 +80,6 @@ Type types[] = {
 	},
 };
 
-#include "sd.h"
-
 extern SDifc sdataifc;
 extern SDifc sdiahciifc;
 
@@ -91,9 +97,9 @@ extern SDifc sdmylexifc;
 extern SDifc sd53c8xxifc;
 SDifc* sdifc[] = {
 	&sdataifc,
+	&sdiahciifc,
 	&sdmylexifc,
 	&sd53c8xxifc,
-	&sdiahciifc,
 	nil,
 };
 
@@ -279,6 +285,7 @@ static char *typenm[] = {
 	[Tsd]		"Tsd",
 	[Tether]	"Tether",
 	[Tcd]		"Tcd",
+	[Tbios]		"Tbios",
 };
 
 void
@@ -326,7 +333,7 @@ main(void)
 	probe(Tany, Fnone, Dany);
 	tried = 0;
 	mode = Mauto;
-	
+
 	p = getconf("bootfile");
 
 	if(p != 0) {
@@ -406,7 +413,7 @@ cistrcmp(char *a, char *b)
 	for(;;){
 		ac = *a++;
 		bc = *b++;
-	
+
 		if(ac >= 'A' && ac <= 'Z')
 			ac = 'a' + (ac - 'A');
 		if(bc >= 'A' && bc <= 'Z')
@@ -568,7 +575,7 @@ warp9(ulong entry)
 		sddetach();
 
 	consdrain();
-	
+
 	splhi();
 	trapdisable();
 

+ 1 - 0
sys/src/boot/pc/mkfile

@@ -35,6 +35,7 @@ LOAD=\
 	boot.$O\
 	cis.$O\
 	conf.$O\
+	devbios.$O\
 	devi82365.$O\
 	devpccard.$O\
 	devsd.$O\

+ 5 - 4
sys/src/boot/pc/trap.c

@@ -315,13 +315,14 @@ trap(Ureg *ur)
 	} while(h);
 }
 
+extern void realmode0(void);	/* in l.s */
+
+extern int realmodeintr;
+extern Ureg realmoderegs;
+
 void
 realmode(int intr, Ureg *ureg)
 {
-	extern void realmode0(void);	/* in l.s */
-	extern int realmodeintr;
-	extern Ureg realmoderegs;
-
 	realmoderegs = *ureg;
 	realmodeintr = intr;
 	trapdisable();

+ 7 - 0
sys/src/cmd/file.c

@@ -802,6 +802,13 @@ struct	FILE_STRING
 	".nr",			"troff input",		3,	"text/troff",
 	".tr",			"troff input",		3,	"text/troff",
 	"vac:",			"venti score",		4,	"text/plain",
+	"-----BEGIN CERTIFICATE-----\n",
+				"pem certificate",	3,	"text/plain",
+	"-----BEGIN TRUSTED CERTIFICATE-----\n",
+				"pem trusted certificate", 3,	"text/plain",
+	"-----BEGIN X509 CERTIFICATE-----\n",
+				"pem x.509 certificate", 3,	"text/plain",
+	"subject=/C=",		"pem certificate with header", 3, "text/plain",
 	0,0,0,0
 };
 

+ 1005 - 0
sys/src/cmd/usb/disk/disk.c

@@ -0,0 +1,1005 @@
+/*
+ * usb/disk - usb mass storage file server
+ */
+#include <u.h>
+#include <libc.h>
+#include <ctype.h>
+#include <bio.h>
+#include <fcall.h>
+#include <thread.h>
+#include <9p.h>
+#include "scsireq.h"
+#include "usb.h"
+
+/*
+ * mass storage transport protocols and subclasses,
+ * from usb mass storage class specification overview rev 1.2
+ */
+enum {
+	Protocbi =	0,	/* control/bulk/interrupt; mainly floppies */
+	Protocb =	1,	/*   "  with no interrupt; mainly floppies */
+	Protobulk =	0x50,	/* bulk only */
+
+	Subrbc =	1,	/* reduced blk cmds */
+	Subatapi =	2,	/* cd/dvd using sff-8020i or mmc-2 cmd blks */
+	Subqic =	3,	/* QIC-157 tapes */
+	Subufi =	4,	/* floppy */
+	Sub8070 =	5,	/* removable media, atapi-like */
+	Subscsi =	6,	/* scsi transparent cmd set */
+	Subisd200 =	7,	/* ISD200 ATA */
+	Subdev =	0xff,	/* use device's value */
+};
+
+enum {
+	GET_MAX_LUN_T =	RD2H | Rclass | Rinterface,
+	GET_MAX_LUN =	0xFE,
+	UMS_RESET_T =	RH2D | Rclass | Rinterface,
+	UMS_RESET =	0xFF,
+
+	MaxIOsize	= 256*1024,	/* max. I/O size */
+//	Maxlun		= 256,
+	Maxlun		= 32,
+};
+
+#define PATH(type, n)	((type) | (n)<<8)
+#define TYPE(path)	((uchar)(path))
+#define NUM(path)	((uint)(path)>>8)
+
+enum {
+	Qdir = 0,
+	Qctl,
+	Qn,
+	Qraw,
+	Qdata,
+
+	CMreset = 1,
+
+	Pcmd = 0,
+	Pdata,
+	Pstatus,
+};
+
+static char *subclass[] = {
+	"?",
+	"rbc",
+	"atapi",
+	"qic tape",
+	"ufi floppy",
+	"8070 removable",
+	"scsi transparent",
+	"isd200 ata",
+};
+
+typedef struct Dirtab Dirtab;
+struct Dirtab {
+	char	*name;
+	int	mode;
+};
+Dirtab dirtab[] = {
+	".",	DMDIR|0555,
+	"ctl",	0640,
+	nil,	DMDIR|0750,
+	"raw",	0640,
+	"data",	0640,
+};
+
+Cmdtab cmdtab[] = {
+	CMreset,	"reset",	1,
+};
+
+/* these are 600 bytes each; ScsiReq is not tiny */
+typedef struct Umsc Umsc;
+struct Umsc {
+	ScsiReq;
+	ulong	blocks;
+	vlong	capacity;
+	uchar 	rawcmd[10];
+	uchar	phase;
+	char	*inq;
+};
+
+typedef struct Ums Ums;
+struct Ums {
+	Umsc	*lun;
+	uchar	maxlun;
+	int	fd2;
+	int	fd;
+	int	setupfd;
+	int	ctlfd;
+	uchar	epin;
+	uchar	epout;
+	char	dev[64];
+};
+
+int exabyte, force6bytecmds;
+long starttime;
+long maxiosize = MaxIOsize;
+volatile int timedout;
+
+char *owner;
+
+static Ums ums;
+
+extern int debug;
+
+static void umsreset(Ums *umsc, int doinit);
+
+/*
+ * USB transparent SCSI devices
+ */
+typedef struct Cbw Cbw;			/* command block wrapper */
+struct Cbw {
+	char	signature[4];		/* "USBC" */
+	long	tag;
+	long	datalen;
+	uchar	flags;
+	uchar	lun;
+	uchar	len;
+	char	command[16];
+};
+
+typedef struct Csw Csw;			/* command status wrapper */
+struct Csw {
+	char	signature[4];		/* "USBS" */
+	long	tag;
+	long	dataresidue;
+	uchar	status;
+};
+
+enum {
+	CbwLen		= 31,
+	CbwDataIn	= 0x80,
+	CbwDataOut	= 0x00,
+	CswLen		= 13,
+	CswOk		= 0,
+	CswFailed	= 1,
+	CswPhaseErr	= 2,
+};
+
+void
+statuscmd(int fd, int type, int req, int value, int index, char *data,
+	int count)
+{
+	char *wp;
+
+	wp = emalloc9p(count + 8);
+	wp[0] = type;
+	wp[1] = req;
+	PUT2(wp + 2, value);
+	PUT2(wp + 4, index);
+	PUT2(wp + 6, count);
+	if(data != nil)
+		memmove(wp + 8, data, count);
+	if(write(fd, wp, count + 8) != count + 8)
+		sysfatal("statuscmd: %r");
+}
+
+void
+statusread(int fd, char *buf, int count)
+{
+	if(read(fd, buf, count) < 0)
+		sysfatal("statusread: %r");
+}
+
+void
+getmaxlun(Ums *ums)
+{
+	uchar max;
+
+	statuscmd(ums->setupfd, GET_MAX_LUN_T, GET_MAX_LUN, 0, 0, nil, 0);
+	statusread(ums->setupfd, (char *)&max, 1);
+	fprint(2, "%s: maxlun %d\n", argv0, max);		// DEBUG
+	ums->lun = mallocz((max + 1) * sizeof *ums->lun, 1);
+	assert(ums->lun);
+	ums->maxlun = max;
+}
+
+int
+umsinit(Ums *ums, int epin, int epout)
+{
+	uchar data[8], i;
+	char fin[128];
+	Umsc *lun;
+
+	if(ums->ctlfd == -1) {
+		snprint(fin, sizeof fin, "%s/ctl", ums->dev);
+		if((ums->ctlfd = open(fin, OWRITE)) == -1)
+			return -1;
+		if(epin == epout) {
+			if(fprint(ums->ctlfd, "ep %d bulk rw 64 16", epin) < 0)
+				return -1;
+		} else {
+			if(fprint(ums->ctlfd, "ep %d bulk r 64 16", epin) < 0 ||
+			   fprint(ums->ctlfd, "ep %d bulk w 64 16", epout) < 0)
+				return -1;
+		}
+		snprint(fin, sizeof fin, "%s/ep%ddata", ums->dev, epin);
+		if((ums->fd = open(fin, OREAD)) == -1)
+			return -1;
+		snprint(fin, sizeof fin, "%s/ep%ddata", ums->dev, epout);
+		if((ums->fd2 = open(fin, OWRITE)) == -1)
+			return -1;
+		snprint(fin, sizeof fin, "%s/setup", ums->dev);
+		if ((ums->setupfd = open(fin, ORDWR)) == -1)
+			return -1;
+	}
+
+	ums->epin = epin;
+	ums->epout = epout;
+	umsreset(ums, 0);
+	getmaxlun(ums);
+	for(i = 0; i <= ums->maxlun; i++) {
+		lun = &ums->lun[i];
+		lun->lun = i;
+		lun->umsc = lun;			/* pointer to self */
+		lun->flags = Fopen | Fusb | Frw10;
+		if(SRinquiry(lun) == -1)
+			return -1;
+		lun->inq = smprint("%.48s", (char *)lun->inquiry+8);
+		SRstart(lun, 1);
+		if (SRrcapacity(lun, data) == -1 &&
+		    SRrcapacity(lun, data) == -1) {
+			lun->blocks = 0;
+			lun->capacity = 0;
+			lun->lbsize = 0;
+		} else {
+			lun->lbsize = data[4]<<24|data[5]<<16|data[6]<<8|data[7];
+			lun->blocks = data[0]<<24|data[1]<<16|data[2]<<8|data[3];
+			lun->blocks++; /* SRcapacity returns LBA of last block */
+			lun->capacity = (vlong)lun->blocks * lun->lbsize;
+		}
+	}
+	return 0;
+}
+
+static void
+unstall(Ums *ums, int ep)
+{
+	if(fprint(ums->ctlfd, "unstall %d", ep & 0xF) < 0)
+		fprint(2, "ctl write failed\n");
+	if(fprint(ums->ctlfd, "data %d 0", ep & 0xF) < 0)
+		fprint(2, "ctl write failed\n");
+
+	statuscmd(ums->setupfd, RH2D | Rstandard | Rendpt, CLEAR_FEATURE, 0,
+		0<<8 | ep, nil, 0);
+}
+
+static void
+umsreset(Ums *umsc, int doinit)
+{
+	statuscmd(umsc->setupfd, UMS_RESET_T, UMS_RESET, 0, 0, nil, 0);
+
+	unstall(umsc, umsc->epin|0x80);
+	unstall(umsc, umsc->epout);
+	if(doinit && umsinit(&ums, umsc->epin, umsc->epout) < 0)
+		sysfatal("device error");
+}
+
+long
+umsrequest(Umsc *umsc, ScsiPtr *cmd, ScsiPtr *data, int *status)
+{
+	Cbw cbw;
+	Csw csw;
+	int n;
+	static int seq = 0;
+
+	memcpy(cbw.signature, "USBC", 4);
+	cbw.tag = ++seq;
+	cbw.datalen = data->count;
+	cbw.flags = data->write? CbwDataOut: CbwDataIn;
+	cbw.lun = umsc->lun;
+	cbw.len = cmd->count;
+	memcpy(cbw.command, cmd->p, cmd->count);
+	memset(cbw.command + cmd->count, 0, sizeof(cbw.command) - cmd->count);
+
+	if(debug) {
+		fprint(2, "cmd:");
+		for (n = 0; n < cbw.len; n++)
+			fprint(2, " %2.2x", cbw.command[n]&0xFF);
+		fprint(2, " datalen: %ld\n", cbw.datalen);
+	}
+	if(write(ums.fd2, &cbw, CbwLen) != CbwLen){
+		fprint(2, "usbscsi: write cmd: %r\n");
+		goto reset;
+	}
+	if(data->count != 0) {
+		if(data->write)
+			n = write(ums.fd2, data->p, data->count);
+		else
+			n = read(ums.fd, data->p, data->count);
+		if(n == -1){
+			if(debug)
+				fprint(2, "usbscsi: data %sput: %r\n",
+					data->write? "out": "in");
+			if(data->write)
+				unstall(&ums, ums.epout);
+			else
+				unstall(&ums, ums.epin | 0x80);
+		}
+	}
+	n = read(ums.fd, &csw, CswLen);
+	if(n == -1){
+		unstall(&ums, ums.epin | 0x80);
+		n = read(ums.fd, &csw, CswLen);
+	}
+	if(n != CswLen || strncmp(csw.signature, "USBS", 4) != 0){
+		fprint(2, "usbscsi: read status: %r\n");
+		goto reset;
+	}
+	if(csw.tag != cbw.tag) {
+		fprint(2, "usbscsi: status tag mismatch\n");
+		goto reset;
+	}
+	if(csw.status >= CswPhaseErr){
+		fprint(2, "usbscsi: phase error\n");
+		goto reset;
+	}
+	if(debug) {
+		fprint(2, "status: %2.2ux residue: %ld\n",
+			csw.status, csw.dataresidue);
+		if(cbw.command[0] == ScmdRsense) {
+			fprint(2, "sense data:");
+			for (n = 0; n < data->count - csw.dataresidue; n++)
+				fprint(2, " %2.2x", data->p[n]);
+			fprint(2, "\n");
+		}
+	}
+
+	if(csw.status == CswOk)
+		*status = STok;
+	else
+		*status = STcheck;
+	return data->count - csw.dataresidue;
+
+reset:
+	umsreset(&ums, 0);
+	*status = STharderr;
+	return -1;
+}
+
+int
+findendpoints(Device *d, int *epin, int *epout)
+{
+	Endpt *ep;
+	ulong csp;
+	int i, addr, nendpt;
+
+	*epin = *epout = -1;
+	nendpt = 0;
+	if(d->nconf < 1)
+		return -1;
+	for(i=0; i<d->nconf; i++) {
+		if (d->config[i] == nil)
+			d->config[i] = mallocz(sizeof(*d->config[i]),1);
+		loadconfig(d, i);
+	}
+	for(i = 0; i < Nendpt; i++){
+		if((ep = d->ep[i]) == nil)
+			continue;
+		nendpt++;
+		csp = ep->csp;
+		if(!(Class(csp) == CL_STORAGE && (Proto(csp) == 0x50)))
+			continue;
+		if(ep->type == Ebulk) {
+			addr = ep->addr;
+			if (debug)
+				print("findendpoints: bulk; ep->addr %ux\n",
+					ep->addr);
+			if (ep->dir == Eboth || addr&0x80)
+				if(*epin == -1)
+					*epin =  addr&0xF;
+			if (ep->dir == Eboth || !(addr&0x80))
+				if(*epout == -1)
+					*epout = addr&0xF;
+		}
+	}
+	if(nendpt == 0) {
+		if(*epin == -1)
+			*epin = *epout;
+		if(*epout == -1)
+			*epout = *epin;
+	}
+	if (*epin == -1 || *epout == -1)
+		return -1;
+	return 0;
+}
+
+int
+timeoutok(void)
+{
+	if (0 /* freakout */)
+		return 1;	/* OK; keep trying */
+	else if (1) {		/* TODO: set */
+		fprint(2,
+"%s: no response from device.  unplug and replug it and try again with -f\n",
+			argv0);
+
+		return 0;	/* die */
+	}
+	return 1;		/* keep trying */
+}
+
+int
+notifyf(void *, char *s)
+{
+	if(strcmp(s, "alarm") != 0)
+		return 0;		/* die */
+	if (!timeoutok()) {
+		fprint(2, "%s: timed out\n", argv0);
+		return 0;		/* die */
+	}
+	alarm(120*1000);
+	fprint(2, "%s: resetting alarm\n", argv0);
+	timedout = 1;
+	return 1;			/* keep going */
+}
+
+int
+devokay(int ctlrno, int id)
+{
+	int epin = -1, epout = -1;
+	long time;
+	Device *d;
+	static int beenhere;
+
+	if (!beenhere) {
+		atnotify(notifyf, 1);
+		beenhere = 1;
+	}
+	time = alarm(15*1000);
+	d = opendev(ctlrno, id);
+	if (describedevice(d) < 0) {
+		perror("");
+		closedev(d);
+		alarm(time);
+		return 0;
+	}
+	if (findendpoints(d, &epin, &epout) < 0) {
+		fprint(2, "%s: bad usb configuration for ctlr %d id %d\n",
+			argv0, ctlrno, id);
+		closedev(d);
+		alarm(time);
+		return 0;
+	}
+	closedev(d);
+
+	snprint(ums.dev, sizeof ums.dev, "/dev/usb%d/%d", ctlrno, id);
+	if (umsinit(&ums, epin, epout) < 0) {
+		alarm(time);
+		fprint(2, "%s: initialisation: %r\n", argv0);
+		return 0;
+	}
+	alarm(time);
+	return 1;
+}
+
+static char *
+subclname(int subcl)
+{
+	if ((unsigned)subcl < nelem(subclass))
+		return subclass[subcl];
+	return "**GOK**";		/* traditional */
+}
+
+static int
+scanstatus(int ctlrno, int id)
+{
+	int winner;
+	ulong csp;
+	char *p, *hex;
+	char buf[64];
+	Biobuf *f;
+
+	/* read port status file */
+	sprint(buf, "/dev/usb%d/%d/status", ctlrno, id);
+	f = Bopen(buf, OREAD);
+	if (f == nil)
+		sysfatal("can't open %s: %r", buf);
+	if (debug)
+		fprint(2, "\n%s: reading %s\n", argv0, buf);
+	winner = 0;
+	while (!winner && (p = Brdline(f, '\n')) != nil) {
+		p[Blinelen(f)-1] = '\0';
+		if (debug && *p == 'E')			/* Enabled? */
+			fprint(2, "%s: %s\n", argv0, p);
+		for (hex = p; *hex != '\0' && *hex != '0'; hex++)
+			continue;
+		csp = atol(hex);
+
+		if (Class(csp) == CL_STORAGE && Proto(csp) == Protobulk) {
+			if (0)
+				fprint(2,
+			"%s: /dev/usb%d/%d: bulk storage of subclass %s\n",
+					argv0, ctlrno, id,
+					subclname(Subclass(csp)));
+			switch (Subclass(csp)) {
+			case Subatapi:
+			case Sub8070:
+			case Subscsi:
+				winner++;
+				break;
+			}
+		}
+	}
+	Bterm(f);
+	return winner;
+}
+
+static int
+findums(int *ctlrp, int *idp)
+{
+	int ctlrno, id, winner, devfd, ctlrfd, nctlr, nport;
+	char buf[64];
+	Dir *ctlrs, *cdp, *ports, *pdp;
+
+	*ctlrp = *idp = -1;
+	winner = 0;
+
+	/* walk controllers */
+	devfd = open("/dev", OREAD);
+	if (devfd < 0)
+		sysfatal("can't open /dev: %r");
+	nctlr = dirreadall(devfd, &ctlrs);
+	if (nctlr < 0)
+		sysfatal("can't read /dev: %r");
+	for (cdp = ctlrs; nctlr-- > 0 && !winner; cdp++) {
+		if (strncmp(cdp->name, "usb", 3) != 0)
+			continue;
+		ctlrno = atoi(cdp->name + 3);
+
+		/* walk ports within a controller */
+		snprint(buf, sizeof buf, "/dev/%s", cdp->name);
+		ctlrfd = open(buf, OREAD);
+		if (ctlrfd < 0)
+			sysfatal("can't open %s: %r", buf);
+		nport = dirreadall(ctlrfd, &ports);
+		if (nport < 0)
+			sysfatal("can't read %s: %r", buf);
+		for (pdp = ports; nport-- > 0 && !winner; pdp++) {
+			if (!isdigit(*pdp->name))
+				continue;
+			id = atoi(pdp->name);
+
+			/* read port status file */
+			winner = scanstatus(ctlrno, id);
+			if (winner)
+				if (devokay(ctlrno, id)) {
+					*ctlrp = ctlrno;
+					*idp = id;
+				} else
+					winner = 0;
+		}
+		free(ports);
+		close(ctlrfd);
+	}
+	free(ctlrs);
+	close(devfd);
+	if (!winner)
+		return -1;
+	else
+		return 0;
+}
+
+void
+rattach(Req *r)
+{
+	r->ofcall.qid.path = PATH(Qdir, 0);
+	r->ofcall.qid.type = dirtab[Qdir].mode >> 24;
+	r->fid->qid = r->ofcall.qid;
+	respond(r, nil);
+}
+
+char*
+rwalk1(Fid *fid, char *name, Qid *qid)
+{
+	int i, n;
+	char buf[32];
+	ulong path;
+
+	path = fid->qid.path;
+	if(!(fid->qid.type & QTDIR))
+		return "walk in non-directory";
+
+	if(strcmp(name, "..") == 0)
+		switch(TYPE(path)) {
+		case Qn:
+			qid->path = PATH(Qn, NUM(path));
+			qid->type = dirtab[Qn].mode >> 24;
+			return nil;
+		case Qdir:
+			return nil;
+		default:
+			return "bug in rwalk1";
+		}
+
+	for(i = TYPE(path)+1; i < nelem(dirtab); i++) {
+		if(i==Qn){
+			n = atoi(name);
+			snprint(buf, sizeof buf, "%d", n);
+			if(n <= ums.maxlun && strcmp(buf, name) == 0){
+				qid->path = PATH(i, n);
+				qid->type = dirtab[i].mode>>24;
+				return nil;
+			}
+			break;
+		}
+		if(strcmp(name, dirtab[i].name) == 0) {
+			qid->path = PATH(i, NUM(path));
+			qid->type = dirtab[i].mode >> 24;
+			return nil;
+		}
+		if(dirtab[i].mode & DMDIR)
+			break;
+	}
+	return "directory entry not found";
+}
+
+void
+dostat(int path, Dir *d)
+{
+	Dirtab *t;
+
+	memset(d, 0, sizeof(*d));
+	d->uid = estrdup9p(owner);
+	d->gid = estrdup9p(owner);
+	d->qid.path = path;
+	d->atime = d->mtime = starttime;
+	t = &dirtab[TYPE(path)];
+	if(t->name)
+		d->name = estrdup9p(t->name);
+	else {
+		d->name = smprint("%ud", NUM(path));
+		if(d->name == nil)
+			sysfatal("out of memory");
+	}
+	if(TYPE(path) == Qdata)
+		d->length = ums.lun[NUM(path)].capacity;
+	d->qid.type = t->mode >> 24;
+	d->mode = t->mode;
+}
+
+static int
+dirgen(int i, Dir *d, void*)
+{
+	i += Qdir + 1;
+	if(i <= Qn) {
+		dostat(i, d);
+		return 0;
+	}
+	i -= Qn;
+	if(i <= ums.maxlun) {
+		dostat(PATH(Qn, i), d);
+		return 0;
+	}
+	return -1;
+}
+
+static int
+lungen(int i, Dir *d, void *aux)
+{
+	int *c;
+
+	c = aux;
+	i += Qn + 1;
+	if(i <= Qdata){
+		dostat(PATH(i, NUM(*c)), d);
+		return 0;
+	}
+	return -1;
+}
+
+void
+rstat(Req *r)
+{
+	dostat((long)r->fid->qid.path, &r->d);
+	respond(r, nil);
+}
+
+void
+ropen(Req *r)
+{
+	ulong path;
+
+	path = r->fid->qid.path;
+	switch(TYPE(path)) {
+	case Qraw:
+		ums.lun[NUM(path)].phase = Pcmd;
+		break;
+	}
+	respond(r, nil);
+}
+
+void
+rread(Req *r)
+{
+	int bno, nb, len, offset, n;
+	ulong path;
+	uchar i;
+	char buf[8192], *p;
+	Umsc *lun;
+
+	path = r->fid->qid.path;
+	switch(TYPE(path)) {
+	case Qdir:
+		dirread9p(r, dirgen, 0);
+		break;
+	case Qn:
+		dirread9p(r, lungen, &path);
+		break;
+	case Qctl:
+		n = 0;
+		for(i = 0; i <= ums.maxlun; i++) {
+			lun = &ums.lun[i];
+			n += snprint(buf + n, sizeof buf - n, "%d: ", i);
+			if(lun->flags & Finqok)
+				n += snprint(buf + n, sizeof buf - n,
+					"inquiry %s ", lun->inq);
+			if(lun->blocks > 0)
+				n += snprint(buf + n, sizeof buf - n,
+					"geometry %ld %ld", lun->blocks,
+					lun->lbsize);
+			n += snprint(buf + n, sizeof buf - n, "\n");
+		}
+		readbuf(r, buf, n);
+		break;
+	case Qraw:
+		lun = &ums.lun[NUM(path)];
+		if(lun->lbsize <= 0) {
+			respond(r, "no media on this lun");
+			return;
+		}
+		switch(lun->phase) {
+		case Pcmd:
+			respond(r, "phase error");
+			return;
+		case Pdata:
+			lun->data.p = (uchar*)r->ofcall.data;
+			lun->data.count = r->ifcall.count;
+			lun->data.write = 0;
+			n = umsrequest(lun, &lun->cmd, &lun->data, &lun->status);
+			lun->phase = Pstatus;
+			if (n == -1) {
+				respond(r, "IO error");
+				return;
+			}
+			r->ofcall.count = n;
+			break;
+		case Pstatus:
+			n = snprint(buf, sizeof buf, "%11.0ud ", lun->status);
+			if (r->ifcall.count < n)
+				n = r->ifcall.count;
+			memmove(r->ofcall.data, buf, n);
+			r->ofcall.count = n;
+			lun->phase = Pcmd;
+			break;
+		}
+		break;
+	case Qdata:
+		lun = &ums.lun[NUM(path)];
+		if(lun->lbsize <= 0) {
+			respond(r, "no media on this lun");
+			return;
+		}
+		bno = r->ifcall.offset / lun->lbsize;
+		nb = (r->ifcall.offset + r->ifcall.count + lun->lbsize - 1)
+			/ lun->lbsize - bno;
+		if(bno + nb > lun->blocks)
+			nb = lun->blocks - bno;
+		if(bno >= lun->blocks || nb == 0) {
+			r->ofcall.count = 0;
+			break;
+		}
+		if(nb * lun->lbsize > maxiosize)
+			nb = maxiosize / lun->lbsize;
+		p = malloc(nb * lun->lbsize);
+		if (p == 0) {
+			respond(r, "no mem");
+			return;
+		}
+		lun->offset = r->ifcall.offset / lun->lbsize;
+		n = SRread(lun, p, nb * lun->lbsize);
+		if(n == -1) {
+			free(p);
+			respond(r, "IO error");
+			return;
+		}
+		len = r->ifcall.count;
+		offset = r->ifcall.offset % lun->lbsize;
+		if(offset + len > n)
+			len = n - offset;
+		r->ofcall.count = len;
+		memmove(r->ofcall.data, p + offset, len);
+		free(p);
+		break;
+	}
+	respond(r, nil);
+}
+
+void
+rwrite(Req *r)
+{
+	int n, bno, nb, len, offset;
+	ulong path;
+	char *p;
+	Cmdbuf *cb;
+	Cmdtab *ct;
+	Umsc *lun;
+
+	n = r->ifcall.count;
+	r->ofcall.count = 0;
+	path = r->fid->qid.path;
+	switch(TYPE(path)) {
+	case Qctl:
+		cb = parsecmd(r->ifcall.data, n);
+		ct = lookupcmd(cb, cmdtab, nelem(cmdtab));
+		if(ct == 0) {
+			respondcmderror(r, cb, "%r");
+			return;
+		}
+		switch(ct->index) {
+		case CMreset:
+			umsreset(&ums, 1);
+		}
+		break;
+	case Qraw:
+		lun = &ums.lun[NUM(path)];
+		if(lun->lbsize <= 0) {
+			respond(r, "no media on this lun");
+			return;
+		}
+		n = r->ifcall.count;
+		switch(lun->phase) {
+		case Pcmd:
+			if(n != 6 && n != 10) {
+				respond(r, "bad command length");
+				return;
+			}
+			memmove(lun->rawcmd, r->ifcall.data, n);
+			lun->cmd.p = lun->rawcmd;
+			lun->cmd.count = n;
+			lun->cmd.write = 1;
+			lun->phase = Pdata;
+			break;
+		case Pdata:
+			lun->data.p = (uchar*)r->ifcall.data;
+			lun->data.count = n;
+			lun->data.write = 1;
+			n = umsrequest(lun, &lun->cmd, &lun->data, &lun->status);
+			lun->phase = Pstatus;
+			if(n == -1) {
+				respond(r, "IO error");
+				return;
+			}
+			break;
+		case Pstatus:
+			lun->phase = Pcmd;
+			respond(r, "phase error");
+			return;
+		}
+		break;
+	case Qdata:
+		lun = &ums.lun[NUM(path)];
+		if(lun->lbsize <= 0) {
+			respond(r, "no media on this lun");
+			return;
+		}
+		bno = r->ifcall.offset / lun->lbsize;
+		nb = (r->ifcall.offset + r->ifcall.count + lun->lbsize-1)
+			/ lun->lbsize - bno;
+		if(bno + nb > lun->blocks)
+			nb = lun->blocks - bno;
+		if(bno >= lun->blocks || nb == 0) {
+			r->ofcall.count = 0;
+			break;
+		}
+		if(nb * lun->lbsize > maxiosize)
+			nb = maxiosize / lun->lbsize;
+		p = malloc(nb * lun->lbsize);
+		if(p == 0) {
+			respond(r, "no mem");
+			return;
+		}
+		offset = r->ifcall.offset % lun->lbsize;
+		len = r->ifcall.count;
+		if(offset || (len % lun->lbsize) != 0) {
+			lun->offset = r->ifcall.offset / lun->lbsize;
+			n = SRread(lun, p, nb * lun->lbsize);
+			if(n == -1) {
+				free(p);
+				respond(r, "IO error");
+				return;
+			}
+			if(offset + len > n)
+				len = n - offset;
+		}
+		memmove(p+offset, r->ifcall.data, len);
+		lun->offset = r->ifcall.offset / lun->lbsize;
+		n = SRwrite(lun, p, nb * lun->lbsize);
+		if(n == -1) {
+			free(p);
+			respond(r, "IO error");
+			return;
+		}
+		if(offset+len > n)
+			len = n - offset;
+		r->ofcall.count = len;
+		free(p);
+		break;
+	}
+	r->ofcall.count = n;
+	respond(r, nil);
+}
+
+Srv usbssrv = {
+	.attach = rattach,
+	.walk1 = rwalk1,
+	.open =	 ropen,
+	.read =	 rread,
+	.write = rwrite,
+	.stat =	 rstat,
+};
+
+void (*dprinter[])(Device *, int, ulong, void *b, int n) = {
+	[STRING] pstring,
+	[DEVICE] pdevice,
+};
+
+void
+usage(void)
+{
+	fprint(2, "usage: %s [-Dd] [-m mountpoint] [-s srvname] [ctrno id]\n",
+		argv0);
+	exits("usage");
+}
+
+void
+main(int argc, char **argv)
+{
+	int ctlrno, id;
+	char *srvname, *mntname;
+
+	mntname = "/n/disk";
+	srvname = nil;
+	ctlrno = 0;
+	id = 1;
+
+	ARGBEGIN{
+	case 'd':
+		debug = Dbginfo;
+		break;
+	case 'm':
+		mntname = EARGF(usage());
+		break;
+	case 's':
+		srvname = EARGF(usage());
+		break;
+	case 'D':
+		++chatty9p;
+		break;
+	default:
+		usage();
+	}ARGEND
+
+	ums.ctlfd = ums.setupfd = ums.fd = ums.fd2 = -1;
+	ums.maxlun = -1;
+	if (argc == 0) {
+		if (findums(&ctlrno, &id) < 0) {
+			sleep(5*1000);
+			if (findums(&ctlrno, &id) < 0)
+				sysfatal("no usb mass storage device found");
+		}
+	} else if (argc == 2 && isdigit(argv[0][0]) && isdigit(argv[1][0])) {
+		ctlrno = atoi(argv[0]);
+		id = atoi(argv[1]);
+		if (!devokay(ctlrno, id))
+			sysfatal("no usable usb mass storage device at %d/%d",
+				ctlrno, id);
+	} else
+		usage();
+
+	starttime = time(0);
+	owner = getuser();
+
+	postmountsrv(&usbssrv, srvname, mntname, 0);
+	exits(0);
+}

+ 21 - 0
sys/src/cmd/usb/disk/mkfile

@@ -0,0 +1,21 @@
+</$objtype/mkfile
+
+TARG=disk
+LIBDIR=../lib
+HFILES = /sys/src/cmd/scuzz/scsireq.h $LIBDIR/usb.h
+OFILES = disk.$O scsireq.$O
+LIB=$LIBDIR/usb.a$O
+
+BIN=/$objtype/bin/usb
+
+</sys/src/cmd/mkone
+
+CFLAGS=-I$LIBDIR -I/sys/src/cmd/scuzz $CFLAGS
+
+$LIB:
+	cd $LIBDIR
+	mk install
+	mk clean
+
+scsireq.$O: /sys/src/cmd/scuzz/scsireq.c
+	$CC $CFLAGS /sys/src/cmd/scuzz/scsireq.c

+ 1 - 0
sys/src/cmd/usb/mkfile

@@ -4,6 +4,7 @@ DIRS=\
 	lib\
 	usbd\
 	audio\
+	disk\
 	misc\
 
 UPDATE=\