#!/opt/SUNWrasag/perl/perl5

require  "subroutines.pm";
&st_globals();

#
# run with perl 5.0
# -d option will enter the perl debugger
#
#########################################################################
# rawdump.pl
# 8 may 98
# 
# Dump the Photon configuration information to stdout.
# This includes;
#   Name
#       Node WWN
#       Port WWN
#       Logical Path  
#   ALPA 
#   HAdr 
#   ID 
#   Typ 
#   DrInst
#       Physical Path
# 
# It also includes the SOC+ Host Adapters.
#
# This information can be saved to a file and have further filtering
# or re-ordering done.
#
# This program gets the raw data from the following sources:
#  /usr/sbin/luxadm sysdump 
#  /usr/sbin/luxadm -e dump_map
#  /etc/path_to_inst
#
# INPUTS:
#   none
#
# USAGE:
#   rawdump [ help | -q ]
# 
# MODIFICATIONS
#   copied to rd_loop.pl
#   added A0,A1,B0,B1 to IB name
#   changed NULL to *
#   added VERBOSE flag
#
#   changed to temp.pl
#       sort in loop map order
#       build lines 1 at a time 
#       process ha's correctly
#       add command line args processing
#   release as rawdump.pl
#
#########################################################################
#########################################################################
# set up
#########################################################################
$PROGNAME = "rawdump";
$SIG{INT} = \&sig_handler;
$LUXADM = "/usr/sbin/luxadm";

#########################################################################
# define a debug flag
#########################################################################
#$DEBUG = "TRUE";
print " * * * * DEBUG FLAG SET * * * * \n" if $DEBUG;

#########################################################################
# default verbose flag to true
#########################################################################
$VERBOSE = 0;

# rawdump. After FCS this should be changed to accept SBUS and PCI
# currently only one call to rawdump (from storconfig:&port_summary())
# makes use of the PCI option. 
# NOTE: this rawdump is not used for the PCI golden snap shot, see: pcidump

&check_root_access( $PROGNAME );
&proc_cli();

#########################################################################
# print all the HA ports
#########################################################################

$t = `$LUXADM -e port`;
print "\nHost Adapter Ports:\n$t" if $VERBOSE;

#########################################################################
# print the online ports
#########################################################################
&make_port_list;

@LD_PORTON = @LD_ON_PORTS;

if (!@LD_PORTON) {
   print "No loops detected.\n" if $VERBOSE;
   exit;
}

print "\nOnline ports:\n$LD_PORTON \n\n" if $VERBOSE;

#########################################################################
# Get A5000 info from luxadm sysdump
# Note: internal FC disks not found by luxadm sysdump 
#########################################################################
@LD_SYSDUMP = split('\n', `$LUXADM sysdump | egrep -v '^Physical'`);

@disklist = split ('\n', `${BINDIR}/disk_inquiry -q -d 2>&1 | grep T300`);
if ($#disklist != -1) {
    #########################################################
    # There are T300 LUN's out there...                     #
    # Append LUN info from /dev/rdsk and disk_inquiry -q -d #
    # since luxadm sysdump doesn't show them                #
    #########################################################
    $scsitargets = "";
    foreach $line (@disklist) {
        ($drive, $vendor, $product, $revision, $serial_no, $dual_port) = split( " ", $line );
        $scsitargets .= "/dev/rdsk/${drive}s0 ";
    }
    my ($line, $wwn, $line, $newline, $lun_number, @fields);
    @LS_LIST = split('\n', `ls -l $scsitargets | grep ssd`);
    foreach $line (@LS_LIST) {
        @fields = split /\s+/, $line;
        $fields[10] = $1 if ($fields[10] =~ /^\.\.\/\.\.(.*)$/);
        $wwn = $1 if ($line =~ /ssd\@w([a-fA-F0-9]+),/);
        $lun_number = "0";
        $lun_number = $1 if ($fields[8] =~ /t\d+d(\d+)s/);
        $newline = sprintf("%-81s%-18s%-18s%-23s%-5s", "$fields[10]", "$wwn", "$wwn", "$fields[8]", "T300,$lun_number");
        push @LD_SYSDUMP, $newline;
        push @LD_T300, $newline; 
    }
}

