Logo Search packages:      
Sourcecode: raidutils version File versions  Download package

deletrad.cpp

/* Copyright (c) 1996-2004, Adaptec Corporation
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * - Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 * - Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 * - Neither the name of the Adaptec Corporation nor the names of its
 *   contributors may be used to endorse or promote products derived from this
 *   software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

/****************************************************************************
*
* Created:  7/30/98
*
*****************************************************************************
*
* File Name:            DeletRad.cpp
* Module:
* Contributors:         Lee Page
* Description:
* Version Control:
*
* $Revision: 22 $
* $NoKeywords: $
* $Log: $
*****************************************************************************/

/*** INCLUDES ***/
#include "deletrad.hpp"
#include "rustring.h"
#include "ctlr_map.hpp"
#include "intlist.hpp"

#include <stdio.h>
/*** CONSTANTS ***/
/*** TYPES ***/
/*** STATIC DATA ***/
/*** EXTERNAL DATA ***/
extern int FID_RESET_OUTBUFF;
extern uSHORT LOG_LIST_SIZE;
/*** MACROS ***/
/*** PROTOTYPES ***/
/*** FUNCTIONS ***/

/****************************************************************************
*
* Function Name:  Delete_Raid(),    Created:7/30/98
*
* Description:          This deletes the logicals listed.  If null is passed in, then
                              ALL logicals will be deleted.
*
* Return:               Delete_Raid
*
* Notes:                ALL LOGICALS WILL BE DELETED IF NULL IS PASSED IN!
*
*****************************************************************************/

Delete_Raid::Delete_Raid(
                        SCSI_Addr_List    *which_Raids,
                        bool              del_Hiddens )
                                          : raids_to_Del( which_Raids ),
                                          delete_Hiddens( del_Hiddens )
      {
      ENTER( "Delete_Raid::Delete_Raid(" );

      EXIT();
      }

Delete_Raid::Delete_Raid( const Delete_Raid &del_Raid ): delete_Hiddens( del_Raid.delete_Hiddens )
      {
      ENTER( "Delete_Raid::Delete_Raid( const Delete_Raid &del_Raid ): delete_Hiddens( del_Raid.delete_Hiddens )" );
      if( del_Raid.raids_to_Del )
            {
            raids_to_Del = new SCSI_Addr_List( *del_Raid.raids_to_Del );
            }
            else
            {
            raids_to_Del = 0;
            }
      EXIT();
      }

Delete_Raid::~Delete_Raid()
      {
      ENTER( "Delete_Raid::~Delete_Raid()" );
      delete      raids_to_Del;
      EXIT();
      }

