/* * (C) Copyright IBM Corp. 2004, 2005 All Rights Reserved. * * main.c * * Tool to make use of a SCSI-feature called Asymmetric Logical Unit Access. * It determines the ALUA state of a device and prints a priority value to * stdout. * * Author(s): Jan Kunigk * S. Bader * * This file is released under the GPL. */ #include #include "debug.h" #include "prio.h" #include "structs.h" #include "alua.h" #define ALUA_PRIO_NOT_SUPPORTED 1 #define ALUA_PRIO_RTPG_FAILED 2 #define ALUA_PRIO_GETAAS_FAILED 3 #define ALUA_PRIO_TPGS_FAILED 4 #define ALUA_PRIO_NO_INFORMATION 5 static const char * aas_string[] = { [AAS_OPTIMIZED] = "active/optimized", [AAS_NON_OPTIMIZED] = "active/non-optimized", [AAS_STANDBY] = "standby", [AAS_UNAVAILABLE] = "unavailable", [AAS_LBA_DEPENDENT] = "logical block dependent", [AAS_RESERVED] = "ARRAY BUG: invalid TPGs state!", [AAS_OFFLINE] = "offline", [AAS_TRANSITIONING] = "transitioning between states", }; static const char *aas_print_string(int rc) { rc &= 0x7f; if (rc & 0x70) return aas_string[AAS_RESERVED]; rc &= 0x0f; if (rc > AAS_RESERVED && rc < AAS_OFFLINE) return aas_string[AAS_RESERVED]; else return aas_string[rc]; } int get_alua_info(struct path * pp, unsigned int timeout) { int rc; int tpg; tpg = get_target_port_group(pp, timeout); if (tpg < 0) { rc = get_target_port_group_support(pp, timeout); if (rc < 0) return -ALUA_PRIO_TPGS_FAILED; if (rc == TPGS_NONE) return -ALUA_PRIO_NOT_SUPPORTED; return -ALUA_PRIO_RTPG_FAILED; } condlog(3, "%s: reported target port group is %i", pp->dev, tpg); rc = get_asymmetric_access_state(pp, tpg, timeout); if (rc < 0) { condlog(2, "%s: get_asymmetric_access_state returned %d", __func__, rc); return -ALUA_PRIO_GETAAS_FAILED; } condlog(3, "%s: aas = %02x [%s]%s", pp->dev, rc, aas_print_string(rc), (rc & 0x80) ? " [preferred]" : ""); return rc; } int get_exclusive_pref_arg(char *args) { char *ptr; if (args == NULL) return 0; ptr = strstr(args, "exclusive_pref_bit"); if (!ptr) return 0; if (ptr[18] != '\0' && ptr[18] != ' ' && ptr[18] != '\t') return 0; if (ptr != args && ptr[-1] != ' ' && ptr[-1] != '\t') return 0; return 1; } int getprio (struct path * pp, char * args, unsigned int timeout) { int rc; int aas; int priopath; int exclusive_pref; if (pp->fd < 0) return -ALUA_PRIO_NO_INFORMATION; exclusive_pref = get_exclusive_pref_arg(args); rc = get_alua_info(pp, timeout); if (rc >= 0) { aas = (rc & 0x0f); priopath = (rc & 0x80); switch(aas) { case AAS_OPTIMIZED: rc = 50; break; case AAS_NON_OPTIMIZED: rc = 10; break; case AAS_LBA_DEPENDENT: rc = 5; break; case AAS_STANDBY: rc = 1; break; default: rc = 0; } if (priopath && (aas != AAS_OPTIMIZED || exclusive_pref)) rc += 80; } else { switch(-rc) { case ALUA_PRIO_NOT_SUPPORTED: condlog(0, "%s: alua not supported", pp->dev); break; case ALUA_PRIO_RTPG_FAILED: condlog(0, "%s: couldn't get target port group", pp->dev); break; case ALUA_PRIO_GETAAS_FAILED: condlog(0, "%s: couldn't get asymmetric access state", pp->dev); break; case ALUA_PRIO_TPGS_FAILED: condlog(3, "%s: couldn't get supported alua states", pp->dev); break; } } return rc; }