#########################################################################
# get the driver instances from path to inst
#########################################################################
$i = 0;
$file = $ENV{PATH_TO_INST} || "/etc/path_to_inst";
if (open(FILE, "<$file")) {;
    @P2INST = <FILE>; # read entire file
    close P2INST;
} else {
    # could not open file
    die "\nCould not locate $path_to_inst file\nPlease set ENV variable \$PATH_TO_INST to proper location of /etc/path_to_inst\n\n";
}
if ($P2INST[0] =~ /#path_to_inst_bootstrap 1/) {
    ##########################################
    # Did not find correct path_to_inst file #
    ##########################################
    die "\nCould not locate proper /etc/path_to_inst file\nPlease set ENV variable \$PATH_TO_INST to proper location of this file\n\n";
}
foreach $line (@P2INST) {
    chomp $line;
    ($field1, $field2, $field3) = $line =~
    /"(\S+)"\s+(\S+)\s+"(\S+)"/;
    next if ($field1 eq "");

    $P2INST_DUMP[$i] = " $field1 ";
    $P2INST_DUMP[$i] .=" $field2 ";
    $P2INST_DUMP[$i] .=" $field3 \n";
    $i++;
}

###################
# Display Heading #
###################
#       0   1   2   3  4  5  6  7  8  9  10
@fw = (19, 17, 17, 14, 5, 5, 3, 4, 8, 8, 100);

printf("%-$fw[0]s%-$fw[1]s%-$fw[2]s%-$fw[3]s%-$fw[4]s%-$fw[5]s%-$fw[6]s%-$fw[7]s%-$fw[8]s%-$fw[9]s%-$fw[10]s\n\n",
"Name","Node WWN","Port WWN","Logical Path","ALPA","HAdr","ID","Typ","DrInst","","Physical Path") if $VERBOSE;


$hadone_l = ' ';
#########################################################################
# Main Loop
# This loop will process each Online Host Adapter Port discovered.
# Each HA Port corresponds to a single loop.
#########################################################################
foreach $olport (@LD_PORTON) {

    if ($hadone_l !~ /$olport/) {
        $ld_dumpmap = `$LUXADM -e dump_map $olport | grep -v 'Pos'`;
        @LD_DUMPMAP = split(/\n/, $ld_dumpmap);
        &buildmaplines;
    }
    print "\n";
}


#########################################################################
# End of Main Program
# Subroutines start here
#########################################################################

#########################################################################
# matchkey                                                              #
# match a string to one field on a line, then return a different field  #
# otherwise return "ER"                                                 #
#########################################################################
sub matchkey {
    my ($match_key, $target_field, $return_field, @table) = @_;
    foreach $line (@table) {
        (@line) = split(' ', $line);
        if ($line[$target_field] =~ /\b$match_key/) {
            return $line[$return_field];
        }
    }
    return "ER";
}

#########################################################################
# matchdrinst
# do the same as matchkey to get the driver instances
# INPUTS:
#   pk  key
#   pkl key location (offset)
#   rl  return location (offset)
#   table   array to search
#########################################################################
sub matchdrinst {
    ($match_key, $target, $return_field, @table) = @_;
    foreach $line (@table) {
        (@line) = split(' ', $line);
        if (($line[$target]) =~ /$match_key/) {
            $rs = $line[$return_field+1].$line[$return_field];
            return $rs; 
        }
    }
    return "ER";
}

#########################################################################
# buildhaline
# process a line in the map that is an HA
# INPUTS:
#   myport  physical address of input ha port   
#   MYLIST  array of dumpmap command
#########################################################################
sub buildhaline {
    my ($current_port) = @_;
    my $myport = $olport;
    $hadone_l .= " $myport";
    # get the alpa of this host adapter from the dumpmap command
    # if its a socal path we are dealing with
    (@la) = split(' ', $current_port);
    $my_alpa = $la[1];


#########################################################################
# output:
# Name  Node WWN  Port WWN  Logical Path  ALPA ID HAdr Typ DrInst Dr Inst Physical Path
#  0      1         2         3             4   5  6    7    8     9      10
#  -      x         x         -             x   x  x    x    x     x       x
#########################################################################

    $val = sprintf("%-$fw[0]s", "*HA*");
    $OBJHA{$key} = $val;

    $nwwn = $la[5];
    $val = sprintf("%-$fw[1]s", $nwwn);
    $OBJHA{$key} .= $val;

    $pwwn = $la[4];
    $val = sprintf("%-$fw[2]s", $pwwn);
    $OBJHA{$key} .= $val;

    $val = sprintf("%-$fw[3]s", "*");
    $OBJHA{$key} .= $val;

    $val = sprintf("%-$fw[4]s", $my_alpa);
    $OBJHA{$key} .= $val;

    $hdaddr = $la[3];
    $val = sprintf("%-$fw[5]s", $hdaddr);
    $OBJHA{$key} .= $val;

    $id = $la[2];
    $val = sprintf("%-$fw[6]s", $id);
    $OBJHA{$key} .= $val;

    $type = "HA";
    $val = sprintf("%-$fw[7]s", $type);
    $OBJHA{$key} .= $val;
        
    $val = sprintf("%-$fw[8]s", $SOCNUM{$myport});
    $OBJHA{$key} .= $val;

    $val = sprintf("%-$fw[9]s", $SFNUM{$myport});
    $OBJHA{$key} .= $val;

    $val = sprintf("%-s", $myport);
    $OBJHA{$key} .= $val;

    print "$OBJHA{$key}\n";

}


