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 | |
| 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>
| -rw-r--r-- | drivers/scsi/aacraid/aachba.c | 4 | ||||
| -rw-r--r-- | drivers/scsi/aacraid/aacraid.h | 4 | ||||
| -rw-r--r-- | drivers/scsi/aacraid/commsup.c | 274 |
3 files changed, 280 insertions, 2 deletions
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c index 0a209b2cd695..85d133c40bd3 100644 --- a/drivers/scsi/aacraid/aachba.c +++ b/drivers/scsi/aacraid/aachba.c | |||
| @@ -479,7 +479,7 @@ static int aac_get_container_name(struct scsi_cmnd * scsicmd, int cid) | |||
| 479 | * is updated in the struct fsa_dev_info structure rather than returned. | 479 | * is updated in the struct fsa_dev_info structure rather than returned. |
| 480 | */ | 480 | */ |
| 481 | 481 | ||
| 482 | static int probe_container(struct aac_dev *dev, int cid) | 482 | int probe_container(struct aac_dev *dev, int cid) |
| 483 | { | 483 | { |
| 484 | struct fsa_dev_info *fsa_dev_ptr; | 484 | struct fsa_dev_info *fsa_dev_ptr; |
| 485 | int status; | 485 | int status; |
| @@ -1471,6 +1471,8 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd) | |||
| 1471 | case TEST_UNIT_READY: | 1471 | case TEST_UNIT_READY: |
| 1472 | spin_unlock_irq(host->host_lock); | 1472 | spin_unlock_irq(host->host_lock); |
| 1473 | probe_container(dev, cid); | 1473 | probe_container(dev, cid); |
| 1474 | if ((fsa_dev_ptr[cid].valid & 1) == 0) | ||
| 1475 | fsa_dev_ptr[cid].valid = 0; | ||
| 1474 | spin_lock_irq(host->host_lock); | 1476 | spin_lock_irq(host->host_lock); |
| 1475 | if (fsa_dev_ptr[cid].valid == 0) { | 1477 | if (fsa_dev_ptr[cid].valid == 0) { |
| 1476 | scsicmd->result = DID_NO_CONNECT << 16; | 1478 | scsicmd->result = DID_NO_CONNECT << 16; |
diff --git a/drivers/scsi/aacraid/aacraid.h b/drivers/scsi/aacraid/aacraid.h index 6fd5074efa5c..0880f4807fc9 100644 --- a/drivers/scsi/aacraid/aacraid.h +++ b/drivers/scsi/aacraid/aacraid.h | |||
| @@ -780,7 +780,9 @@ struct fsa_dev_info { | |||
| 780 | u64 last; | 780 | u64 last; |
| 781 | u64 size; | 781 | u64 size; |
| 782 | u32 type; | 782 | u32 type; |
| 783 | u32 config_waiting_on; | ||
| 783 | u16 queue_depth; | 784 | u16 queue_depth; |
| 785 | u8 config_needed; | ||
| 784 | u8 valid; | 786 | u8 valid; |
| 785 | u8 ro; | 787 | u8 ro; |
| 786 | u8 locked; | 788 | u8 locked; |
| @@ -1715,6 +1717,7 @@ extern struct aac_common aac_config; | |||
| 1715 | #define AifCmdJobProgress 2 /* Progress report */ | 1717 | #define AifCmdJobProgress 2 /* Progress report */ |
| 1716 | #define AifJobCtrZero 101 /* Array Zero progress */ | 1718 | #define AifJobCtrZero 101 /* Array Zero progress */ |
| 1717 | #define AifJobStsSuccess 1 /* Job completes */ | 1719 | #define AifJobStsSuccess 1 /* Job completes */ |
| 1720 | #define AifJobStsRunning 102 /* Job running */ | ||
| 1718 | #define AifCmdAPIReport 3 /* Report from other user of API */ | 1721 | #define AifCmdAPIReport 3 /* Report from other user of API */ |
| 1719 | #define AifCmdDriverNotify 4 /* Notify host driver of event */ | 1722 | #define AifCmdDriverNotify 4 /* Notify host driver of event */ |
| 1720 | #define AifDenMorphComplete 200 /* A morph operation completed */ | 1723 | #define AifDenMorphComplete 200 /* A morph operation completed */ |
| @@ -1785,6 +1788,7 @@ int fib_adapter_complete(struct fib * fibptr, unsigned short size); | |||
| 1785 | struct aac_driver_ident* aac_get_driver_ident(int devtype); | 1788 | struct aac_driver_ident* aac_get_driver_ident(int devtype); |
| 1786 | int aac_get_adapter_info(struct aac_dev* dev); | 1789 | int aac_get_adapter_info(struct aac_dev* dev); |
| 1787 | int aac_send_shutdown(struct aac_dev *dev); | 1790 | int aac_send_shutdown(struct aac_dev *dev); |
| 1791 | int probe_container(struct aac_dev *dev, int cid); | ||
| 1788 | extern int numacb; | 1792 | extern int numacb; |
| 1789 | extern int acbsize; | 1793 | extern int acbsize; |
| 1790 | extern char aac_driver_version[]; | 1794 | extern char aac_driver_version[]; |
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 | /* |
