#!/usr/bin/wish -f
# Copyright 1994 Michael Weller (eowmob@exp-math.uni-essen.de)
# You may copy this file according to the terms and conditions of version 2
# of the GNU General Public License as published by the Free Software
# Foundation.

set sdevice [lindex $argv 0]

set spindle_x 10
set disk_radius 400
set canvas_width 600
set canvas_height 350
# One less disk is actually shown s.t. the user is able to guess that some are missing
set max_disks 12
set disk_y 40
set disk_skip 30
set ratio 5

#Number of colors in spindle_colors, Note: Outermost color choosen is at index 0
set num_color 6
set spindle_colors {firebrick2 DarkOrange1 yellow1 green1 blue1 VioletRed2}
#Same but for active buttons
set spindle_colors_act {firebrick3 DarkOrange2 yellow2 green2 blue2 VioletRed3}
#Same but for texts
set spindle_colors_for {white white black black white white}

proc set_notch { { notch } } {
  global pages_sup sdevice
  if { ($pages_sup & (1 << 12)) } then {
     set line [ exec scsiinfo -nX $sdevice ]
     set line [ lreplace $line 3 3 $notch ]
# Use /bin/sh to cut $line in multiple pieces
     set line [ exec sh -c "scsiinfo -nXR $sdevice $line" ]
#    exec scsiinfo -nX $sdevice >/dev/tty
  }
}

proc arrow_horz { {y} {startx} {endx} {text} } {
  set center [expr ($endx+$startx)/2]
  set textid [.fra.c create text $center $y -text $text -justify center]
  set bbox [.fra.c bbox $textid]
  set ltext [lindex $bbox 0]
  set rtext [lindex $bbox 2]
  .fra.c create line $startx $y $ltext $y -arrow first 
  .fra.c create line $rtext $y $endx $y -arrow last 
  set yl [expr $y + 4]
  set yh [expr $y - 3]
  .fra.c create line $startx $yl $startx $yh
  .fra.c create line $endx $yl $endx $yh
}

proc arrow_vert { {x} {starty} {endy} {text} } {
  set center [expr ($endy+$starty)/2]
  set textid [.fra.c create text $x $center -text $text -justify center]
  set bbox [.fra.c bbox $textid]
  set utext [lindex $bbox 1]
  set dtext [lindex $bbox 3]
  .fra.c create line $x $starty $x $utext -arrow first 
  .fra.c create line $x $dtext $x $endy -arrow last 
  set xl [expr $x + 4]
  set xh [expr $x - 3]
  .fra.c create line $xl $starty $xh $starty
  .fra.c create line $xl $endy $xh $endy
}

proc draw_disk { {y} } {
  global spindle_x disk_radius spindle_colors num_color
  global not_drv not_num not_start not_end ratio

  if ($not_drv) {
    set maxsect [lindex $not_end 0]
    set color [lindex $spindle_colors 0]
    set out_color black
    for { set i 1 } {[expr $i <= $not_num]} { set i [expr $i+1] } {
      set radi [expr (($maxsect-[lindex $not_start $i])*$disk_radius)/$maxsect]
      .fra.c create oval [expr $spindle_x-$radi] [expr $y-$radi/$ratio]\
           [expr $spindle_x+$radi] [expr $y+$radi/$ratio] -fill $color -outline $out_color
      set color [lindex $spindle_colors [expr $i % $num_color]]
      set out_color $color
    }
  } else {
    .fra.c create oval [expr $spindle_x-$disk_radius] [expr $y-$disk_radius/$ratio]\
           [expr $spindle_x+$disk_radius] [expr $y+$disk_radius/$ratio] -fill DarkOrange -outline black
  }
}

proc cyl_mark { {cyl} {text} {offset 14} } {
  global spindle_x disk_radius cyls disk_y

  if ([expr $cyls*$cyl!=0]) {
    vert_mark [expr ($disk_radius*$cyl)/$cyls] "$text" $offset
  }
}

proc vert_mark { {xoffset} {text} {offset 25} } {
  global spindle_x disk_radius disk_y

  set destx [expr $xoffset+$spindle_x]
  .fra.c create text $destx [expr $disk_y-$offset]  -anchor s -text "$text" -justify center
  .fra.c create line $destx [expr $disk_y-$offset] $destx [expr $disk_y-7] -arrow last
}

proc show_help {} {
.but.help configure -state disabled

toplevel .help
frame .help.h
label .help.h.info -bitmap info -bg pink
message .help.h.message -aspect 200 -justify left -bg pink -text \
"Well, since this is a tool for experienced users there is not much to say here.\
Most things should explain themself. This page is most useful for notched disk drives.\
Then it will show a few things from several notches at one glance and allow to select the\
notched pages immediately for each notch. The middle button in the top row gives access\
to all pages. Notched pages are marked with a SlateGrey background. All pages are accessed\
with active notch 0.
The numbers on the notch buttons correspond to the alternating sectors for this notch.\
These are sectors that are used for automatic reallocation of bad sectors. The first number\
is the number of tracks that define a zone (0 if there is only one zone) and then the number\
of alternate sectors per zone, of alternate tracks per zone, and alternate tracks per lun\
each seperated by dashes.
Note that none of values shown is reread when you change something\
from this window.
If needed scrollbars will appear to show the whole drawing."
button .help.quit -text "Dismiss" -command "destroy .help"\
  -activeforeground white -activebackground red
pack .help.h.info .help.h.message -padx 10 -side left
pack .help.h -pady 10
pack .help.quit -pady 10 -ipadx 10

wm geometry .help +300+300
wm title .help "Quickhelp for Geometry Overview"
tkwait window .help
.but.help configure -state normal
}