Command::Dpt_Error      Delete_Raid::execute( String_List **output )
      {
      ENTER( "Command::Dpt_Error    Delete_Raid::execute( String_List **output )" );
      String_List       *out;
      Dpt_Error err = Dpt_Error::DPT_CMD_ERR_NO_ERROR;
    extern void add_Unique_Item( Int_List *component_List, DPT_TAG_T component_Tag );
      Int_List raid_List;
      Int_List raid_List_dual;

      *output     = out = new String_List();

   Init_Engine();

      if( !raids_to_Del )
            {
            Make_Address_List_of_All_Logicals( &raids_to_Del );
            }

      while( raids_to_Del->num_Left() )
            {
            bool more_Devs_Left = true;
            bool tag_Valid; //kds
            SCSI_Address trash_addr; //kds
            SCSI_Address raid_Address = raids_to_Del->get_Next_Item();
            // get this raid's tag
            for (int dev_Index = 0; more_Devs_Left; dev_Index++)
                  {
                  get_Devs_Type devs_Type;

                  DPT_TAG_T raid_Tag = Get_Address_by_Index( raid_Address,
                    dev_Index, &more_Devs_Left, &devs_Type );
                  if ( !more_Devs_Left )
                        {
                        break;
                        }
                  switch ( devs_Type )
                        {
                        case GET_RAID:
                        case GET_RAID_HOT_SPARE:
                        case GET_RAID_REDIRECT:
                    break;
                default:
                    continue;
                }
            if ((devs_Type == GET_RAID_HOT_SPARE) ^ (delete_Hiddens == 0))
                {
                              trash_addr = DPT_Tag_to_Address (raid_Tag, &tag_Valid);
                              // if dual level array, put in one list
                              if (trash_addr.level >= 2)
                                    add_Unique_Item ( &raid_List_dual, raid_Tag);
                              // otherwise put in other
                              else
                                    add_Unique_Item( &raid_List, raid_Tag );
                        }
                  }
            }

      raid_List_dual.reset_Next_Index();
      raid_List.reset_Next_Index();

      // invalid if target not found -kds
      if ((raid_List_dual.num_Left() == 0) &&
            (raid_List.num_Left() == 0))
            {
            err = Dpt_Error::DPT_CMD_ERR_CANT_FIND_COMPONENT;
            out->add_Item( (char *) err );
            }

      if (!err.Is_Error())
      {
      // get rid of parents and their children first
            if (raid_List_dual.num_Left())
            {
                  while( raid_List_dual.num_Left() )
                  {
                        Dpt_Error this_err = Delete_Raid_and_Children(
                              raid_List_dual.get_Next_Item(), out );
                        if( this_err.Is_Error() )
                        {
                              err |= this_err;
                              // output intermediate errors, but don't stop
                              // deleting others
                              out->add_Item( (char *) this_err );
                        }
                  }
            }                 
            // now get rid of orphans
            if (raid_List.num_Left())
            {
                  while( raid_List.num_Left() )
                  {
                        Dpt_Error this_err = Delete_Raid_and_Children(
                                    raid_List.get_Next_Item(), out );
                        // this was already deleted in if (dual) above
                        if (this_err == Dpt_Error::DPT_ERR_INVALID_TGT_TAG)
                              this_err = Dpt_Error::DPT_CMD_ERR_NO_ERROR;
                        // other errors are really errors
                        if( this_err.Is_Error() )
                        {
                              err |= this_err;
                              // output intermediate errors, but don't stop
                              // deleting others
                              out->add_Item( (char *) this_err );
                        }
                  }
            }

      Commit();
      } // !err.Is_Error

      EXIT();
      return( err );
}


/****************************************************************************
*
* Function Name:  Make_Address_List_of_All_Logicals(),      Created:7/30/98
*
* Description:          This fetches a list of all logicals, whether they be parent
*                             or child logicals.
*
* Return:               SCSI_Addr_List
*
* Notes:                The caller must deallocate the object returned.
*
*****************************************************************************/

void  Delete_Raid::Make_Address_List_of_All_Logicals( SCSI_Addr_List **ret_List )
      {
      ENTER( "void      Delete_Raid::Make_Address_List_of_All_Logicals( SCSI_Addr_List **ret_List )" );
      SCSI_Addr_List  *addr_List;
      int                     dev_Index;
      bool              index_Found = true;     // force it to succeed the first time through

      *ret_List   = 0;
      addr_List   = new SCSI_Addr_List();
      
      for( dev_Index = 0; index_Found; dev_Index++ )
            {
            SCSI_Address    this_Logicals_Address;
            DPT_TAG_T         this_Logicals_Tag;
      
            this_Logicals_Tag = Get_Log_Dev_by_Index( dev_Index, (bool)false, &index_Found );
            if( index_Found )
                  {
                  this_Logicals_Address   = DPT_Tag_to_Address( this_Logicals_Tag, &index_Found );
      
                  if( index_Found )
                        {
                        addr_List->add_Item( this_Logicals_Address );
                        }
                  }
            }
      
      *ret_List = addr_List;
      EXIT();
}

