[movitz-cvs] CVS update: movitz/losp/tmp/harddisk.lisp

Frode Vatvedt Fjeld ffjeld at common-lisp.net
Sat Apr 24 15:13:27 UTC 2004


Update of /project/movitz/cvsroot/movitz/losp/tmp
In directory common-lisp.net:/tmp/cvs-serv21555

Modified Files:
	harddisk.lisp 
Log Message:
Checked in new version from Peter Minten.

Date: Sat Apr 24 11:13:27 2004
Author: ffjeld

Index: movitz/losp/tmp/harddisk.lisp
diff -u movitz/losp/tmp/harddisk.lisp:1.1 movitz/losp/tmp/harddisk.lisp:1.2
--- movitz/losp/tmp/harddisk.lisp:1.1	Mon Apr 19 18:55:55 2004
+++ movitz/losp/tmp/harddisk.lisp	Sat Apr 24 11:13:26 2004
@@ -1,10 +1,23 @@
-;;;; $Id: harddisk.lisp,v 1.1 2004/04/19 22:55:55 ffjeld Exp $
+;;;; $Id: harddisk.lisp,v 1.2 2004/04/24 15:13:26 ffjeld Exp $
 
 (require :lib/named-integers)
+(provide :tmp/harddisk)
 
-(provide :x86-pc/harddisk)
+(defpackage muerte.x86-pc.harddisk
+  (:use muerte.cl muerte muerte.lib muerte.x86-pc)
+  (:export make-512-vector
+           hd-read-sectors
+           hd-write-sectors
+           hd-commands
+	   ))
 
