diff options
author | Mark Haverkamp <markh@osdl.org> | 2005-09-26 16:04:56 -0400 |
---|---|---|
committer | James Bottomley <jejb@mulgrave.(none)> | 2005-09-26 18:42:50 -0400 |
commit | 131256cf203d0df62014dda8453a70cb6af0d0bb (patch) | |
tree | 6e7ba27ba4d4181a312a7b1bec385cf68b501dcd /drivers/scsi/aacraid/commsup.c | |
parent | 2f130980d14cb938226011875ca5224cd46dc1f9 (diff) |
[SCSI] aacraid: handle AIF hotplug events (update)
Received from Mark Salyzyn from Adaptec.
Hotplug sniffs the AIFs (events) from the adapter and if a container
change resulting in the device going offline (container zero), online
(container zero completed) or changing capacity (morph) it will take
actions by calling the appropriate API.
Signed-off-by: Mark Haverkamp <markh@osdl.org>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/scsi/aacraid/commsup.c')
-rw-r--r-- | drivers/scsi/aacraid/commsup.c | 274 |
1 files changed, 273 insertions, 1 deletions
diff --git a/drivers/scsi/aacraid/commsup.c b/drivers/scsi/aacraid/commsup.c index 3741be2f4bfa..69985b08a270 100644 --- a/drivers/scsi/aacraid/commsup.c +++ b/drivers/scsi/aacraid/commsup.c | |||
@@ -39,6 +39,7 @@ | |||
39 | #include <linux/completion.h> | 39 | #include <linux/completion.h> |
40 | #include <linux/blkdev.h> | 40 | #include <linux/blkdev.h> |
41 | #include <scsi/scsi_host.h> | 41 | #include <scsi/scsi_host.h> |
42 | #include <scsi/scsi_device.h> | ||
42 | #include <asm/semaphore.h> | 43 | #include <asm/semaphore.h> |
43 | 44 | ||
44 | #include "aacraid.h" | 45 | #include "aacraid.h" |
@@ -791,6 +792,268 @@ void aac_printf(struct aac_dev *dev, u32 val) | |||
791 | memset(cp, 0, 256); | 792 | memset(cp, 0, 256); |
792 | } | 793 | } |
793 | 794 | ||
795 | |||
796 | /** | ||
797 | * aac_handle_aif - Handle a message from the firmware | ||
798 | * @dev: Which adapter this fib is from | ||
799 | * @fibptr: Pointer to fibptr from adapter | ||
800 | * | ||
801 | * This routine handles a driver notify fib from the adapter and | ||
802 | * dispatches it to the appropriate routine for handling. | ||
803 | */ | ||
804 | |||
805 | static void aac_handle_aif(struct aac_dev * dev, struct fib * fibptr) | ||
806 | { | ||
807 | struct hw_fib * hw_fib = fibptr->hw_fib; | ||
808 | struct aac_aifcmd * aifcmd = (struct aac_aifcmd *)hw_fib->data; | ||
809 | int busy; | ||
810 | u32 container; | ||
811 | struct scsi_device *device; | ||
812 | enum { | ||
813 | NOTHING, | ||
814 | DELETE, | ||
815 | ADD, | ||
816 | CHANGE | ||
817 | } device_config_needed; | ||
818 | |||
819 | /* Sniff for container changes */ | ||
820 | |||
821 | if (!dev) | ||
822 | return; | ||
823 | container = (u32)-1; | ||
824 | |||
825 | /* | ||
826 | * We have set this up to try and minimize the number of | ||
827 | * re-configures that take place. As a result of this when | ||
828 | * certain AIF's come in we will set a flag waiting for another | ||
829 | * type of AIF before setting the re-config flag. | ||
830 | */ | ||
831 | switch (le32_to_cpu(aifcmd->command)) { | ||
832 | case AifCmdDriverNotify: | ||
833 | switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) { | ||
834 | /* | ||
835 | * Morph or Expand complete | ||
836 | */ | ||
837 | case AifDenMorphComplete: | ||
838 | case AifDenVolumeExtendComplete: | ||
839 | container = le32_to_cpu(((u32 *)aifcmd->data)[1]); | ||
840 | if (container >= dev->maximum_num_containers) | ||
841 | break; | ||
842 | |||
843 | /* | ||
844 | * Find the Scsi_Device associated with the SCSI | ||
845 | * address. Make sure we have the right array, and if | ||
846 | * so set the flag to initiate a new re-config once we | ||
847 | * see an AifEnConfigChange AIF come through. | ||
848 | */ | ||
849 | |||
850 | if ((dev != NULL) && (dev->scsi_host_ptr != NULL)) { | ||
851 | device = scsi_device_lookup(dev->scsi_host_ptr, | ||
852 | CONTAINER_TO_CHANNEL(container), | ||
853 | CONTAINER_TO_ID(container), | ||
854 | CONTAINER_TO_LUN(container)); | ||
855 | if (device) { | ||
856 | dev->fsa_dev[container].config_needed = CHANGE; | ||
857 | dev->fsa_dev[container].config_waiting_on = AifEnConfigChange; | ||
858 | scsi_device_put(device); | ||
859 | } | ||
860 | } | ||
861 | } | ||
862 | |||
863 | /* | ||
864 | * If we are waiting on something and this happens to be | ||
865 | * that thing then set the re-configure flag. | ||
866 | */ | ||
867 | if (container != (u32)-1) { | ||
868 | if (container >= dev->maximum_num_containers) | ||
869 | break; | ||
870 | if (dev->fsa_dev[container].config_waiting_on == | ||
871 | le32_to_cpu(*(u32 *)aifcmd->data)) | ||
872 | dev->fsa_dev[container].config_waiting_on = 0; | ||
873 | } else for (container = 0; | ||
874 | container < dev->maximum_num_containers; ++container) { | ||
875 | if (dev->fsa_dev[container].config_waiting_on == | ||
876 | le32_to_cpu(*(u32 *)aifcmd->data)) | ||
877 | dev->fsa_dev[container].config_waiting_on = 0; | ||
878 | } | ||
879 | break; | ||
880 | |||
881 | case AifCmdEventNotify: | ||
882 | switch (le32_to_cpu(((u32 *)aifcmd->data)[0])) { | ||
883 | /* | ||
884 | * Add an Array. | ||
885 | */ | ||
886 | case AifEnAddContainer: | ||
887 | container = le32_to_cpu(((u32 *)aifcmd->data)[1]); | ||
888 | if (container >= dev->maximum_num_containers) | ||
889 | break; | ||
890 | dev->fsa_dev[container].config_needed = ADD; | ||
891 | dev->fsa_dev[container].config_waiting_on = | ||
892 | AifEnConfigChange; | ||
893 | break; | ||
894 | |||
895 | /* | ||
896 | * Delete an Array. | ||
897 | */ | ||
898 | case AifEnDeleteContainer: | ||
899 | container = le32_to_cpu(((u32 *)aifcmd->data)[1]); | ||
900 | if (container >= dev->maximum_num_containers) | ||
901 | break; | ||
902 | dev->fsa_dev[container].config_needed = DELETE; | ||
903 | dev->fsa_dev[container].config_waiting_on = | ||
904 | AifEnConfigChange; | ||
905 | break; | ||
906 | |||
907 | /* | ||
908 | * Container change detected. If we currently are not | ||
909 | * waiting on something else, setup to wait on a Config Change. | ||
910 | */ | ||
911 | case AifEnContainerChange: | ||
912 | container = le32_to_cpu(((u32 *)aifcmd->data)[1]); | ||
913 | if (container >= dev->maximum_num_containers) | ||
914 | break; | ||
915 | if (dev->fsa_dev[container].config_waiting_on) | ||
916 | break; | ||
917 | dev->fsa_dev[container].config_needed = CHANGE; | ||
918 | dev->fsa_dev[container].config_waiting_on = | ||
919 | AifEnConfigChange; | ||
920 | break; | ||
921 | |||
922 | case AifEnConfigChange: | ||
923 | break; | ||
924 | |||
925 | } | ||
926 | |||
927 | /* | ||
928 | * If we are waiting on something and this happens to be | ||
929 | * that thing then set the re-configure flag. | ||
930 | */ | ||
931 | if (container != (u32)-1) { | ||
932 | if (container >= dev->maximum_num_containers) | ||
933 | break; | ||
934 | if (dev->fsa_dev[container].config_waiting_on == | ||
935 | le32_to_cpu(*(u32 *)aifcmd->data)) | ||
936 | dev->fsa_dev[container].config_waiting_on = 0; | ||
937 | } else for (container = 0; | ||
938 | container < dev->maximum_num_containers; ++container) { | ||
939 | if (dev->fsa_dev[container].config_waiting_on == | ||
940 | le32_to_cpu(*(u32 *)aifcmd->data)) | ||
941 | dev->fsa_dev[container].config_waiting_on = 0; | ||
942 | } | ||
943 | break; | ||
944 | |||
945 | case AifCmdJobProgress: | ||
946 | /* | ||
947 | * These are job progress AIF's. When a Clear is being | ||
948 | * done on a container it is initially created then hidden from | ||
949 | * the OS. When the clear completes we don't get a config | ||
950 | * change so we monitor the job status complete on a clear then | ||
951 | * wait for a container change. | ||
952 | */ | ||
953 | |||
954 | if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero)) | ||
955 | && ((((u32 *)aifcmd->data)[6] == ((u32 *)aifcmd->data)[5]) | ||
956 | || (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsSuccess)))) { | ||
957 | for (container = 0; | ||
958 | container < dev->maximum_num_containers; | ||
959 | ++container) { | ||
960 | /* | ||
961 | * Stomp on all config sequencing for all | ||
962 | * containers? | ||
963 | */ | ||
964 | dev->fsa_dev[container].config_waiting_on = | ||
965 | AifEnContainerChange; | ||
966 | dev->fsa_dev[container].config_needed = ADD; | ||
967 | } | ||
968 | } | ||
969 | if ((((u32 *)aifcmd->data)[1] == cpu_to_le32(AifJobCtrZero)) | ||
970 | && (((u32 *)aifcmd->data)[6] == 0) | ||
971 | && (((u32 *)aifcmd->data)[4] == cpu_to_le32(AifJobStsRunning))) { | ||
972 | for (container = 0; | ||
973 | container < dev->maximum_num_containers; | ||
974 | ++container) { | ||
975 | /* | ||
976 | * Stomp on all config sequencing for all | ||
977 | * containers? | ||
978 | */ | ||
979 | dev->fsa_dev[container].config_waiting_on = | ||
980 | AifEnContainerChange; | ||
981 | dev->fsa_dev[container].config_needed = DELETE; | ||
982 | } | ||
983 | } | ||
984 | break; | ||
985 | } | ||
986 | |||
987 | device_config_needed = NOTHING; | ||
988 | for (container = 0; container < dev->maximum_num_containers; | ||
989 | ++container) { | ||
990 | if ((dev->fsa_dev[container].config_waiting_on == 0) | ||
991 | && (dev->fsa_dev[container].config_needed != NOTHING)) { | ||
992 | device_config_needed = | ||
993 | dev->fsa_dev[container].config_needed; | ||
994 | dev->fsa_dev[container].config_needed = NOTHING; | ||
995 | break; | ||
996 | } | ||
997 | } | ||
998 | if (device_config_needed == NOTHING) | ||
999 | return; | ||
1000 | |||
1001 | /* | ||
1002 | * If we decided that a re-configuration needs to be done, | ||
1003 | * schedule it here on the way out the door, please close the door | ||
1004 | * behind you. | ||
1005 | */ | ||
1006 | |||
1007 | busy = 0; | ||
1008 | |||
1009 | |||
1010 | /* | ||
1011 | * Find the Scsi_Device associated with the SCSI address, | ||
1012 | * and mark it as changed, invalidating the cache. This deals | ||
1013 | * with changes to existing device IDs. | ||
1014 | */ | ||
1015 | |||
1016 | if (!dev || !dev->scsi_host_ptr) | ||
1017 | return; | ||
1018 | /* | ||
1019 | * force reload of disk info via probe_container | ||
1020 | */ | ||
1021 | if ((device_config_needed == CHANGE) | ||
1022 | && (dev->fsa_dev[container].valid == 1)) | ||
1023 | dev->fsa_dev[container].valid = 2; | ||
1024 | if ((device_config_needed == CHANGE) || | ||
1025 | (device_config_needed == ADD)) | ||
1026 | probe_container(dev, container); | ||
1027 | device = scsi_device_lookup(dev->scsi_host_ptr, | ||
1028 | CONTAINER_TO_CHANNEL(container), | ||
1029 | CONTAINER_TO_ID(container), | ||
1030 | CONTAINER_TO_LUN(container)); | ||
1031 | if (device) { | ||
1032 | switch (device_config_needed) { | ||
1033 | case DELETE: | ||
1034 | scsi_remove_device(device); | ||
1035 | break; | ||
1036 | case CHANGE: | ||
1037 | if (!dev->fsa_dev[container].valid) { | ||
1038 | scsi_remove_device(device); | ||
1039 | break; | ||
1040 | } | ||
1041 | scsi_rescan_device(&device->sdev_gendev); | ||
1042 | |||
1043 | default: | ||
1044 | break; | ||
1045 | } | ||
1046 | scsi_device_put(device); | ||
1047 | } | ||
1048 | if (device_config_needed == ADD) { | ||
1049 | scsi_add_device(dev->scsi_host_ptr, | ||
1050 | CONTAINER_TO_CHANNEL(container), | ||
1051 | CONTAINER_TO_ID(container), | ||
1052 | CONTAINER_TO_LUN(container)); | ||
1053 | } | ||
1054 | |||
1055 | } | ||
1056 | |||
794 | /** | 1057 | /** |
795 | * aac_command_thread - command processing thread | 1058 | * aac_command_thread - command processing thread |
796 | * @dev: Adapter to monitor | 1059 | * @dev: Adapter to monitor |
@@ -860,6 +1123,7 @@ int aac_command_thread(struct aac_dev * dev) | |||
860 | aifcmd = (struct aac_aifcmd *) hw_fib->data; | 1123 | aifcmd = (struct aac_aifcmd *) hw_fib->data; |
861 | if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) { | 1124 | if (aifcmd->command == cpu_to_le32(AifCmdDriverNotify)) { |
862 | /* Handle Driver Notify Events */ | 1125 | /* Handle Driver Notify Events */ |
1126 | aac_handle_aif(dev, fib); | ||
863 | *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); | 1127 | *(__le32 *)hw_fib->data = cpu_to_le32(ST_OK); |
864 | fib_adapter_complete(fib, (u16)sizeof(u32)); | 1128 | fib_adapter_complete(fib, (u16)sizeof(u32)); |
865 | } else { | 1129 | } else { |
@@ -872,7 +1136,15 @@ int aac_command_thread(struct aac_dev * dev) | |||
872 | unsigned num; | 1136 | unsigned num; |
873 | struct hw_fib ** hw_fib_pool, ** hw_fib_p; | 1137 | struct hw_fib ** hw_fib_pool, ** hw_fib_p; |
874 | struct fib ** fib_pool, ** fib_p; | 1138 | struct fib ** fib_pool, ** fib_p; |
875 | 1139 | ||
1140 | /* Sniff events */ | ||
1141 | if ((aifcmd->command == | ||
1142 | cpu_to_le32(AifCmdEventNotify)) || | ||
1143 | (aifcmd->command == | ||
1144 | cpu_to_le32(AifCmdJobProgress))) { | ||
1145 | aac_handle_aif(dev, fib); | ||
1146 | } | ||
1147 | |||
876 | time_now = jiffies/HZ; | 1148 | time_now = jiffies/HZ; |
877 | 1149 | ||
878 | /* | 1150 | /* |