Command::Dpt_Error      Delete_Raid::Delete_Raid_and_Children(
      DPT_TAG_T raid_Tag,
      String_List *out)
{
      ENTER( "Command::Dpt_Error    Delete_Raid::Delete_Raid_and_Children(" );
      Dpt_Error   err, busy_err;

      int               component_Index;
      Int_List    component_List;
      bool        raid_Component_Found = TRUE;

      // collect all the children
      for( component_Index = 0; raid_Component_Found; component_Index++ )
            {
            DPT_TAG_T         component_Tag;
            get_Devs_Type     comp_Type;

            // find the nth *logical* (not physical) owned by this logical
            component_Tag     = Get_Component( raid_Tag,
                                                             component_Index,
                                                             &raid_Component_Found,
                                                             &comp_Type );

            if( raid_Component_Found && ( comp_Type != GET_SCSI_DASD ))
                  {
                  component_List.add_Item( component_Tag );
                  }
            }

      // delete this top-level raid
      engine->Reset();
      err   = engine->Send( MSG_GET_INFO, raid_Tag );

      // Checks to see if there are any reserved devices that are trying to be deleted
      if ((engine->devInfo_P->flags3 & FLG_DEV_RES_CONFLICT) && (!(engine->devInfo_P->raidType == RAID_HOT_SPARE)) ){
            out->add_Item( EventStrings[STR_RESCONFLICT] );
      }


      else if( !err.Is_Error() )
            {
            bool tag_Valid;
            SCSI_Address raid_Address;
            switch( engine->devInfo_P->raidType )
                  {
                  case RAID_0 :
                  case RAID_1 :
                  case RAID_5 :
                  case RAID_HOT_SPARE :
                  case RAID_REDIRECT :

                /*******start of device busy section**********/
                  uLONG devStatus;
                busy_err |= engine->Send(MSG_CHECK_BUSY, raid_Tag);

                  // If busy_err = MSG_RTN_IGNORED, then the engine does not
                  // support this command.  Simply treat as not busy.
                  if ((busy_err.Is_Error()) &&
                        (busy_err != Dpt_Error::DPT_MSG_RTN_IGNORED))
                            err |= busy_err;
                  if (!err.Is_Error())
                  {
                        engine->Extract(&devStatus, sizeof(uLONG));
            
                        // If 1, then this device is busy, otherwise
                            // the device is considered NOT busy.
                        if (devStatus == 1)
                        {
                              err = Dpt_Error::DPT_CMD_ERR_COMPONENT_BUSY;
                        }
                  }
                /*******end of device busy section**********/

                        // delete all logicals (not physicals) owned by this logical
                if (!err.Is_Error())
                {
                        raid_Address = DPT_Tag_to_Address(raid_Tag, &tag_Valid);
               // get the tag for the corresponding physical device
               DPT_TAG_T newComponent;
               bool compFound = false;
               get_Devs_Type comp_Type;
               for (int cmpIdx = 0; !compFound; ++cmpIdx)
               {
                  newComponent = Get_Component(raid_Tag, cmpIdx,
                     &compFound, &comp_Type);
               }
//      err = engine->Send(MSG_GET_INFO, newComponent);
//      if (compFound && (comp_Type == GET_SCSI_DASD))

                    

                        engine->Reset();
                        err = engine->Send(MSG_DELETE, raid_Tag);
               // check to see if this made it unintentionally suppressed
               CheckForSuppressed(newComponent);
                }
                        if( !err.Is_Error())
                              {
                              DPTControllerMap * map = new DPTControllerMap;
                              char * String = map->getTargetString(
                                raid_Address.hba, raid_Address.bus, raid_Address.id, raid_Address.lun );
                              out->add_Item( String );
                              delete [] String;
                              delete map;
                              out->add_Item( "\n" );

                              }
                        break;
                  }

            component_List.reset_Next_Index();
            while ( component_List.num_Left() )
                  {
                  // delete all logicals (not physicals) owned by this logical
                  err   |= (Dpt_Error)Delete_Raid_and_Children( component_List.get_Next_Item(), out );
                  }
            }

      EXIT();
      return( err );
}