#########################################################################
# buildmaplines
# build disk drive (DD) and interface board (IB) type lines found in 
# a loop map.
# INPUTS: global variable @LD_DUMPMAP
#########################################################################
sub buildmaplines {
        foreach $line (@LD_DUMPMAP) {
            $dr_inst0 = "";
            @LINE = split(' ', $line);
            $pwwn = $LINE[4];   # port WWN
            $nwwn = $LINE[5];   # Node WWN
            $name = &matchkey($pwwn, 2, 4, @LD_SYSDUMP);
            $key = &matchkey($pwwn, 2, 0, @LD_SYSDUMP);
            $logpath = &matchkey($pwwn, 2, 3, @LD_SYSDUMP);
            @lp = split('/',$logpath);
            if ($lp[3] =~ /^(c.*)s\d+$/) {
                ($ddlp) = $1;
            } elsif ($lp[3] =~ /ses/) {
                $ddlp = $lp[3];
            } else {
                #########################################################
                # unknown device, no scsi target, try disklist with wwn #
                # as last chance to identify it.                        #
                #########################################################
                $ddlp = "*";
                my $guess = `$BINDIR/disklist | grep $pwwn`;
                $ddlp = $1 if ($guess =~ /^(c\d+t\d+d\d+)\s+/);
            }
            $alpa = $LINE[1];
            $id = $LINE[2];
            $hdaddr = $LINE[3];
            $type = $LINE[6];
            if ($line =~ /Host Bus Adapter/) {
               &buildhaline($line);
               next;
            } elsif ($line =~ /Disk device/) {
               $ttran = "DD"; 
               $name = "*Disk*" if ($name eq "ER"); # no SES enclosure, internal drive
               if ($key eq "ER") {
                   ##############################################
                   # find /dev/rdsk path info for internal disk #
                   ##############################################
                   $key = `grep $pwwn /etc/path_to_inst`;
                   ($field1, $field2, $field3) = $key =~ /"(\S+)"\s+(\S+)\s+"(\S+)"/;
                   $key = "$field1:c,raw" if ($field1 ne "");
                   $dr_inst0 = "$field3$field2" if ($field3 ne "");
               }
            } elsif ($line =~ /SES device/) {
               $ttran = "IB";
            } elsif ($line =~ /Unknown Type/) {
               $ttran = "UK";
               &unktype(@LINE);
               next;
            } else {
               $ttran = "UK"; 
               &unktype(@LINE);
               $ttran = $type;
               next;
            }
            if (($type =~ /0/) && (($pwwn == 0) || ($nwwn == 0))) {
               print "\n\nError in Map!\n\n";
               next;
            }
            if ($ttran eq IB) {
                ##################################################################
                # With A5000's the world wide number gives you a clue            #
                # as to what physical port is used on the back of the enclosure. #
                # Remember, we have 4 ports labeled A0,A1,B0,B1                  #
                ##################################################################
                ($ibpwwn) = $pwwn =~ /([0-9a-f?])$/;
                if ($ibpwwn eq "1") {
                    $ibport = A0;
                } elsif ($ibpwwn eq "2") {
                    $ibport = A1;
                } elsif ($ibpwwn eq "3") {
                    $ibport = B0;
                } elsif ($ibpwwn eq "4") {
                    $ibport = B1;
                } elsif ($ibpwwn eq "9") {
                    $ibport = A0;
                } elsif ($ibpwwn eq "a") {
                    $ibport = A1;
                } elsif ($ibpwwn eq "b") {
                    $ibport = B0;
                } elsif ($ibpwwn eq "c") {
                    $ibport = B1;
                } else {
                    $ibport = ER;
                }
                $name .= ",$ibport";
            }   
            # strip off the leading "/devices" from the key
            my ($modkey) = $key =~ /\/devices(\S+,0):/; 
            ($dr_inst0) = &matchdrinst($modkey, 0, 1, @P2INST_DUMP) if ($dr_inst0 eq "");
            if ($dr_inst0 eq "") {
                $dr_inst0 = "ER";
            }             
    
            if ($name =~ /T300/) {
               ################################
               # check for multi-LUN scenario #
               ################################
               $scsi_target = "";
               undef %T300_names;
               if ($ddlp =~ /^(c\d+t\d+)/) {
                   $scsi_target = "/dev/rdsk/$1";
                   foreach $lun (@LD_T300) {
                       my @LUN = split /\s+/, $lun;
                       if (($lun =~ /$scsi_target/) and ($LUN[1] eq $pwwn)) {
                           #########################################
                           # collect all T300 names and rdsk paths #
                           # associated with this wwn.             #
                           #########################################
                           my $new_ddlp = $ddlp;
                           $new_ddlp = $1 if ($LUN[3] =~ /(c\d+t\d+d\d+)/);
                           $T300_names{$LUN[0]} = $LUN[4]; # save for sort later
               &print_line($LUN[4], $nwwn, $pwwn, $new_ddlp, $alpa, $hdaddr, $id, $ttran, $dr_inst0, $LUN[0]);
                       }
                   }
               }
            } else {
               &print_line($name, $nwwn, $pwwn, $ddlp, $alpa, $hdaddr, $id, $ttran, $dr_inst0, $key);
            }
        }
}

