Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

[SCSI] mptfc: correct out of order event processing

This patch corrects a problem in mptfc which can result in targets
being removed after executing an "lsiutil 99" reset of the fibre
channel ports.

The last rescan event was being processed before the setup reset work
due to an inappropriate optimization in the event processing logic.
Every rescan event is now queued for execution and the setup reset
work now executes in the proper sequence.

Signed-off-by: Michael Reed <mdr@sgi.com>
Acked-by: Moore, Eric <Eric.Moore@lsil.com>
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>

authored by

Michael Reed and committed by
James Bottomley
3a0c56d8 77d88ee2

+37 -57
-1
drivers/message/fusion/mptbase.h
··· 640 640 struct work_struct fc_setup_reset_work; 641 641 struct list_head fc_rports; 642 642 spinlock_t fc_rescan_work_lock; 643 - int fc_rescan_work_count; 644 643 struct work_struct fc_rescan_work; 645 644 char fc_rescan_work_q_name[KOBJ_NAME_LEN]; 646 645 struct workqueue_struct *fc_rescan_work_q;
+37 -56
drivers/message/fusion/mptfc.c
··· 898 898 { 899 899 MPT_ADAPTER *ioc = (MPT_ADAPTER *)arg; 900 900 int ii; 901 - int work_to_do; 902 901 u64 pn; 903 - unsigned long flags; 904 902 struct mptfc_rport_info *ri; 905 903 906 - do { 907 - /* start by tagging all ports as missing */ 908 - list_for_each_entry(ri, &ioc->fc_rports, list) { 909 - if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { 910 - ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; 911 - } 904 + /* start by tagging all ports as missing */ 905 + list_for_each_entry(ri, &ioc->fc_rports, list) { 906 + if (ri->flags & MPT_RPORT_INFO_FLAGS_REGISTERED) { 907 + ri->flags |= MPT_RPORT_INFO_FLAGS_MISSING; 912 908 } 909 + } 913 910 914 - /* 915 - * now rescan devices known to adapter, 916 - * will reregister existing rports 917 - */ 918 - for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { 919 - (void) mptfc_GetFcPortPage0(ioc, ii); 920 - mptfc_init_host_attr(ioc,ii); /* refresh */ 921 - mptfc_GetFcDevPage0(ioc,ii,mptfc_register_dev); 911 + /* 912 + * now rescan devices known to adapter, 913 + * will reregister existing rports 914 + */ 915 + for (ii=0; ii < ioc->facts.NumberOfPorts; ii++) { 916 + (void) mptfc_GetFcPortPage0(ioc, ii); 917 + mptfc_init_host_attr(ioc, ii); /* refresh */ 918 + mptfc_GetFcDevPage0(ioc, ii, mptfc_register_dev); 919 + } 920 + 921 + /* delete devices still missing */ 922 + list_for_each_entry(ri, &ioc->fc_rports, list) { 923 + /* if newly missing, delete it */ 924 + if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { 925 + 926 + ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| 927 + MPT_RPORT_INFO_FLAGS_MISSING); 928 + fc_remote_port_delete(ri->rport); /* won't sleep */ 929 + ri->rport = NULL; 930 + 931 + pn = (u64)ri->pg0.WWPN.High << 32 | 932 + (u64)ri->pg0.WWPN.Low; 933 + dfcprintk ((MYIOC_s_INFO_FMT 934 + "mptfc_rescan.%d: %llx deleted\n", 935 + ioc->name, 936 + ioc->sh->host_no, 937 + (unsigned long long)pn)); 922 938 } 923 - 924 - /* delete devices still missing */ 925 - list_for_each_entry(ri, &ioc->fc_rports, list) { 926 - /* if newly missing, delete it */ 927 - if (ri->flags & MPT_RPORT_INFO_FLAGS_MISSING) { 928 - 929 - ri->flags &= ~(MPT_RPORT_INFO_FLAGS_REGISTERED| 930 - MPT_RPORT_INFO_FLAGS_MISSING); 931 - fc_remote_port_delete(ri->rport); /* won't sleep */ 932 - ri->rport = NULL; 933 - 934 - pn = (u64)ri->pg0.WWPN.High << 32 | 935 - (u64)ri->pg0.WWPN.Low; 936 - dfcprintk ((MYIOC_s_INFO_FMT 937 - "mptfc_rescan.%d: %llx deleted\n", 938 - ioc->name, 939 - ioc->sh->host_no, 940 - (unsigned long long)pn)); 941 - } 942 - } 943 - 944 - /* 945 - * allow multiple passes as target state 946 - * might have changed during scan 947 - */ 948 - spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); 949 - if (ioc->fc_rescan_work_count > 2) /* only need one more */ 950 - ioc->fc_rescan_work_count = 2; 951 - work_to_do = --ioc->fc_rescan_work_count; 952 - spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); 953 - } while (work_to_do); 939 + } 954 940 } 955 941 956 942 static int ··· 1148 1162 * by doing it via the workqueue, some locking is eliminated 1149 1163 */ 1150 1164 1151 - ioc->fc_rescan_work_count = 1; 1152 1165 queue_work(ioc->fc_rescan_work_q, &ioc->fc_rescan_work); 1153 1166 flush_workqueue(ioc->fc_rescan_work_q); 1154 1167 ··· 1190 1205 case MPI_EVENT_RESCAN: 1191 1206 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); 1192 1207 if (ioc->fc_rescan_work_q) { 1193 - if (ioc->fc_rescan_work_count++ == 0) { 1194 - queue_work(ioc->fc_rescan_work_q, 1195 - &ioc->fc_rescan_work); 1196 - } 1208 + queue_work(ioc->fc_rescan_work_q, 1209 + &ioc->fc_rescan_work); 1197 1210 } 1198 1211 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); 1199 1212 break; ··· 1234 1251 mptfc_SetFcPortPage1_defaults(ioc); 1235 1252 spin_lock_irqsave(&ioc->fc_rescan_work_lock, flags); 1236 1253 if (ioc->fc_rescan_work_q) { 1237 - if (ioc->fc_rescan_work_count++ == 0) { 1238 - queue_work(ioc->fc_rescan_work_q, 1239 - &ioc->fc_rescan_work); 1240 - } 1254 + queue_work(ioc->fc_rescan_work_q, 1255 + &ioc->fc_rescan_work); 1241 1256 } 1242 1257 spin_unlock_irqrestore(&ioc->fc_rescan_work_lock, flags); 1243 1258 }