// check to see if this made it unintentionally suppressed
// if so, the new id will be the lowest chan/id available
Command::Dpt_Error Delete_Raid::CheckForSuppressed (DPT_TAG_T tag)
{
      Dpt_Error err = Dpt_Error::DPT_CMD_ERR_NO_ERROR;
   const int MAX_CHANNELS = 4;
   const int NUMBER_OF_IDS = 16;
   const int NOT_IN_USE = 0;
   const int IN_USE = 1;

      err = engine->Send(MSG_GET_INFO, tag);
   if ((engine->devInfo_P->flags & FLG_DEV_SUPPRESSED) &&
       (!(engine->devInfo_P->flags & FLG_DEV_SUP_DESIRED)))
   {
      dptID_S *loglist = new dptID_S[LOG_LIST_SIZE];
      int devChannel; // channel number of this device
         int availIDs [MAX_CHANNELS];
      char ids [MAX_CHANNELS][NUMBER_OF_IDS];         // array of IDs

         // Get the information about this device
      DPT_TAG_T newIDhba = engine->devInfo_P->hbaTag;
         devChannel = engine->devInfo_P->addr.chan;

      ///////////////////////////////////////////
         // We need to find out which IDs are legal
      ///////////////////////////////////////////

         // first mark all IDs as NOT-IN-USE
      for(int i = 0; i < MAX_CHANNELS; i++)
            for(int j = 0; j < NUMBER_OF_IDS; j++)
                  ids[i][j] = NOT_IN_USE;

      // mark the HBAs ID as IN-USE on all channels
         if(engine->devInfo_P->level != 0)
      {
            err = engine->Send(MSG_GET_INFO, newIDhba);
               // assume that it is an HBA for now
            for(int j = 0; j < MAX_CHANNELS; j++)
                  ids[j][engine->hbaInfo_P->addr.id] = IN_USE;
         }

      // mark off the IDs that are out-of-range for the HBA as IN-USE
         for(int k = 0; k < MAX_CHANNELS; k++)
      {
            for(int l = 0; l < NUMBER_OF_IDS; l++)
               {
                     if((l > engine->hbaInfo_P->maxAddr.id) || 
               (k > engine->hbaInfo_P->maxAddr.chan))
                           ids[k][l] = IN_USE;
            }
         }

      // loop through the logicals of this guy's manager and
         // mark off the ids that are in use
      int numLogs = EngineFindIDs(FID_RESET_OUTBUFF,MSG_ID_LOGICALS,newIDhba,loglist, LOG_LIST_SIZE);
         for(int m = 0; m < numLogs; m++)
      {
            err = engine->Send(MSG_GET_INFO, loglist[m].tag);
               ids[engine->devInfo_P->addr.chan][engine->devInfo_P->addr.id] = IN_USE;
      }

      // Figure out the maximum number of IDs available on any bus
         // and how many buses have IDs available
      for(int n = 0; n < MAX_CHANNELS; n++)
         availIDs[n] = 0;

      int newID = -1;
      int newChan;
         for(int p = 0; p < MAX_CHANNELS; p++)
      {
            for(int q = 0; q < NUMBER_OF_IDS; q++)
               {
                  if(ids[p][q] == NOT_IN_USE)
                  {
                        availIDs[p]++;
                        // remember the lowest available ID
                           if(newID == -1)
                        {
                              newChan = p;
                              newID = q;
                        }
                     }
            }
         }
      int maxAvail = 0;       // max. number of IDs available on any channel
         int chansWithAvail = 0;    // number of channels with available IDs
      for(int r = 0; r < MAX_CHANNELS; r++)
         {
               if(availIDs[r] > maxAvail) maxAvail = availIDs[r];
            if(availIDs[r]) chansWithAvail++;
         }

      // Make sure there are IDs available to redirect this drive to
         if(!chansWithAvail)
      {
         err = Dpt_Error::DPT_ERR_ABS_NO_MORE_IDS;
      }

      if (!err.Is_Error())
      {
         // set new id
         engine->Reset();
               raidHeader_S rh;
            memset(&rh, 0, sizeof(raidHeader_S));
            rh.refNum = RAID_REDIRECT;
               rh.addr.id = newID;
            rh.addr.chan = newChan;
            rh.control = FLG_RCTL_ADDR;

               raidCompList_S component;
            component.tag = tag;
            engine->Insert (&rh, sizeof(raidHeader_S));
               engine->Insert (&component, sizeof(raidCompList_S));
            engine->Send (MSG_RAID_NEW, newIDhba);
      }
   }
   return (err);
}

Command &Delete_Raid::Clone() const
{
      ENTER( "Command         &Delete_Raid::Clone() const" );
      EXIT();
      return( *new Delete_Raid( *this ) );
}

/*** END OF FILE ***/

Generated by  Doxygen 1.6.0   Back to index