proc notch_menu {number} {
set_notch $number
.not_men.headline configure -text "Notch #$number"
.not_men post 300 300
}

proc add_button {mask backmask index menu text command} {
global sdevice

if { ($mask & (1<<$index)) } then {
  if { ($backmask & (1<<$index)) } then {
    $menu add command -label "$text" -background SlateGray1 -activebackground SlateGray2\
      -command "exec /usr/lib/scsi/$command $sdevice"
  } else {
    $menu add command -label "$text"\
      -command "exec /usr/lib/scsi/$command $sdevice"
  }
}
}

proc add_items {menu mask {backmask 0}} {
add_button $mask $backmask 8 $menu "Cache Control Page" cache
add_button $mask $backmask 3 $menu "Format Device Page" format
add_button $mask $backmask 10 $menu "Control Mode Page" control
add_button $mask $backmask 1 $menu "Read-Write Error Recovery Page" error
add_button $mask $backmask 7 $menu "Verify Error Recovery Page" verify
add_button $mask $backmask 2 $menu "Disconnect/Reconnect Page" disconnect
add_button $mask $backmask 4 $menu "Rigid Disk Geometry Page" rigid
add_button $mask $backmask 9 $menu "Peripheral Device Page" peripheral
add_button $mask $backmask 12 $menu "Notch Page" notch
}

set line [ exec scsiinfo -XL $sdevice ]
set pages_sup [lindex $line 0]
set pages_notch [lindex $line 1]

#Force notch to 0 if possible.
set_notch 0

frame .h
label .h.info -bitmap hourglass -bg pink
message .h.message -width 300 -justify center -bg pink -text \
	"Analyzing device - $sdevice."

pack .h.info .h.message -padx 10 -side left

frame .but
button .but.help -text "Quick Help" \
	-activebackground green -command show_help
menubutton .but.base -relief raised\
  -text "Unnotched or Notch 0 pages" -menu .but.base.menu
menu .but.base.menu -postcommand "set_notch 0"
add_items .but.base.menu $pages_sup $pages_notch

button .but.quit -text Quit \
	-activeforeground white -activebackground red -command exit
pack .h .but -pady 10
pack .but.help .but.base .but.quit -side left -fill x -ipadx 20 -ipady 1 -padx 20 -pady 2
frame .fra 
canvas .fra.c -relief raised -width $canvas_width -height $canvas_height
pack .fra.c -expand yes -fill both
pack .fra -fill both
update

if { ($pages_sup & (1 << 4)) } then {
  set line [ exec scsiinfo -gX $sdevice ]
} else {
  set line {0 0 0 0 0 0 0 0 0}
}
set cyls [lindex $line 0]
set head [lindex $line 1]
set writepre [lindex $line 2]
set reduccur [lindex $line 3]
set land [lindex $line 5]
set rotrate [lindex $line 8]

if { ($pages_sup & (1 << 3)) } then {
  set line [ exec scsiinfo -fX $sdevice ]
} else {
  set line {0 0 0 0 0  0 0 0 0 0  0 0 0}
}

set trperzone [lindex $line 4]
set altern "[lindex $line 5]-[lindex $line 6]-[lindex $line 7]"
set bytesps [lindex $line 9]
set sectptr [lindex $line 8]

if { ($pages_sup & (1 << 12)) } then {
  set line [ exec scsiinfo -nX $sdevice ]
  set not_drv [lindex $line 0]
  set not_log [lindex $line 1]
  set not_num [lindex $line 2]
  set not_start [lindex $line 4]
  set not_end [lindex $line 5]

  for {set i 1} {$i <= $not_num} {set i [expr $i + 1] } {
    set_notch $i
    set line [ exec scsiinfo -nX $sdevice ]
    lappend not_start [lindex $line 4]
    lappend not_end [lindex $line 5]
    if { ($pages_notch & (1<<3)) } then {
      set line [ exec scsiinfo -fX $sdevice ]
      lappend altern "[lindex $line 5]-[lindex $line 6]-[lindex $line 7]"
      lappend sectptr [lindex $line 8]
      lappend trperzone [lindex $line 4]
    }
  }
  set_notch 0
} else {
  set not_drv 0
  set not_log 0
  set not_num 1
  set not_start {}
  set not_end {}
}