-(in-package muerte.x86-pc)
+(in-package muerte.x86-pc.harddisk)
+
+;;;
+;;; global variables
+;;;
+(defvar *hd-controllers* (vector (make-instance 'hd-controller))
+  "A vector of harddisk controllers.")
 
 ;;;
 ;;; constants
@@ -16,53 +29,8 @@
 (defconstant +hd-default-first-control-base+ #x3F6)
 (defconstant +hd-default-second-control-base+ #x376)
 
-;;;
-;;; structures
-;;;
-
-(defstruct hd-controller             
-  (number 0 :type integer)              ;for error messages
-  (command-base +hd-default-first-command-base+ :type (integer 0 *))
-  (control-base +hd-default-first-control-base+ :type (integer 0 *))
-  (active-hd 0 :type hd)                ;hd with pending task
-  (master nil :type hd)
-  (slave nil :type hd))
-
-(defstruct hd
-  ;; hd info
-  (place 0 :type bit)                   ;0=master,1=slave
-  (cylinders 0 :type (integer 0 *))
-  (heads 0 :type (integer 0 *))
-  (spt 0 :type (integer 0 *))
-  (sector-1-lba 0 :type (integer 0 *))
-  ;; task stuff
-  (tasks (make-hash-table) :type hash-table)
-  (pending-tasks '() :type list)
-  (pending-last-cons '() :type cons)    ;speeds append up
-  (active-task nil :type hd-task)
-  (done-tasks '() :type list))
-
-(deftype hd-data-vector ()
-  '(vector (unsigned-byte 8)))
-
-(defstruct hd-read-sectors-task
-  (start-sector 0 :type (unsigned-byte 28))
-  (count 1 :type (integer 1 256))
-  (data #() :type data-vector)
-  (offset 0 :type (integer 0 *)))
-
-(defstruct hd-write-sectors-task
-  (start-sector 0 :type (unsigned-byte 28))
-  (count 1 :type (integer 1 256))
-  (data #() :type data-vector)
-  (offset 0 :type (integer 0 *)))
-
-;;;
-;;; low level code
-;;;
-
 (define-named-integer hd-register-offset 
-    (:only-constants t :export-constants t)
+    (:only-constants t)
   (0 data)
   (1 error)                            
   (1 features)
@@ -75,16 +43,12 @@
   (7 command))
 
 (define-named-integer hd-commands
-    (:only-constants t :export-constants t)
+    (:only-constants t)
   (#x20 read-sectors-with-retry)
   (#x30 write-sectors-with-retry))
 
-(defun hd-controller-command-register (hdc name type)
-  (+ (named-integer 'hd-register-offset name)
-     (hd-controller-command-base hdc)))
-
 (define-named-integer hd-status-bits
-    (:only-constants t :export-constants t)
+    (:only-constants t)
   (0 error)
   (1 index)
   (2 corrected-data)
@@ -94,130 +58,49 @@
   (6 drive-ready)
   (7 busy))
 
-(defun hd-controller-busy (hdc)
-  ;; use control base, not command base, to avoid side effects
-  (/= 0 (logand (io-port (hd-controller-control-base hdc)
-                         :unsigned-byte8)
-                #x80)))
-
-(defun hd-controller-wait-for-ready (hdc)    ;wait for BSY=0
-  (do () ((not (hd-controller-busy))) ()))
-
-(defun hd-controller-status (hdc code)
-  (named-integer 'hd-status-bits code))
-
-(defmacro define-hd-controller-interrupt-handler (hdc irq)
-  (let ((name (gensym "hdc-irq-handler-")))
-    `(progn
-      (defun ,name (number int-frame)
-        (declare (ignore (number int-frame)))
-        (let ((hdc ,hdc))
-          (if (hd-controller-handle-task-signal hdc)
-            (hd-controller-queue-next-task hdc))))
-      (setf (interrupt-handler ,irq) ,name))))
-
-(defgeneric hd-controller-handle-task-signal (hdc task))
-
-(defmethod hd-controller-handle-task-signal :before (hdc task)
-  (hd-controller-wait-for-ready hdc))   ;just in case
-
-(defmethod hd-controller-handle-task-signal (hdc (task hd-read-sectors-task))
-  (with-slots (count data offset) task
-    (let ((status (io-port (hd-controller-command-register hdc 'status)
-                           :unsigned-byte8))
-          (read-data (io-port (hd-controller-command-register hdc 'status)
-                              :unsigned-byte16)))
-      ;; by now the drive is getting the next piece, if necessary,
-      ;; so I hope this code is reentrant
-      (if (= 0 (logand (power 2 (hd-controller-status 'error))
-                       status))
-        (progn 
-          ;; read 512 bytes
-          (dotimes (i 256)
-            (setf (aref data offset) (logand read-data #xFF))
-            (setf (aref data (1+ offset)) (logand read-data #xFF00))              
-            (incf offset 2))
-          (= offset (1- (* count 512)))) ;return value, are we done or not?
-        (error "Harddrive read-sectors returned error. Controller nr ~A, HD number:
-~A, error register: ~A." 
-               (hd-controller-number hdc)
-               (hd-controller-active-hd hdc)
-               (io-port (hd-controller-command-register hdc 'error)
-                        :unsigned-byte8))))))
-
-(defmethod hd-controller-handle-task-signal (hdc (task hd-write-sectors-task))
-  (with-slots (count data offset) task
-    (let ((status (io-port (hd-controller-command-register hdc 'status)
-                           :unsigned-byte8))
-          (write-data nil))
-      (if (= 0 (logand (power 2 (hd-controller-status 'error))
-                       status))
-        (if (= 0 (logand (power 2 (hd-controller-status 'data-request))
-                       status))
-          ;; write 512 bytes
-          (progn
-            (dotimes (i 256)
-              ;; hope the byte order is correct
-              (setf write-data (aref data offset))
-              (incf write-data (* #xFF (aref data (1+ offset))))
-              (incf offset 2)
-              (setf (io-port (hd-controller-command-register hdc 'data)
-                             :unsigned-byte16)
-                      write-data))
-            nil)                        ;not done yet
-          t)                            ;no data requested, so done
-        (error "Harddrive read-sectors returned error. Controller nr ~A, HD number:
-~A, error register: ~A." 
-               (hd-controller-number hdc)
-               (hd-controller-active-hd hdc)
-               (io-port (hd-controller-command-register hdc 'error)
-                        :unsigned-byte8))))))
-
-
-(defmethod hd-controller-feed-task :before (hdc task)
-  (hd-controller-wait-for-ready hdc)
-  ;; we always use LBA mode
+;;;
+;;; classes
+;;;
+(defclass hd-controller ()
+  ((command-base :initform +hd-default-first-command-base+
+                 :initarg :command-base
+                 :type integer)
+   (control-base :initform +hd-default-first-control-base+
+                 :initarg :command-base
+                 :type integer)))
+
+;;;
+;;; waiters
+;;;
+(defun hd-controller-wait-for-drive-ready (hdc) ;wait for DRDY=1
+  (with-slots (control-base) hdc
+    (loop until (/= 0 (logand (io-port control-base :unsigned-byte8)
+                              #x40)))))  
+
+(defun hd-controller-wait-for-ready (hdc) ;wait for BSY=0
+  (with-slots (control-base) hdc
+    (loop until (= 0 (logand (io-port control-base :unsigned-byte8)
+                             #x80)))))
+
+(defun hd-controller-wait-for-data-request (hdc) ;wait for DRQ=1
+  (with-slots (control-base) hdc
+    (loop until (/= 0 (logand (io-port control-base :unsigned-byte8)
+                              #x08)))))
+
+;;;
+;;; feeders
+;;;
+(defun hd-controller-feed-lba-mode (hdc)
   (setf (io-port (hd-controller-command-register hdc 'lba-byte-4)
                  :unsigned-byte8)
           (logior (io-port (hd-controller-command-register hdc 'lba-byte-4)
                            :unsigned-byte8)
                   #b01000000)))
 
-(defmethod hd-controller-feed-task (hdc (task hd-read-sectors-task))
-  (with-slots (drive count start-sector) task
-    ;; set drive
-    (hd-controller-feed-drive hdc drive)
-    ;; set count
-    (setf (io-port (hd-controller-command-register hdc 'sector-count)
-                   :unsigned-byte8)
-            count)
-    ;; set address
-    (hd-controller-feed-lba-address start-sector)
-    ;; get going
-    (setf (io-port (hd-controller-command-register hdc 'command)
-                   :unsigned-byte8)
-            (named-integer 'hd-commands 'read-sectors-with-retry))))
-
-(defmethod hd-controller-feed-task (hdc (task hd-write-sectors-task))
-  (with-slots (count start-sector offset data) task
-    ;; set drive
-    (hd-controller-feed-drive hdc)
-    ;; set count
-    (setf (io-port (hd-controller-command-register hdc 'sector-count)
-                   :unsigned-byte8)
-            count)
-    ;; set address
-    (hd-controller-feed-lba-address start-sector)
-    ;; get going
-    (setf (io-port (hd-controller-command-register hdc 'command)
-                   :unsigned-byte8)
-            (named-integer 'hd-commands 'read-sectors-with-retry))))
-  
-
-(defun hd-controller-feed-drive (hdc)
+(defun hd-controller-feed-drive (hdc drive)
   (setf (io-port (hd-controller-command-register hdc 'lba-byte-4)
                  :unsigned-byte8)
-          (logior (* #b00010000 (hd-controller-active-hd hdc))
+          (logior (* #b00010000 drive)
                   (logand (io-port (hd-controller-command-register hdc 'lba-byte-4)
                                    :unsigned-byte8)
                           #b11101111))))
@@ -239,43 +122,143 @@
                   (logand lba #x000F0000))))
 
 ;;;
-;;; scheduler code
+;;; misc
+;;;
+(defmacro while (test &body body)
+  `(do () ((not ,test))
+    , at body))
+
+(defun div (a b)
+  "Floored integer division, the painful way."
+  (let ((r 0)
+        (x a))
+    (while (>= x 0)
+      (decf x b)
+      (incf r))
+    (1- r)))
+
+(defun log2 (n)
+  (cond ((= n 256) 8)
+        ((= n 128) 7)
+        ((= n 64) 6)
+        ((= n 32) 5)
+        ((= n 16) 4)
+        ((= n 8) 3)
+        ((= n 4) 2)
+        ((= n 2) 1)
+        ((= n 1) 0)))
+        
+(defmacro with-hd-info ((hdc drive-number) hd-number &body body)
+  (let ((gs-hdnr (gensym "hd-number-")))
+    `(let* ((,gs-hdnr ,hd-number)
+            (,hdc (aref *hd-controllers* (div ,hd-number 2)))
+            (,drive-number (mod ,gs-hdnr 2)))
+      , at body)))
+
+(defun hd-controller-command-register (hdc name)
+  ;; use a case statement for now, until I learn how to use
+  ;; named-integer right
+  (+ (case name
+       ('data 0)
+       ('error 1)
+       ('features 1)
+       ('sector-count 2)
+       ('lba-byte-1 3)
+       ('lba-byte-2 4)
+       ('lba-byte-3 5)
+       ('lba-byte-4 6)
+       ('status 7)
+       ('command 7)
+       (else (error "HD command register not found ~A" name)))
+     (slot-value hdc 'command-base)))
+
+(defun error-code-meaning (code)
+  (nth (log2 code)
+       '("Address Mark Not Found"
+         "Track 0 Not Found"
+         "Media Change Requested"
+         "Aborted Command"
+         "ID Not Found"
+         "Media Changed"
+         "Uncorrectable Data Error"
+         "Bad Block Detected")))
+    
+    
+(defun hd-check-error (hdc command-name hdnr)
+  "Check and when found signal an error in task."
+  (when (/= 0 (logand (io-port (slot-value hdc 'control-base)
+                               :unsigned-byte8)
+                      #x01))
+    (error "Harddrive command ~A returned error. HD number: ~A. Error message: '~A'." 
+           command-name hdnr 
+           (error-code-meaning 
+            (io-port (hd-controller-command-register hdc 'error)
+                     :unsigned-byte8)))))
+
+;;;
+;;; hd operations
 ;;;
-(defun hd-queue-next-task (hdc)
-  ;; very dumb scheduler, FIFO and master before slave
-  (labels ((queue (hd)
-             (let ((task (first (hd-pending-tasks hd))))
-               (setf (hd-active-task hd) task)
-               (unless (rest (hd-pending-tasks hd))
-                 (setf (hd-pending-last-cons hd)
-                         (hd-pending-tasks hd)))
-               (hd-controller-feed-task hdc task))))
-    (let ((master (hd-controller-master hdc))
-          (slave (hd-controller-slave hdc)))
-      (cond ((> 0 (length (hd-pending-tasks master)))
-              (queue master)
-              (setf (hd-controller-active-hd hdc) 0))
-            ((> 0 (length (hd-pending-tasks slave)))
-              (queue slave)
-              (setf (hd-controller-active-hd hdc) 1))))))
-
-
-(defun hd-add-read-sectors-task (hd start-sector count)
-  "Add a task to read count sectors, starting at start-sector. Count
-must be between 1 and 256 inclusive."
-  (let* ((task (make-hd-read-sectors-task :start-sector start-sector
-                                          :count (mod (count 256))))
-                         
-         (pending-cons (cons task nil)))
-    (rplacd (hd-pending-last-cons hd) pending-cons)
-    (setf (hd-pending-last-cons hd) pending-cons)))
-
-(defun hd-add-write-sectors-task (hd start-sector count data)
-  "Add a task to write count sectors of data, starting at
-start-sector. Count must be between 1 and 256 inclusive."
-  (let* ((task (make-hd-read-sectors-task :start-sector start-sector
-                                          :count (mod (count 256))
-                                          :data data))
-         (pending-cons (cons task nil)))
-    (rplacd (hd-pending-last-cons hd) pending-cons)
-    (setf (hd-pending-last-cons hd) pending-cons)))
\ No newline at end of file
+(defun hd-read-sectors (hdnr start-sector count)
+  (let ((data (make-array 512 :element-type :unsigned-byte8))
+        (offset 0)
+        (read-data nil))
+    (with-hd-info (hdc drive) hdnr
+      ;; set drive
+      (hd-controller-feed-drive hdc drive)
+      ;; set count
+      (setf (io-port (hd-controller-command-register hdc 'sector-count)
+                     :unsigned-byte8)
+              count)
+      ;; set LBA and address
+      (hd-controller-feed-lba-mode hdc)
+      (hd-controller-feed-lba-address hdc start-sector)
+      ;; get going
+      (setf (io-port (hd-controller-command-register hdc 'command)
+                     :unsigned-byte8)
+              +hd-commands-read-sectors-with-retry+)
+      ;; data handling
+      (while (<= offset (* count 512))
+        (hd-controller-wait-for-drive-ready hdc)
+        (hd-controller-wait-for-ready hdc)
+        (hd-check-error hdc "read-sectors" hdnr)
+        (hd-controller-wait-for-data-request hdc)
+        (dotimes (i 256)
+          (setf read-data (io-port (hd-controller-command-register hdc 'status)
+                                   :unsigned-byte16)))
+          (setf (aref data offset) (logand read-data #xFF))
+          (setf (aref data (1+ offset)) (logand read-data #xFF00))              
+          (incf offset 2))
+      ;; done
+      data)))
+
+(defun hd-write-sectors (hdnr start-sector data)
+  (let ((offset 0)
+        (write-data nil)
+        (count (div (length data) 512)))
+    (with-hd-info (hdc drive) hdnr
+      ;; set drive
+      (hd-controller-feed-drive hdc drive)
+      ;; set count
+      (setf (io-port (hd-controller-command-register hdc 'sector-count)
+                     :unsigned-byte8)
+              count)
+      ;; set LBA and address
+      (hd-controller-feed-lba-mode hdc)
+      (hd-controller-feed-lba-address hdc start-sector)
+      ;; get going
+      (setf (io-port (hd-controller-command-register hdc 'command)
+                     :unsigned-byte8)
+              +hd-commands-write-sectors-with-retry+)
+      ;; data handling
+      (while (<= offset (* count 512))
+        (hd-controller-wait-for-drive-ready hdc)
+        (hd-controller-wait-for-ready hdc)
+        (hd-check-error hdc "write-sectors" hdnr)
+        (hd-controller-wait-for-data-request hdc)
+        (dotimes (i 256)
+          (setf write-data (aref data offset))
+          (incf write-data (* #xFF (aref data (1+ offset))))
+          (setf (io-port (hd-controller-command-register hdc 'data)
+                         :unsigned-byte16)
+                  write-data)
+          (incf offset 2))))))
\ No newline at end of file





More information about the Movitz-cvs mailing list