git: 9front

Download patch

ref: dfc9837b715921492b93ab24d2acedf6e8b94f09
parent: 66e33b9e0fcbde17081bfb82135e06e61120a693
author: Sigrid Solveig Haflínudóttir <sigrid@ftrv.se>
date: Wed May 24 12:14:33 EDT 2023

sdnvme, fshalt: turn disks off on fshalt

MNT Reform's power rails are switched off abruptly on shutdown
which causes an "unsafe" shutdown on nvme. This may result in
loss of valid data in the volatile write cache, which is never
going to be synced in this case. This problem has been reported
on forums about Linux too, including actual filesystem errors
resulting from that behavior.

Notify nvme about a shutdown and wait up to 3s before disabling
the controller. This resulted in "unsafe shutdowns" nvme's counter
to never increase on fshalt.

--- a/rc/bin/fshalt
+++ b/rc/bin/fshalt
@@ -31,13 +31,14 @@
 
 c=`{ls /srv/cwfs*cmd >[2]/dev/null}
 h=`{ls /srv/hjfs*cmd >[2]/dev/null}
+s=`{awk '/^sd./ {print substr($1,3,1)}' <'#S/sdctl' >[2]/dev/null}
 
 # for scram, don't scram other systems
 bind -b '#P' /dev >[2]/dev/null
 if(! ~ $reboot yes){
-	if (test -e '#P'/apm)
+	if(test -e '#P'/apm)
 		scram=yes
-	if (test -e '#P'/acpitbls -a -e '#P'/iow)
+	if(test -e '#P'/acpitbls -a -e '#P'/iow)
 		scram=yes
 }
 
@@ -66,9 +67,9 @@
 fn x {
 	echo
 	echo -n halting...
-	for (i in $c $h)
+	for(i in $c $h)
 		echo halt >>$i
-	for (i in $c $h){
+	for(i in $c $h){
 		echo -n $i...
 		while(test -e $i)
 			sleep 1
@@ -76,15 +77,19 @@
 	echo
 	echo done halting
 
-	if (~ $reboot yes) {
+	# turn off disk drives
+	for(i in $s)
+		echo config spec $i switch off >>'#S/sdctl'
+
+	if(~ $reboot yes){
 		echo rebooting...
 		echo reboot $bootf >'#c/reboot'
 	}
-	if not if (test -e /dev/pmctl) {
-		echo power off >>/dev/pmctl
-	}
-	if (~ $scram yes){
-		scram
+	if not {
+		if (test -e /dev/pmctl)
+			echo power off >>/dev/pmctl
+		if (~ $scram yes)
+			scram
 		echo 'It''s now safe to turn off your computer'
 	}
 }
--- a/sys/src/9/port/sdnvme.c
+++ b/sys/src/9/port/sdnvme.c
@@ -208,9 +208,8 @@
 	SQ *sq = ws->queue;
 	Ctlr *ctlr = sq->ctlr;
 
-	if(e != nil) {
+	if(e != nil)
 		dmaflush(1, e, 64);
-	}
 	coherence();
 	ctlr->reg[DBell + ((sq-ctlr->sq)*2+0 << ctlr->dstrd)] = sq->tail & sq->mask;
 	if(sq > ctlr->sq) {
@@ -270,9 +269,8 @@
 		count -= n;
 		lba += n;
 	}
-	if(!write) {
+	if(!write)
 		dmaflush(0, a, p - (uchar*)a);
-	}
 	return p - (uchar*)a;
 }
 
@@ -521,9 +519,16 @@
 	ctlr->reg[IntMs] = ~ctlr->ints;
 	iunlock(&ctlr->intr);
 
+	/* notify normal power off */
+	ctlr->reg[CCfg] = (ctlr->reg[CCfg] & ~(3<<14)) | 1<<14;
+	for(i = 0; i < 30; i++){
+		if((ctlr->reg[CSts] & 0xc) == 0x8)
+			break;
+		tsleep(&up->sleep, return0, nil, 100);
+	}
+
 	/* disable controller */
 	ctlr->reg[CCfg] = 0;
-
 	for(i = 0; i < 10; i++){
 		if((ctlr->reg[CSts] & 1) == 0)
 			break;
--