if [expr $head == 0] {
  draw_disk $disk_y
} else {
  set disco [expr (($head + 1)/2) - 1]
  if { $disco >= $max_disks } then { set disco [expr $max_disks-1] }
  if { $disco < 1 } then { set disco 1 }
  for { set i $disco } {[expr $i >= 0]} { set i [expr $i-1] } {
    draw_disk [expr $disk_y+$i*$disk_skip]
  }
  set basey [expr $disk_radius/$ratio+$disk_y]
  arrow_vert [expr $spindle_x+30] $basey [expr $basey+$disco*$disk_skip] "$head heads"
}

.fra.c create line $spindle_x $disk_y $spindle_x [expr $disk_y - 20] -width 7
.fra.c create oval [expr $spindle_x-3] [expr $disk_y-2] [expr $spindle_x+3] [expr $disk_y+2]\
   -fill black
.fra.c create oval [expr $spindle_x-3] [expr $disk_y-22] [expr $spindle_x+3] [expr $disk_y-18]\
   -fill black

if [expr $cyls != 0] {
  arrow_horz $disk_y [expr $spindle_x+3] [expr $spindle_x+$disk_radius] "$cyls cylinders"
}

if [expr $rotrate != 0] {
  .fra.c create arc [expr $spindle_x-44] [expr $disk_y-44/$ratio]\
           [expr $spindle_x+44] [expr $disk_y+44/$ratio]\
           -width 3 -start -60 -extent 330 -style arc -fill black
  .fra.c create line [expr $spindle_x-5] [expr $disk_y+44/$ratio]\
           [expr $spindle_x+5] [expr $disk_y+44/$ratio] -arrow last -width 3
  .fra.c create text [expr $spindle_x+5] [expr $disk_y+15] -anchor w -justify center\
           -text "$rotrate rotations per minute"
}

frame .fra.c.buttons

if ($not_drv) {
  for { set i $not_num } {[expr $i >= 1]} { set i [expr $i-1] } {
    set maxsect [lindex $not_end 0]
    set radi [expr ((2*$maxsect-[lindex $not_end $i]-[lindex $not_start $i])\
      *$disk_radius)/(2*$maxsect)]
    vert_mark $radi [lindex $sectptr $i] 
#While looping through the notches create notch_buttons
    set backcolor [lindex $spindle_colors [expr ($i-1)%$num_color]]
    set actcolor [lindex $spindle_colors_act [expr ($i-1)%$num_color]]
    set forecolor [lindex $spindle_colors_for [expr ($i-1)%$num_color]]

    menubutton .fra.c.buttons.$i -background $backcolor -activebackground $actcolor\
        -relief raised -text "Notch #$i: [lindex $trperzone $i], [lindex $altern $i]"\
        -menu .fra.c.buttons.$i.menu -foreground $forecolor -activeforeground $forecolor
    menu .fra.c.buttons.$i.menu -postcommand "set_notch $i" -background $backcolor\
        -activebackground $actcolor -disabledforeground $forecolor -foreground $forecolor\
        -activeforeground $forecolor
    .fra.c.buttons.$i.menu add command -label "Start: [lindex $not_start $i]" -state disabled
    .fra.c.buttons.$i.menu add command -label "End: [lindex $not_end $i]" -state disabled
    add_items .fra.c.buttons.$i.menu $pages_notch
    pack .fra.c.buttons.$i -side bottom -fill x -padx 10
  }
  .fra.c create text [expr $spindle_x+$disk_radius] [expr $disk_y-25] -text "- Sectors per track"\
    -justify left -anchor sw
} else {
  vert_mark [expr $disk_radius/2] "$sectptr sectors per track"
}

cyl_mark $writepre "Write precomp.($writepre)"
cyl_mark $reduccur "Red. current($reduccur)"
cyl_mark $land "Landing zone($land)"

.fra.c create window [expr $disk_radius+15] $disk_y -window .fra.c.buttons -anchor nw
.fra.c addtag alltag all
set bb [ .fra.c bbox alltag ]

#The following are mostly needed for the window item in the canvas.
#they are fully experimental and probably only needed due to a bug in the
#bbox canvas code for windows.. anyway nothing serious can go wrong..

set xbound [expr [lindex $bb 2]+50]
set ybound [expr [lindex $bb 3]+5]
set packed 1

if {( $ybound+20 > $canvas_height )} then {
  if {( $packed )} then {
    pack forget .fra.c
    set packed 0
  }
  .fra.c configure -scrollregion "0 0 $xbound $ybound" -yscroll ".fra.yscroll set"
  scrollbar .fra.yscroll -relief sunken -command ".fra.c yview"
  pack .fra.yscroll -side right -fill y
}
if {( $xbound+20 > $canvas_width )} then {
  if {( $packed )} then {
    pack forget .fra.c
    set packed 0
  }
  .fra.c configure -scrollregion "0 0 $xbound $ybound" -xscroll ".fra.hscroll set"
  scrollbar .fra.hscroll -orient horiz -relief sunken -command ".fra.c xview"
  pack .fra.hscroll -side bottom -fill x
}
if {( !$packed )} then {
  pack .fra.c -in .fra -expand yes -fill both
  set packed 1
}

.h.info configure -bitmap info
.h.message configure -text "Disk Drive Geometry Overview - $sdevice."