sub print_line {

    my ($name, $nwwn, $pwwn, $ddlp, $alpa, $hdaddr, $id, $ttran, $dr_inst0, $key) = @_;
    $val = sprintf("%-$fw[0]s", $name);
    $objr = $val;

    $val = sprintf("%-$fw[1]s", $nwwn);
    $objr .= $val;

    $val = sprintf("%-$fw[2]s", $pwwn);
    $objr .= $val;

    $val = sprintf("%-$fw[3]s", $ddlp);
    $objr .= $val;

    $val = sprintf("%-$fw[4]s", $alpa);
    $objr .= $val;

    $val = sprintf("%-$fw[5]s", $hdaddr);
    $objr .= $val;

    $val = sprintf("%-$fw[6]s", $id);
    $objr .= $val;

    $val = sprintf("%-$fw[7]s", $ttran);
    $objr .= $val;

    $val = sprintf("%-$fw[8].$fw[8]s", $dr_inst0);
    $objr .= $val;

    # add space to the object record
    $val = sprintf("%-$fw[9]s", "*");
    $objr .= $val;

    # add path to the object record
    $val = sprintf("%-s", $key);
    $objr .= $val;

    print "$objr\n";

}

#########################################################################
# unktype
# process a line for a unknown node type in a loop map.
# most likely, the unknown type is an HA
# it could be an actual problem in the loop map
#########################################################################
sub unktype {
    (@LINEIN) = @_;

    my $socal_substr;
    my $portnum;

    $val = sprintf("%-$fw[0]s", "*Unknown Type*");
    $objr = $val;

    $alpa = $LINEIN[1];
    $id = $LINEIN[2];
    $hdaddr = $LINEIN[3];
    $ttran = UK;

    $val = sprintf("%-$fw[1]s", "$LINEIN[4]");
    $objr .= $val;
    $val = sprintf("%-$fw[2]s", "$LINEIN[5]");
    $objr .= $val;

    $val = sprintf("%-$fw[3]s", "*");
    $objr .= $val;

    $val = sprintf("%-$fw[4]s", $alpa);
    $objr .= $val;

    $val = sprintf("%-$fw[5]s", $hdaddr);
    $objr .= $val;

    $val = sprintf("%-$fw[6]s", $id);
    $objr .= $val;

    $val = sprintf("%-$fw[7]s", $ttran);
    $objr .= $val;
    
    $val = sprintf("%-$fw[8].$fw[8]s", "*");
    $objr .= $val;

    # add space to the object record
    $val = sprintf("%-$fw[9]s", "*");
    $objr .= $val;

    # add path to the object record
    $val = sprintf("%-s", "Unknown Type - May be HA on another system");
    $objr .= $val;

    print "$objr\n";

}

#########################################################################
# process command line arguments
# get the input parms and process them
# define the usage
# INPUTS:
#   ARGV    input parms
#########################################################################

sub proc_cli {
    $usage[0] = "$PROGNAME [-help] [-v]\n";
    $usage[1] = "-help - prints out the usage\n";
    $usage[2] = "-v    - print headers\n";

    foreach $arg (@ARGV) {
        if ($arg =~ /help/) {
            die @usage;
        } elsif ($arg =~ /^-v/)       {
            $VERBOSE = 1;
        } else {
            die @usage;
        }
    }

}
