xref: /OK3568_Linux_fs/kernel/drivers/message/fusion/mptsas.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun /*
2*4882a593Smuzhiyun  *  linux/drivers/message/fusion/mptsas.c
3*4882a593Smuzhiyun  *      For use with LSI PCI chip/adapter(s)
4*4882a593Smuzhiyun  *      running LSI Fusion MPT (Message Passing Technology) firmware.
5*4882a593Smuzhiyun  *
6*4882a593Smuzhiyun  *  Copyright (c) 1999-2008 LSI Corporation
7*4882a593Smuzhiyun  *  (mailto:DL-MPTFusionLinux@lsi.com)
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10*4882a593Smuzhiyun /*
11*4882a593Smuzhiyun     This program is free software; you can redistribute it and/or modify
12*4882a593Smuzhiyun     it under the terms of the GNU General Public License as published by
13*4882a593Smuzhiyun     the Free Software Foundation; version 2 of the License.
14*4882a593Smuzhiyun 
15*4882a593Smuzhiyun     This program is distributed in the hope that it will be useful,
16*4882a593Smuzhiyun     but WITHOUT ANY WARRANTY; without even the implied warranty of
17*4882a593Smuzhiyun     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18*4882a593Smuzhiyun     GNU General Public License for more details.
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun     NO WARRANTY
21*4882a593Smuzhiyun     THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22*4882a593Smuzhiyun     CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23*4882a593Smuzhiyun     LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24*4882a593Smuzhiyun     MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25*4882a593Smuzhiyun     solely responsible for determining the appropriateness of using and
26*4882a593Smuzhiyun     distributing the Program and assumes all risks associated with its
27*4882a593Smuzhiyun     exercise of rights under this Agreement, including but not limited to
28*4882a593Smuzhiyun     the risks and costs of program errors, damage to or loss of data,
29*4882a593Smuzhiyun     programs or equipment, and unavailability or interruption of operations.
30*4882a593Smuzhiyun 
31*4882a593Smuzhiyun     DISCLAIMER OF LIABILITY
32*4882a593Smuzhiyun     NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33*4882a593Smuzhiyun     DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34*4882a593Smuzhiyun     DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35*4882a593Smuzhiyun     ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36*4882a593Smuzhiyun     TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37*4882a593Smuzhiyun     USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38*4882a593Smuzhiyun     HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39*4882a593Smuzhiyun 
40*4882a593Smuzhiyun     You should have received a copy of the GNU General Public License
41*4882a593Smuzhiyun     along with this program; if not, write to the Free Software
42*4882a593Smuzhiyun     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
43*4882a593Smuzhiyun */
44*4882a593Smuzhiyun /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #include <linux/module.h>
47*4882a593Smuzhiyun #include <linux/kernel.h>
48*4882a593Smuzhiyun #include <linux/slab.h>
49*4882a593Smuzhiyun #include <linux/init.h>
50*4882a593Smuzhiyun #include <linux/errno.h>
51*4882a593Smuzhiyun #include <linux/jiffies.h>
52*4882a593Smuzhiyun #include <linux/workqueue.h>
53*4882a593Smuzhiyun #include <linux/delay.h>	/* for mdelay */
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun #include <scsi/scsi.h>
56*4882a593Smuzhiyun #include <scsi/scsi_cmnd.h>
57*4882a593Smuzhiyun #include <scsi/scsi_device.h>
58*4882a593Smuzhiyun #include <scsi/scsi_host.h>
59*4882a593Smuzhiyun #include <scsi/scsi_transport_sas.h>
60*4882a593Smuzhiyun #include <scsi/scsi_transport.h>
61*4882a593Smuzhiyun #include <scsi/scsi_dbg.h>
62*4882a593Smuzhiyun 
63*4882a593Smuzhiyun #include "mptbase.h"
64*4882a593Smuzhiyun #include "mptscsih.h"
65*4882a593Smuzhiyun #include "mptsas.h"
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun 
68*4882a593Smuzhiyun #define my_NAME		"Fusion MPT SAS Host driver"
69*4882a593Smuzhiyun #define my_VERSION	MPT_LINUX_VERSION_COMMON
70*4882a593Smuzhiyun #define MYNAM		"mptsas"
71*4882a593Smuzhiyun 
72*4882a593Smuzhiyun /*
73*4882a593Smuzhiyun  * Reserved channel for integrated raid
74*4882a593Smuzhiyun  */
75*4882a593Smuzhiyun #define MPTSAS_RAID_CHANNEL	1
76*4882a593Smuzhiyun 
77*4882a593Smuzhiyun #define SAS_CONFIG_PAGE_TIMEOUT		30
78*4882a593Smuzhiyun MODULE_AUTHOR(MODULEAUTHOR);
79*4882a593Smuzhiyun MODULE_DESCRIPTION(my_NAME);
80*4882a593Smuzhiyun MODULE_LICENSE("GPL");
81*4882a593Smuzhiyun MODULE_VERSION(my_VERSION);
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static int mpt_pt_clear;
84*4882a593Smuzhiyun module_param(mpt_pt_clear, int, 0);
85*4882a593Smuzhiyun MODULE_PARM_DESC(mpt_pt_clear,
86*4882a593Smuzhiyun 		" Clear persistency table: enable=1  "
87*4882a593Smuzhiyun 		"(default=MPTSCSIH_PT_CLEAR=0)");
88*4882a593Smuzhiyun 
89*4882a593Smuzhiyun /* scsi-mid layer global parmeter is max_report_luns, which is 511 */
90*4882a593Smuzhiyun #define MPTSAS_MAX_LUN (16895)
91*4882a593Smuzhiyun static int max_lun = MPTSAS_MAX_LUN;
92*4882a593Smuzhiyun module_param(max_lun, int, 0);
93*4882a593Smuzhiyun MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
94*4882a593Smuzhiyun 
95*4882a593Smuzhiyun static int mpt_loadtime_max_sectors = 8192;
96*4882a593Smuzhiyun module_param(mpt_loadtime_max_sectors, int, 0);
97*4882a593Smuzhiyun MODULE_PARM_DESC(mpt_loadtime_max_sectors,
98*4882a593Smuzhiyun 		" Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192");
99*4882a593Smuzhiyun 
100*4882a593Smuzhiyun static u8	mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
101*4882a593Smuzhiyun static u8	mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
102*4882a593Smuzhiyun static u8	mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
103*4882a593Smuzhiyun static u8	mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
104*4882a593Smuzhiyun static u8	mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun static void mptsas_firmware_event_work(struct work_struct *work);
107*4882a593Smuzhiyun static void mptsas_send_sas_event(struct fw_event_work *fw_event);
108*4882a593Smuzhiyun static void mptsas_send_raid_event(struct fw_event_work *fw_event);
109*4882a593Smuzhiyun static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
110*4882a593Smuzhiyun static void mptsas_parse_device_info(struct sas_identify *identify,
111*4882a593Smuzhiyun 		struct mptsas_devinfo *device_info);
112*4882a593Smuzhiyun static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
113*4882a593Smuzhiyun 		struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
114*4882a593Smuzhiyun static struct mptsas_phyinfo	*mptsas_find_phyinfo_by_sas_address
115*4882a593Smuzhiyun 		(MPT_ADAPTER *ioc, u64 sas_address);
116*4882a593Smuzhiyun static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
117*4882a593Smuzhiyun 	struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
118*4882a593Smuzhiyun static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
119*4882a593Smuzhiyun 	struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
120*4882a593Smuzhiyun static int mptsas_add_end_device(MPT_ADAPTER *ioc,
121*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info);
122*4882a593Smuzhiyun static void mptsas_del_end_device(MPT_ADAPTER *ioc,
123*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info);
124*4882a593Smuzhiyun static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
125*4882a593Smuzhiyun static struct mptsas_portinfo	*mptsas_find_portinfo_by_sas_address
126*4882a593Smuzhiyun 		(MPT_ADAPTER *ioc, u64 sas_address);
127*4882a593Smuzhiyun static void mptsas_expander_delete(MPT_ADAPTER *ioc,
128*4882a593Smuzhiyun 		struct mptsas_portinfo *port_info, u8 force);
129*4882a593Smuzhiyun static void mptsas_send_expander_event(struct fw_event_work *fw_event);
130*4882a593Smuzhiyun static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
131*4882a593Smuzhiyun static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
132*4882a593Smuzhiyun static void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event);
133*4882a593Smuzhiyun static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
134*4882a593Smuzhiyun static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
135*4882a593Smuzhiyun void	mptsas_schedule_target_reset(void *ioc);
136*4882a593Smuzhiyun 
mptsas_print_phy_data(MPT_ADAPTER * ioc,MPI_SAS_IO_UNIT0_PHY_DATA * phy_data)137*4882a593Smuzhiyun static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
138*4882a593Smuzhiyun 					MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
139*4882a593Smuzhiyun {
140*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
141*4882a593Smuzhiyun 	    "---- IO UNIT PAGE 0 ------------\n", ioc->name));
142*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
143*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
144*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
145*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
146*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
147*4882a593Smuzhiyun 	    ioc->name, phy_data->Port));
148*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
149*4882a593Smuzhiyun 	    ioc->name, phy_data->PortFlags));
150*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
151*4882a593Smuzhiyun 	    ioc->name, phy_data->PhyFlags));
152*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
153*4882a593Smuzhiyun 	    ioc->name, phy_data->NegotiatedLinkRate));
154*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
155*4882a593Smuzhiyun 	    "Controller PHY Device Info=0x%X\n", ioc->name,
156*4882a593Smuzhiyun 	    le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
157*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
158*4882a593Smuzhiyun 	    ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
mptsas_print_phy_pg0(MPT_ADAPTER * ioc,SasPhyPage0_t * pg0)161*4882a593Smuzhiyun static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
162*4882a593Smuzhiyun {
163*4882a593Smuzhiyun 	__le64 sas_address;
164*4882a593Smuzhiyun 
165*4882a593Smuzhiyun 	memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
168*4882a593Smuzhiyun 	    "---- SAS PHY PAGE 0 ------------\n", ioc->name));
169*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
170*4882a593Smuzhiyun 	    "Attached Device Handle=0x%X\n", ioc->name,
171*4882a593Smuzhiyun 	    le16_to_cpu(pg0->AttachedDevHandle)));
172*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
173*4882a593Smuzhiyun 	    ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
174*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
175*4882a593Smuzhiyun 	    "Attached PHY Identifier=0x%X\n", ioc->name,
176*4882a593Smuzhiyun 	    pg0->AttachedPhyIdentifier));
177*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
178*4882a593Smuzhiyun 	    ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
179*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
180*4882a593Smuzhiyun 	    ioc->name,  pg0->ProgrammedLinkRate));
181*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
182*4882a593Smuzhiyun 	    ioc->name, pg0->ChangeCount));
183*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
184*4882a593Smuzhiyun 	    ioc->name, le32_to_cpu(pg0->PhyInfo)));
185*4882a593Smuzhiyun }
186*4882a593Smuzhiyun 
mptsas_print_phy_pg1(MPT_ADAPTER * ioc,SasPhyPage1_t * pg1)187*4882a593Smuzhiyun static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
188*4882a593Smuzhiyun {
189*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
190*4882a593Smuzhiyun 	    "---- SAS PHY PAGE 1 ------------\n", ioc->name));
191*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
192*4882a593Smuzhiyun 	    ioc->name,  pg1->InvalidDwordCount));
193*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
194*4882a593Smuzhiyun 	    "Running Disparity Error Count=0x%x\n", ioc->name,
195*4882a593Smuzhiyun 	    pg1->RunningDisparityErrorCount));
196*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
197*4882a593Smuzhiyun 	    "Loss Dword Synch Count=0x%x\n", ioc->name,
198*4882a593Smuzhiyun 	    pg1->LossDwordSynchCount));
199*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
200*4882a593Smuzhiyun 	    "PHY Reset Problem Count=0x%x\n\n", ioc->name,
201*4882a593Smuzhiyun 	    pg1->PhyResetProblemCount));
202*4882a593Smuzhiyun }
203*4882a593Smuzhiyun 
mptsas_print_device_pg0(MPT_ADAPTER * ioc,SasDevicePage0_t * pg0)204*4882a593Smuzhiyun static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	__le64 sas_address;
207*4882a593Smuzhiyun 
208*4882a593Smuzhiyun 	memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
211*4882a593Smuzhiyun 	    "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
212*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
213*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg0->DevHandle)));
214*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
215*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
216*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
217*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
218*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
219*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg0->Slot)));
220*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
221*4882a593Smuzhiyun 	    ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
222*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
223*4882a593Smuzhiyun 	    ioc->name, pg0->TargetID));
224*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
225*4882a593Smuzhiyun 	    ioc->name, pg0->Bus));
226*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
227*4882a593Smuzhiyun 	    ioc->name, pg0->PhyNum));
228*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
229*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg0->AccessStatus)));
230*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
231*4882a593Smuzhiyun 	    ioc->name, le32_to_cpu(pg0->DeviceInfo)));
232*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
233*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg0->Flags)));
234*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
235*4882a593Smuzhiyun 	    ioc->name, pg0->PhysicalPort));
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
mptsas_print_expander_pg1(MPT_ADAPTER * ioc,SasExpanderPage1_t * pg1)238*4882a593Smuzhiyun static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
241*4882a593Smuzhiyun 	    "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
242*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
243*4882a593Smuzhiyun 	    ioc->name, pg1->PhysicalPort));
244*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
245*4882a593Smuzhiyun 	    ioc->name, pg1->PhyIdentifier));
246*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
247*4882a593Smuzhiyun 	    ioc->name, pg1->NegotiatedLinkRate));
248*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
249*4882a593Smuzhiyun 	    ioc->name, pg1->ProgrammedLinkRate));
250*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
251*4882a593Smuzhiyun 	    ioc->name, pg1->HwLinkRate));
252*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
253*4882a593Smuzhiyun 	    ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
254*4882a593Smuzhiyun 	dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
255*4882a593Smuzhiyun 	    "Attached Device Handle=0x%X\n\n", ioc->name,
256*4882a593Smuzhiyun 	    le16_to_cpu(pg1->AttachedDevHandle)));
257*4882a593Smuzhiyun }
258*4882a593Smuzhiyun 
259*4882a593Smuzhiyun /* inhibit sas firmware event handling */
260*4882a593Smuzhiyun static void
mptsas_fw_event_off(MPT_ADAPTER * ioc)261*4882a593Smuzhiyun mptsas_fw_event_off(MPT_ADAPTER *ioc)
262*4882a593Smuzhiyun {
263*4882a593Smuzhiyun 	unsigned long flags;
264*4882a593Smuzhiyun 
265*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->fw_event_lock, flags);
266*4882a593Smuzhiyun 	ioc->fw_events_off = 1;
267*4882a593Smuzhiyun 	ioc->sas_discovery_quiesce_io = 0;
268*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
269*4882a593Smuzhiyun 
270*4882a593Smuzhiyun }
271*4882a593Smuzhiyun 
272*4882a593Smuzhiyun /* enable sas firmware event handling */
273*4882a593Smuzhiyun static void
mptsas_fw_event_on(MPT_ADAPTER * ioc)274*4882a593Smuzhiyun mptsas_fw_event_on(MPT_ADAPTER *ioc)
275*4882a593Smuzhiyun {
276*4882a593Smuzhiyun 	unsigned long flags;
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->fw_event_lock, flags);
279*4882a593Smuzhiyun 	ioc->fw_events_off = 0;
280*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
281*4882a593Smuzhiyun }
282*4882a593Smuzhiyun 
283*4882a593Smuzhiyun /* queue a sas firmware event */
284*4882a593Smuzhiyun static void
mptsas_add_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event,unsigned long delay)285*4882a593Smuzhiyun mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
286*4882a593Smuzhiyun     unsigned long delay)
287*4882a593Smuzhiyun {
288*4882a593Smuzhiyun 	unsigned long flags;
289*4882a593Smuzhiyun 
290*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->fw_event_lock, flags);
291*4882a593Smuzhiyun 	list_add_tail(&fw_event->list, &ioc->fw_event_list);
292*4882a593Smuzhiyun 	INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
293*4882a593Smuzhiyun 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)"
294*4882a593Smuzhiyun 		"on cpuid %d\n", ioc->name, __func__,
295*4882a593Smuzhiyun 		fw_event, smp_processor_id()));
296*4882a593Smuzhiyun 	queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q,
297*4882a593Smuzhiyun 	    &fw_event->work, delay);
298*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
299*4882a593Smuzhiyun }
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun /* requeue a sas firmware event */
302*4882a593Smuzhiyun static void
mptsas_requeue_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event,unsigned long delay)303*4882a593Smuzhiyun mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
304*4882a593Smuzhiyun     unsigned long delay)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun 	unsigned long flags;
307*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->fw_event_lock, flags);
308*4882a593Smuzhiyun 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
309*4882a593Smuzhiyun 	    "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__,
310*4882a593Smuzhiyun 		fw_event, smp_processor_id()));
311*4882a593Smuzhiyun 	fw_event->retries++;
312*4882a593Smuzhiyun 	queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q,
313*4882a593Smuzhiyun 	    &fw_event->work, msecs_to_jiffies(delay));
314*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
315*4882a593Smuzhiyun }
316*4882a593Smuzhiyun 
317*4882a593Smuzhiyun /* free memory associated to a sas firmware event */
318*4882a593Smuzhiyun static void
mptsas_free_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event)319*4882a593Smuzhiyun mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
320*4882a593Smuzhiyun {
321*4882a593Smuzhiyun 	unsigned long flags;
322*4882a593Smuzhiyun 
323*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->fw_event_lock, flags);
324*4882a593Smuzhiyun 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
325*4882a593Smuzhiyun 	    ioc->name, __func__, fw_event));
326*4882a593Smuzhiyun 	list_del(&fw_event->list);
327*4882a593Smuzhiyun 	kfree(fw_event);
328*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
329*4882a593Smuzhiyun }
330*4882a593Smuzhiyun 
331*4882a593Smuzhiyun /* walk the firmware event queue, and either stop or wait for
332*4882a593Smuzhiyun  * outstanding events to complete */
333*4882a593Smuzhiyun static void
mptsas_cleanup_fw_event_q(MPT_ADAPTER * ioc)334*4882a593Smuzhiyun mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun 	struct fw_event_work *fw_event, *next;
337*4882a593Smuzhiyun 	struct mptsas_target_reset_event *target_reset_list, *n;
338*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
339*4882a593Smuzhiyun 
340*4882a593Smuzhiyun 	/* flush the target_reset_list */
341*4882a593Smuzhiyun 	if (!list_empty(&hd->target_reset_list)) {
342*4882a593Smuzhiyun 		list_for_each_entry_safe(target_reset_list, n,
343*4882a593Smuzhiyun 		    &hd->target_reset_list, list) {
344*4882a593Smuzhiyun 			dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
345*4882a593Smuzhiyun 			    "%s: removing target reset for id=%d\n",
346*4882a593Smuzhiyun 			    ioc->name, __func__,
347*4882a593Smuzhiyun 			   target_reset_list->sas_event_data.TargetID));
348*4882a593Smuzhiyun 			list_del(&target_reset_list->list);
349*4882a593Smuzhiyun 			kfree(target_reset_list);
350*4882a593Smuzhiyun 		}
351*4882a593Smuzhiyun 	}
352*4882a593Smuzhiyun 
353*4882a593Smuzhiyun 	if (list_empty(&ioc->fw_event_list) ||
354*4882a593Smuzhiyun 	     !ioc->fw_event_q || in_interrupt())
355*4882a593Smuzhiyun 		return;
356*4882a593Smuzhiyun 
357*4882a593Smuzhiyun 	list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
358*4882a593Smuzhiyun 		if (cancel_delayed_work(&fw_event->work))
359*4882a593Smuzhiyun 			mptsas_free_fw_event(ioc, fw_event);
360*4882a593Smuzhiyun 	}
361*4882a593Smuzhiyun }
362*4882a593Smuzhiyun 
363*4882a593Smuzhiyun 
phy_to_ioc(struct sas_phy * phy)364*4882a593Smuzhiyun static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
365*4882a593Smuzhiyun {
366*4882a593Smuzhiyun 	struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
367*4882a593Smuzhiyun 	return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
368*4882a593Smuzhiyun }
369*4882a593Smuzhiyun 
rphy_to_ioc(struct sas_rphy * rphy)370*4882a593Smuzhiyun static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
373*4882a593Smuzhiyun 	return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
374*4882a593Smuzhiyun }
375*4882a593Smuzhiyun 
376*4882a593Smuzhiyun /*
377*4882a593Smuzhiyun  * mptsas_find_portinfo_by_handle
378*4882a593Smuzhiyun  *
379*4882a593Smuzhiyun  * This function should be called with the sas_topology_mutex already held
380*4882a593Smuzhiyun  */
381*4882a593Smuzhiyun static struct mptsas_portinfo *
mptsas_find_portinfo_by_handle(MPT_ADAPTER * ioc,u16 handle)382*4882a593Smuzhiyun mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
383*4882a593Smuzhiyun {
384*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info, *rc=NULL;
385*4882a593Smuzhiyun 	int i;
386*4882a593Smuzhiyun 
387*4882a593Smuzhiyun 	list_for_each_entry(port_info, &ioc->sas_topology, list)
388*4882a593Smuzhiyun 		for (i = 0; i < port_info->num_phys; i++)
389*4882a593Smuzhiyun 			if (port_info->phy_info[i].identify.handle == handle) {
390*4882a593Smuzhiyun 				rc = port_info;
391*4882a593Smuzhiyun 				goto out;
392*4882a593Smuzhiyun 			}
393*4882a593Smuzhiyun  out:
394*4882a593Smuzhiyun 	return rc;
395*4882a593Smuzhiyun }
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun /**
398*4882a593Smuzhiyun  *	mptsas_find_portinfo_by_sas_address -
399*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
400*4882a593Smuzhiyun  *	@handle:
401*4882a593Smuzhiyun  *
402*4882a593Smuzhiyun  *	This function should be called with the sas_topology_mutex already held
403*4882a593Smuzhiyun  *
404*4882a593Smuzhiyun  **/
405*4882a593Smuzhiyun static struct mptsas_portinfo *
mptsas_find_portinfo_by_sas_address(MPT_ADAPTER * ioc,u64 sas_address)406*4882a593Smuzhiyun mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
407*4882a593Smuzhiyun {
408*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info, *rc = NULL;
409*4882a593Smuzhiyun 	int i;
410*4882a593Smuzhiyun 
411*4882a593Smuzhiyun 	if (sas_address >= ioc->hba_port_sas_addr &&
412*4882a593Smuzhiyun 	    sas_address < (ioc->hba_port_sas_addr +
413*4882a593Smuzhiyun 	    ioc->hba_port_num_phy))
414*4882a593Smuzhiyun 		return ioc->hba_port_info;
415*4882a593Smuzhiyun 
416*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
417*4882a593Smuzhiyun 	list_for_each_entry(port_info, &ioc->sas_topology, list)
418*4882a593Smuzhiyun 		for (i = 0; i < port_info->num_phys; i++)
419*4882a593Smuzhiyun 			if (port_info->phy_info[i].identify.sas_address ==
420*4882a593Smuzhiyun 			    sas_address) {
421*4882a593Smuzhiyun 				rc = port_info;
422*4882a593Smuzhiyun 				goto out;
423*4882a593Smuzhiyun 			}
424*4882a593Smuzhiyun  out:
425*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
426*4882a593Smuzhiyun 	return rc;
427*4882a593Smuzhiyun }
428*4882a593Smuzhiyun 
429*4882a593Smuzhiyun /*
430*4882a593Smuzhiyun  * Returns true if there is a scsi end device
431*4882a593Smuzhiyun  */
432*4882a593Smuzhiyun static inline int
mptsas_is_end_device(struct mptsas_devinfo * attached)433*4882a593Smuzhiyun mptsas_is_end_device(struct mptsas_devinfo * attached)
434*4882a593Smuzhiyun {
435*4882a593Smuzhiyun 	if ((attached->sas_address) &&
436*4882a593Smuzhiyun 	    (attached->device_info &
437*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_END_DEVICE) &&
438*4882a593Smuzhiyun 	    ((attached->device_info &
439*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_SSP_TARGET) |
440*4882a593Smuzhiyun 	    (attached->device_info &
441*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_STP_TARGET) |
442*4882a593Smuzhiyun 	    (attached->device_info &
443*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
444*4882a593Smuzhiyun 		return 1;
445*4882a593Smuzhiyun 	else
446*4882a593Smuzhiyun 		return 0;
447*4882a593Smuzhiyun }
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun /* no mutex */
450*4882a593Smuzhiyun static void
mptsas_port_delete(MPT_ADAPTER * ioc,struct mptsas_portinfo_details * port_details)451*4882a593Smuzhiyun mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
452*4882a593Smuzhiyun {
453*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
454*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
455*4882a593Smuzhiyun 	u8	i;
456*4882a593Smuzhiyun 
457*4882a593Smuzhiyun 	if (!port_details)
458*4882a593Smuzhiyun 		return;
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	port_info = port_details->port_info;
461*4882a593Smuzhiyun 	phy_info = port_info->phy_info;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
464*4882a593Smuzhiyun 	    "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
465*4882a593Smuzhiyun 	    port_details->num_phys, (unsigned long long)
466*4882a593Smuzhiyun 	    port_details->phy_bitmask));
467*4882a593Smuzhiyun 
468*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++, phy_info++) {
469*4882a593Smuzhiyun 		if(phy_info->port_details != port_details)
470*4882a593Smuzhiyun 			continue;
471*4882a593Smuzhiyun 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
472*4882a593Smuzhiyun 		mptsas_set_rphy(ioc, phy_info, NULL);
473*4882a593Smuzhiyun 		phy_info->port_details = NULL;
474*4882a593Smuzhiyun 	}
475*4882a593Smuzhiyun 	kfree(port_details);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
478*4882a593Smuzhiyun static inline struct sas_rphy *
mptsas_get_rphy(struct mptsas_phyinfo * phy_info)479*4882a593Smuzhiyun mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
480*4882a593Smuzhiyun {
481*4882a593Smuzhiyun 	if (phy_info->port_details)
482*4882a593Smuzhiyun 		return phy_info->port_details->rphy;
483*4882a593Smuzhiyun 	else
484*4882a593Smuzhiyun 		return NULL;
485*4882a593Smuzhiyun }
486*4882a593Smuzhiyun 
487*4882a593Smuzhiyun static inline void
mptsas_set_rphy(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,struct sas_rphy * rphy)488*4882a593Smuzhiyun mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
489*4882a593Smuzhiyun {
490*4882a593Smuzhiyun 	if (phy_info->port_details) {
491*4882a593Smuzhiyun 		phy_info->port_details->rphy = rphy;
492*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
493*4882a593Smuzhiyun 		    ioc->name, rphy));
494*4882a593Smuzhiyun 	}
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (rphy) {
497*4882a593Smuzhiyun 		dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
498*4882a593Smuzhiyun 		    &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
499*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
500*4882a593Smuzhiyun 		    ioc->name, rphy, rphy->dev.release));
501*4882a593Smuzhiyun 	}
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
504*4882a593Smuzhiyun static inline struct sas_port *
mptsas_get_port(struct mptsas_phyinfo * phy_info)505*4882a593Smuzhiyun mptsas_get_port(struct mptsas_phyinfo *phy_info)
506*4882a593Smuzhiyun {
507*4882a593Smuzhiyun 	if (phy_info->port_details)
508*4882a593Smuzhiyun 		return phy_info->port_details->port;
509*4882a593Smuzhiyun 	else
510*4882a593Smuzhiyun 		return NULL;
511*4882a593Smuzhiyun }
512*4882a593Smuzhiyun 
513*4882a593Smuzhiyun static inline void
mptsas_set_port(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,struct sas_port * port)514*4882a593Smuzhiyun mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
515*4882a593Smuzhiyun {
516*4882a593Smuzhiyun 	if (phy_info->port_details)
517*4882a593Smuzhiyun 		phy_info->port_details->port = port;
518*4882a593Smuzhiyun 
519*4882a593Smuzhiyun 	if (port) {
520*4882a593Smuzhiyun 		dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
521*4882a593Smuzhiyun 		    &port->dev, MYIOC_s_FMT "add:", ioc->name));
522*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
523*4882a593Smuzhiyun 		    ioc->name, port, port->dev.release));
524*4882a593Smuzhiyun 	}
525*4882a593Smuzhiyun }
526*4882a593Smuzhiyun 
527*4882a593Smuzhiyun static inline struct scsi_target *
mptsas_get_starget(struct mptsas_phyinfo * phy_info)528*4882a593Smuzhiyun mptsas_get_starget(struct mptsas_phyinfo *phy_info)
529*4882a593Smuzhiyun {
530*4882a593Smuzhiyun 	if (phy_info->port_details)
531*4882a593Smuzhiyun 		return phy_info->port_details->starget;
532*4882a593Smuzhiyun 	else
533*4882a593Smuzhiyun 		return NULL;
534*4882a593Smuzhiyun }
535*4882a593Smuzhiyun 
536*4882a593Smuzhiyun static inline void
mptsas_set_starget(struct mptsas_phyinfo * phy_info,struct scsi_target * starget)537*4882a593Smuzhiyun mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
538*4882a593Smuzhiyun starget)
539*4882a593Smuzhiyun {
540*4882a593Smuzhiyun 	if (phy_info->port_details)
541*4882a593Smuzhiyun 		phy_info->port_details->starget = starget;
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun /**
545*4882a593Smuzhiyun  *	mptsas_add_device_component -
546*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
547*4882a593Smuzhiyun  *	@channel: fw mapped id's
548*4882a593Smuzhiyun  *	@id:
549*4882a593Smuzhiyun  *	@sas_address:
550*4882a593Smuzhiyun  *	@device_info:
551*4882a593Smuzhiyun  *
552*4882a593Smuzhiyun  **/
553*4882a593Smuzhiyun static void
mptsas_add_device_component(MPT_ADAPTER * ioc,u8 channel,u8 id,u64 sas_address,u32 device_info,u16 slot,u64 enclosure_logical_id)554*4882a593Smuzhiyun mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
555*4882a593Smuzhiyun 	u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
556*4882a593Smuzhiyun {
557*4882a593Smuzhiyun 	struct mptsas_device_info	*sas_info, *next;
558*4882a593Smuzhiyun 	struct scsi_device	*sdev;
559*4882a593Smuzhiyun 	struct scsi_target	*starget;
560*4882a593Smuzhiyun 	struct sas_rphy	*rphy;
561*4882a593Smuzhiyun 
562*4882a593Smuzhiyun 	/*
563*4882a593Smuzhiyun 	 * Delete all matching devices out of the list
564*4882a593Smuzhiyun 	 */
565*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_device_info_mutex);
566*4882a593Smuzhiyun 	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
567*4882a593Smuzhiyun 	    list) {
568*4882a593Smuzhiyun 		if (!sas_info->is_logical_volume &&
569*4882a593Smuzhiyun 		    (sas_info->sas_address == sas_address ||
570*4882a593Smuzhiyun 		    (sas_info->fw.channel == channel &&
571*4882a593Smuzhiyun 		     sas_info->fw.id == id))) {
572*4882a593Smuzhiyun 			list_del(&sas_info->list);
573*4882a593Smuzhiyun 			kfree(sas_info);
574*4882a593Smuzhiyun 		}
575*4882a593Smuzhiyun 	}
576*4882a593Smuzhiyun 
577*4882a593Smuzhiyun 	sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
578*4882a593Smuzhiyun 	if (!sas_info)
579*4882a593Smuzhiyun 		goto out;
580*4882a593Smuzhiyun 
581*4882a593Smuzhiyun 	/*
582*4882a593Smuzhiyun 	 * Set Firmware mapping
583*4882a593Smuzhiyun 	 */
584*4882a593Smuzhiyun 	sas_info->fw.id = id;
585*4882a593Smuzhiyun 	sas_info->fw.channel = channel;
586*4882a593Smuzhiyun 
587*4882a593Smuzhiyun 	sas_info->sas_address = sas_address;
588*4882a593Smuzhiyun 	sas_info->device_info = device_info;
589*4882a593Smuzhiyun 	sas_info->slot = slot;
590*4882a593Smuzhiyun 	sas_info->enclosure_logical_id = enclosure_logical_id;
591*4882a593Smuzhiyun 	INIT_LIST_HEAD(&sas_info->list);
592*4882a593Smuzhiyun 	list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
593*4882a593Smuzhiyun 
594*4882a593Smuzhiyun 	/*
595*4882a593Smuzhiyun 	 * Set OS mapping
596*4882a593Smuzhiyun 	 */
597*4882a593Smuzhiyun 	shost_for_each_device(sdev, ioc->sh) {
598*4882a593Smuzhiyun 		starget = scsi_target(sdev);
599*4882a593Smuzhiyun 		rphy = dev_to_rphy(starget->dev.parent);
600*4882a593Smuzhiyun 		if (rphy->identify.sas_address == sas_address) {
601*4882a593Smuzhiyun 			sas_info->os.id = starget->id;
602*4882a593Smuzhiyun 			sas_info->os.channel = starget->channel;
603*4882a593Smuzhiyun 		}
604*4882a593Smuzhiyun 	}
605*4882a593Smuzhiyun 
606*4882a593Smuzhiyun  out:
607*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_device_info_mutex);
608*4882a593Smuzhiyun 	return;
609*4882a593Smuzhiyun }
610*4882a593Smuzhiyun 
611*4882a593Smuzhiyun /**
612*4882a593Smuzhiyun  *	mptsas_add_device_component_by_fw -
613*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
614*4882a593Smuzhiyun  *	@channel:  fw mapped id's
615*4882a593Smuzhiyun  *	@id:
616*4882a593Smuzhiyun  *
617*4882a593Smuzhiyun  **/
618*4882a593Smuzhiyun static void
mptsas_add_device_component_by_fw(MPT_ADAPTER * ioc,u8 channel,u8 id)619*4882a593Smuzhiyun mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
620*4882a593Smuzhiyun {
621*4882a593Smuzhiyun 	struct mptsas_devinfo sas_device;
622*4882a593Smuzhiyun 	struct mptsas_enclosure enclosure_info;
623*4882a593Smuzhiyun 	int rc;
624*4882a593Smuzhiyun 
625*4882a593Smuzhiyun 	rc = mptsas_sas_device_pg0(ioc, &sas_device,
626*4882a593Smuzhiyun 	    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
627*4882a593Smuzhiyun 	     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
628*4882a593Smuzhiyun 	    (channel << 8) + id);
629*4882a593Smuzhiyun 	if (rc)
630*4882a593Smuzhiyun 		return;
631*4882a593Smuzhiyun 
632*4882a593Smuzhiyun 	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
633*4882a593Smuzhiyun 	mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
634*4882a593Smuzhiyun 	    (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
635*4882a593Smuzhiyun 	     MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
636*4882a593Smuzhiyun 	     sas_device.handle_enclosure);
637*4882a593Smuzhiyun 
638*4882a593Smuzhiyun 	mptsas_add_device_component(ioc, sas_device.channel,
639*4882a593Smuzhiyun 	    sas_device.id, sas_device.sas_address, sas_device.device_info,
640*4882a593Smuzhiyun 	    sas_device.slot, enclosure_info.enclosure_logical_id);
641*4882a593Smuzhiyun }
642*4882a593Smuzhiyun 
643*4882a593Smuzhiyun /**
644*4882a593Smuzhiyun  *	mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
645*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
646*4882a593Smuzhiyun  *	@channel: fw mapped id's
647*4882a593Smuzhiyun  *	@id:
648*4882a593Smuzhiyun  *
649*4882a593Smuzhiyun  **/
650*4882a593Smuzhiyun static void
mptsas_add_device_component_starget_ir(MPT_ADAPTER * ioc,struct scsi_target * starget)651*4882a593Smuzhiyun mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
652*4882a593Smuzhiyun 		struct scsi_target *starget)
653*4882a593Smuzhiyun {
654*4882a593Smuzhiyun 	CONFIGPARMS			cfg;
655*4882a593Smuzhiyun 	ConfigPageHeader_t		hdr;
656*4882a593Smuzhiyun 	dma_addr_t			dma_handle;
657*4882a593Smuzhiyun 	pRaidVolumePage0_t		buffer = NULL;
658*4882a593Smuzhiyun 	int				i;
659*4882a593Smuzhiyun 	RaidPhysDiskPage0_t 		phys_disk;
660*4882a593Smuzhiyun 	struct mptsas_device_info	*sas_info, *next;
661*4882a593Smuzhiyun 
662*4882a593Smuzhiyun 	memset(&cfg, 0 , sizeof(CONFIGPARMS));
663*4882a593Smuzhiyun 	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
664*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
665*4882a593Smuzhiyun 	/* assumption that all volumes on channel = 0 */
666*4882a593Smuzhiyun 	cfg.pageAddr = starget->id;
667*4882a593Smuzhiyun 	cfg.cfghdr.hdr = &hdr;
668*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
669*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
670*4882a593Smuzhiyun 
671*4882a593Smuzhiyun 	if (mpt_config(ioc, &cfg) != 0)
672*4882a593Smuzhiyun 		goto out;
673*4882a593Smuzhiyun 
674*4882a593Smuzhiyun 	if (!hdr.PageLength)
675*4882a593Smuzhiyun 		goto out;
676*4882a593Smuzhiyun 
677*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
678*4882a593Smuzhiyun 	    &dma_handle);
679*4882a593Smuzhiyun 
680*4882a593Smuzhiyun 	if (!buffer)
681*4882a593Smuzhiyun 		goto out;
682*4882a593Smuzhiyun 
683*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
684*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
685*4882a593Smuzhiyun 
686*4882a593Smuzhiyun 	if (mpt_config(ioc, &cfg) != 0)
687*4882a593Smuzhiyun 		goto out;
688*4882a593Smuzhiyun 
689*4882a593Smuzhiyun 	if (!buffer->NumPhysDisks)
690*4882a593Smuzhiyun 		goto out;
691*4882a593Smuzhiyun 
692*4882a593Smuzhiyun 	/*
693*4882a593Smuzhiyun 	 * Adding entry for hidden components
694*4882a593Smuzhiyun 	 */
695*4882a593Smuzhiyun 	for (i = 0; i < buffer->NumPhysDisks; i++) {
696*4882a593Smuzhiyun 
697*4882a593Smuzhiyun 		if (mpt_raid_phys_disk_pg0(ioc,
698*4882a593Smuzhiyun 		    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
699*4882a593Smuzhiyun 			continue;
700*4882a593Smuzhiyun 
701*4882a593Smuzhiyun 		mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
702*4882a593Smuzhiyun 		    phys_disk.PhysDiskID);
703*4882a593Smuzhiyun 
704*4882a593Smuzhiyun 		mutex_lock(&ioc->sas_device_info_mutex);
705*4882a593Smuzhiyun 		list_for_each_entry(sas_info, &ioc->sas_device_info_list,
706*4882a593Smuzhiyun 		    list) {
707*4882a593Smuzhiyun 			if (!sas_info->is_logical_volume &&
708*4882a593Smuzhiyun 			    (sas_info->fw.channel == phys_disk.PhysDiskBus &&
709*4882a593Smuzhiyun 			    sas_info->fw.id == phys_disk.PhysDiskID)) {
710*4882a593Smuzhiyun 				sas_info->is_hidden_raid_component = 1;
711*4882a593Smuzhiyun 				sas_info->volume_id = starget->id;
712*4882a593Smuzhiyun 			}
713*4882a593Smuzhiyun 		}
714*4882a593Smuzhiyun 		mutex_unlock(&ioc->sas_device_info_mutex);
715*4882a593Smuzhiyun 
716*4882a593Smuzhiyun 	}
717*4882a593Smuzhiyun 
718*4882a593Smuzhiyun 	/*
719*4882a593Smuzhiyun 	 * Delete all matching devices out of the list
720*4882a593Smuzhiyun 	 */
721*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_device_info_mutex);
722*4882a593Smuzhiyun 	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
723*4882a593Smuzhiyun 	    list) {
724*4882a593Smuzhiyun 		if (sas_info->is_logical_volume && sas_info->fw.id ==
725*4882a593Smuzhiyun 		    starget->id) {
726*4882a593Smuzhiyun 			list_del(&sas_info->list);
727*4882a593Smuzhiyun 			kfree(sas_info);
728*4882a593Smuzhiyun 		}
729*4882a593Smuzhiyun 	}
730*4882a593Smuzhiyun 
731*4882a593Smuzhiyun 	sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
732*4882a593Smuzhiyun 	if (sas_info) {
733*4882a593Smuzhiyun 		sas_info->fw.id = starget->id;
734*4882a593Smuzhiyun 		sas_info->os.id = starget->id;
735*4882a593Smuzhiyun 		sas_info->os.channel = starget->channel;
736*4882a593Smuzhiyun 		sas_info->is_logical_volume = 1;
737*4882a593Smuzhiyun 		INIT_LIST_HEAD(&sas_info->list);
738*4882a593Smuzhiyun 		list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
739*4882a593Smuzhiyun 	}
740*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_device_info_mutex);
741*4882a593Smuzhiyun 
742*4882a593Smuzhiyun  out:
743*4882a593Smuzhiyun 	if (buffer)
744*4882a593Smuzhiyun 		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
745*4882a593Smuzhiyun 		    dma_handle);
746*4882a593Smuzhiyun }
747*4882a593Smuzhiyun 
748*4882a593Smuzhiyun /**
749*4882a593Smuzhiyun  *	mptsas_add_device_component_starget -
750*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
751*4882a593Smuzhiyun  *	@starget:
752*4882a593Smuzhiyun  *
753*4882a593Smuzhiyun  **/
754*4882a593Smuzhiyun static void
mptsas_add_device_component_starget(MPT_ADAPTER * ioc,struct scsi_target * starget)755*4882a593Smuzhiyun mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
756*4882a593Smuzhiyun 	struct scsi_target *starget)
757*4882a593Smuzhiyun {
758*4882a593Smuzhiyun 	VirtTarget	*vtarget;
759*4882a593Smuzhiyun 	struct sas_rphy	*rphy;
760*4882a593Smuzhiyun 	struct mptsas_phyinfo	*phy_info = NULL;
761*4882a593Smuzhiyun 	struct mptsas_enclosure	enclosure_info;
762*4882a593Smuzhiyun 
763*4882a593Smuzhiyun 	rphy = dev_to_rphy(starget->dev.parent);
764*4882a593Smuzhiyun 	vtarget = starget->hostdata;
765*4882a593Smuzhiyun 	phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
766*4882a593Smuzhiyun 			rphy->identify.sas_address);
767*4882a593Smuzhiyun 	if (!phy_info)
768*4882a593Smuzhiyun 		return;
769*4882a593Smuzhiyun 
770*4882a593Smuzhiyun 	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
771*4882a593Smuzhiyun 	mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
772*4882a593Smuzhiyun 		(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
773*4882a593Smuzhiyun 		MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
774*4882a593Smuzhiyun 		phy_info->attached.handle_enclosure);
775*4882a593Smuzhiyun 
776*4882a593Smuzhiyun 	mptsas_add_device_component(ioc, phy_info->attached.channel,
777*4882a593Smuzhiyun 		phy_info->attached.id, phy_info->attached.sas_address,
778*4882a593Smuzhiyun 		phy_info->attached.device_info,
779*4882a593Smuzhiyun 		phy_info->attached.slot, enclosure_info.enclosure_logical_id);
780*4882a593Smuzhiyun }
781*4882a593Smuzhiyun 
782*4882a593Smuzhiyun /**
783*4882a593Smuzhiyun  *	mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
784*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
785*4882a593Smuzhiyun  *	@channel: os mapped id's
786*4882a593Smuzhiyun  *	@id:
787*4882a593Smuzhiyun  *
788*4882a593Smuzhiyun  **/
789*4882a593Smuzhiyun static void
mptsas_del_device_component_by_os(MPT_ADAPTER * ioc,u8 channel,u8 id)790*4882a593Smuzhiyun mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
791*4882a593Smuzhiyun {
792*4882a593Smuzhiyun 	struct mptsas_device_info	*sas_info, *next;
793*4882a593Smuzhiyun 
794*4882a593Smuzhiyun 	/*
795*4882a593Smuzhiyun 	 * Set is_cached flag
796*4882a593Smuzhiyun 	 */
797*4882a593Smuzhiyun 	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
798*4882a593Smuzhiyun 		list) {
799*4882a593Smuzhiyun 		if (sas_info->os.channel == channel && sas_info->os.id == id)
800*4882a593Smuzhiyun 			sas_info->is_cached = 1;
801*4882a593Smuzhiyun 	}
802*4882a593Smuzhiyun }
803*4882a593Smuzhiyun 
804*4882a593Smuzhiyun /**
805*4882a593Smuzhiyun  *	mptsas_del_device_components - Cleaning the list
806*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
807*4882a593Smuzhiyun  *
808*4882a593Smuzhiyun  **/
809*4882a593Smuzhiyun static void
mptsas_del_device_components(MPT_ADAPTER * ioc)810*4882a593Smuzhiyun mptsas_del_device_components(MPT_ADAPTER *ioc)
811*4882a593Smuzhiyun {
812*4882a593Smuzhiyun 	struct mptsas_device_info	*sas_info, *next;
813*4882a593Smuzhiyun 
814*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_device_info_mutex);
815*4882a593Smuzhiyun 	list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
816*4882a593Smuzhiyun 		list) {
817*4882a593Smuzhiyun 		list_del(&sas_info->list);
818*4882a593Smuzhiyun 		kfree(sas_info);
819*4882a593Smuzhiyun 	}
820*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_device_info_mutex);
821*4882a593Smuzhiyun }
822*4882a593Smuzhiyun 
823*4882a593Smuzhiyun 
824*4882a593Smuzhiyun /*
825*4882a593Smuzhiyun  * mptsas_setup_wide_ports
826*4882a593Smuzhiyun  *
827*4882a593Smuzhiyun  * Updates for new and existing narrow/wide port configuration
828*4882a593Smuzhiyun  * in the sas_topology
829*4882a593Smuzhiyun  */
830*4882a593Smuzhiyun static void
mptsas_setup_wide_ports(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info)831*4882a593Smuzhiyun mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
832*4882a593Smuzhiyun {
833*4882a593Smuzhiyun 	struct mptsas_portinfo_details * port_details;
834*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info, *phy_info_cmp;
835*4882a593Smuzhiyun 	u64	sas_address;
836*4882a593Smuzhiyun 	int	i, j;
837*4882a593Smuzhiyun 
838*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
839*4882a593Smuzhiyun 
840*4882a593Smuzhiyun 	phy_info = port_info->phy_info;
841*4882a593Smuzhiyun 	for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
842*4882a593Smuzhiyun 		if (phy_info->attached.handle)
843*4882a593Smuzhiyun 			continue;
844*4882a593Smuzhiyun 		port_details = phy_info->port_details;
845*4882a593Smuzhiyun 		if (!port_details)
846*4882a593Smuzhiyun 			continue;
847*4882a593Smuzhiyun 		if (port_details->num_phys < 2)
848*4882a593Smuzhiyun 			continue;
849*4882a593Smuzhiyun 		/*
850*4882a593Smuzhiyun 		 * Removing a phy from a port, letting the last
851*4882a593Smuzhiyun 		 * phy be removed by firmware events.
852*4882a593Smuzhiyun 		 */
853*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
854*4882a593Smuzhiyun 		    "%s: [%p]: deleting phy = %d\n",
855*4882a593Smuzhiyun 		    ioc->name, __func__, port_details, i));
856*4882a593Smuzhiyun 		port_details->num_phys--;
857*4882a593Smuzhiyun 		port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
858*4882a593Smuzhiyun 		memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
859*4882a593Smuzhiyun 		if (phy_info->phy) {
860*4882a593Smuzhiyun 			devtprintk(ioc, dev_printk(KERN_DEBUG,
861*4882a593Smuzhiyun 				&phy_info->phy->dev, MYIOC_s_FMT
862*4882a593Smuzhiyun 				"delete phy %d, phy-obj (0x%p)\n", ioc->name,
863*4882a593Smuzhiyun 				phy_info->phy_id, phy_info->phy));
864*4882a593Smuzhiyun 			sas_port_delete_phy(port_details->port, phy_info->phy);
865*4882a593Smuzhiyun 		}
866*4882a593Smuzhiyun 		phy_info->port_details = NULL;
867*4882a593Smuzhiyun 	}
868*4882a593Smuzhiyun 
869*4882a593Smuzhiyun 	/*
870*4882a593Smuzhiyun 	 * Populate and refresh the tree
871*4882a593Smuzhiyun 	 */
872*4882a593Smuzhiyun 	phy_info = port_info->phy_info;
873*4882a593Smuzhiyun 	for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
874*4882a593Smuzhiyun 		sas_address = phy_info->attached.sas_address;
875*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
876*4882a593Smuzhiyun 		    ioc->name, i, (unsigned long long)sas_address));
877*4882a593Smuzhiyun 		if (!sas_address)
878*4882a593Smuzhiyun 			continue;
879*4882a593Smuzhiyun 		port_details = phy_info->port_details;
880*4882a593Smuzhiyun 		/*
881*4882a593Smuzhiyun 		 * Forming a port
882*4882a593Smuzhiyun 		 */
883*4882a593Smuzhiyun 		if (!port_details) {
884*4882a593Smuzhiyun 			port_details = kzalloc(sizeof(struct
885*4882a593Smuzhiyun 				mptsas_portinfo_details), GFP_KERNEL);
886*4882a593Smuzhiyun 			if (!port_details)
887*4882a593Smuzhiyun 				goto out;
888*4882a593Smuzhiyun 			port_details->num_phys = 1;
889*4882a593Smuzhiyun 			port_details->port_info = port_info;
890*4882a593Smuzhiyun 			if (phy_info->phy_id < 64 )
891*4882a593Smuzhiyun 				port_details->phy_bitmask |=
892*4882a593Smuzhiyun 				    (1 << phy_info->phy_id);
893*4882a593Smuzhiyun 			phy_info->sas_port_add_phy=1;
894*4882a593Smuzhiyun 			dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
895*4882a593Smuzhiyun 			    "phy_id=%d sas_address=0x%018llX\n",
896*4882a593Smuzhiyun 			    ioc->name, i, (unsigned long long)sas_address));
897*4882a593Smuzhiyun 			phy_info->port_details = port_details;
898*4882a593Smuzhiyun 		}
899*4882a593Smuzhiyun 
900*4882a593Smuzhiyun 		if (i == port_info->num_phys - 1)
901*4882a593Smuzhiyun 			continue;
902*4882a593Smuzhiyun 		phy_info_cmp = &port_info->phy_info[i + 1];
903*4882a593Smuzhiyun 		for (j = i + 1 ; j < port_info->num_phys ; j++,
904*4882a593Smuzhiyun 		    phy_info_cmp++) {
905*4882a593Smuzhiyun 			if (!phy_info_cmp->attached.sas_address)
906*4882a593Smuzhiyun 				continue;
907*4882a593Smuzhiyun 			if (sas_address != phy_info_cmp->attached.sas_address)
908*4882a593Smuzhiyun 				continue;
909*4882a593Smuzhiyun 			if (phy_info_cmp->port_details == port_details )
910*4882a593Smuzhiyun 				continue;
911*4882a593Smuzhiyun 			dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
912*4882a593Smuzhiyun 			    "\t\tphy_id=%d sas_address=0x%018llX\n",
913*4882a593Smuzhiyun 			    ioc->name, j, (unsigned long long)
914*4882a593Smuzhiyun 			    phy_info_cmp->attached.sas_address));
915*4882a593Smuzhiyun 			if (phy_info_cmp->port_details) {
916*4882a593Smuzhiyun 				port_details->rphy =
917*4882a593Smuzhiyun 				    mptsas_get_rphy(phy_info_cmp);
918*4882a593Smuzhiyun 				port_details->port =
919*4882a593Smuzhiyun 				    mptsas_get_port(phy_info_cmp);
920*4882a593Smuzhiyun 				port_details->starget =
921*4882a593Smuzhiyun 				    mptsas_get_starget(phy_info_cmp);
922*4882a593Smuzhiyun 				port_details->num_phys =
923*4882a593Smuzhiyun 					phy_info_cmp->port_details->num_phys;
924*4882a593Smuzhiyun 				if (!phy_info_cmp->port_details->num_phys)
925*4882a593Smuzhiyun 					kfree(phy_info_cmp->port_details);
926*4882a593Smuzhiyun 			} else
927*4882a593Smuzhiyun 				phy_info_cmp->sas_port_add_phy=1;
928*4882a593Smuzhiyun 			/*
929*4882a593Smuzhiyun 			 * Adding a phy to a port
930*4882a593Smuzhiyun 			 */
931*4882a593Smuzhiyun 			phy_info_cmp->port_details = port_details;
932*4882a593Smuzhiyun 			if (phy_info_cmp->phy_id < 64 )
933*4882a593Smuzhiyun 				port_details->phy_bitmask |=
934*4882a593Smuzhiyun 				(1 << phy_info_cmp->phy_id);
935*4882a593Smuzhiyun 			port_details->num_phys++;
936*4882a593Smuzhiyun 		}
937*4882a593Smuzhiyun 	}
938*4882a593Smuzhiyun 
939*4882a593Smuzhiyun  out:
940*4882a593Smuzhiyun 
941*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
942*4882a593Smuzhiyun 		port_details = port_info->phy_info[i].port_details;
943*4882a593Smuzhiyun 		if (!port_details)
944*4882a593Smuzhiyun 			continue;
945*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
946*4882a593Smuzhiyun 		    "%s: [%p]: phy_id=%02d num_phys=%02d "
947*4882a593Smuzhiyun 		    "bitmask=0x%016llX\n", ioc->name, __func__,
948*4882a593Smuzhiyun 		    port_details, i, port_details->num_phys,
949*4882a593Smuzhiyun 		    (unsigned long long)port_details->phy_bitmask));
950*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
951*4882a593Smuzhiyun 		    ioc->name, port_details->port, port_details->rphy));
952*4882a593Smuzhiyun 	}
953*4882a593Smuzhiyun 	dsaswideprintk(ioc, printk("\n"));
954*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
955*4882a593Smuzhiyun }
956*4882a593Smuzhiyun 
957*4882a593Smuzhiyun /**
958*4882a593Smuzhiyun  * csmisas_find_vtarget
959*4882a593Smuzhiyun  *
960*4882a593Smuzhiyun  * @ioc
961*4882a593Smuzhiyun  * @volume_id
962*4882a593Smuzhiyun  * @volume_bus
963*4882a593Smuzhiyun  *
964*4882a593Smuzhiyun  **/
965*4882a593Smuzhiyun static VirtTarget *
mptsas_find_vtarget(MPT_ADAPTER * ioc,u8 channel,u8 id)966*4882a593Smuzhiyun mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
967*4882a593Smuzhiyun {
968*4882a593Smuzhiyun 	struct scsi_device 		*sdev;
969*4882a593Smuzhiyun 	VirtDevice			*vdevice;
970*4882a593Smuzhiyun 	VirtTarget 			*vtarget = NULL;
971*4882a593Smuzhiyun 
972*4882a593Smuzhiyun 	shost_for_each_device(sdev, ioc->sh) {
973*4882a593Smuzhiyun 		vdevice = sdev->hostdata;
974*4882a593Smuzhiyun 		if ((vdevice == NULL) ||
975*4882a593Smuzhiyun 			(vdevice->vtarget == NULL))
976*4882a593Smuzhiyun 			continue;
977*4882a593Smuzhiyun 		if ((vdevice->vtarget->tflags &
978*4882a593Smuzhiyun 		    MPT_TARGET_FLAGS_RAID_COMPONENT ||
979*4882a593Smuzhiyun 		    vdevice->vtarget->raidVolume))
980*4882a593Smuzhiyun 			continue;
981*4882a593Smuzhiyun 		if (vdevice->vtarget->id == id &&
982*4882a593Smuzhiyun 			vdevice->vtarget->channel == channel)
983*4882a593Smuzhiyun 			vtarget = vdevice->vtarget;
984*4882a593Smuzhiyun 	}
985*4882a593Smuzhiyun 	return vtarget;
986*4882a593Smuzhiyun }
987*4882a593Smuzhiyun 
988*4882a593Smuzhiyun static void
mptsas_queue_device_delete(MPT_ADAPTER * ioc,MpiEventDataSasDeviceStatusChange_t * sas_event_data)989*4882a593Smuzhiyun mptsas_queue_device_delete(MPT_ADAPTER *ioc,
990*4882a593Smuzhiyun 	MpiEventDataSasDeviceStatusChange_t *sas_event_data)
991*4882a593Smuzhiyun {
992*4882a593Smuzhiyun 	struct fw_event_work *fw_event;
993*4882a593Smuzhiyun 
994*4882a593Smuzhiyun 	fw_event = kzalloc(sizeof(*fw_event) +
995*4882a593Smuzhiyun 			   sizeof(MpiEventDataSasDeviceStatusChange_t),
996*4882a593Smuzhiyun 			   GFP_ATOMIC);
997*4882a593Smuzhiyun 	if (!fw_event) {
998*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
999*4882a593Smuzhiyun 		    ioc->name, __func__, __LINE__);
1000*4882a593Smuzhiyun 		return;
1001*4882a593Smuzhiyun 	}
1002*4882a593Smuzhiyun 	memcpy(fw_event->event_data, sas_event_data,
1003*4882a593Smuzhiyun 	    sizeof(MpiEventDataSasDeviceStatusChange_t));
1004*4882a593Smuzhiyun 	fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
1005*4882a593Smuzhiyun 	fw_event->ioc = ioc;
1006*4882a593Smuzhiyun 	mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1007*4882a593Smuzhiyun }
1008*4882a593Smuzhiyun 
1009*4882a593Smuzhiyun static void
mptsas_queue_rescan(MPT_ADAPTER * ioc)1010*4882a593Smuzhiyun mptsas_queue_rescan(MPT_ADAPTER *ioc)
1011*4882a593Smuzhiyun {
1012*4882a593Smuzhiyun 	struct fw_event_work *fw_event;
1013*4882a593Smuzhiyun 
1014*4882a593Smuzhiyun 	fw_event = kzalloc(sizeof(*fw_event), GFP_ATOMIC);
1015*4882a593Smuzhiyun 	if (!fw_event) {
1016*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1017*4882a593Smuzhiyun 		    ioc->name, __func__, __LINE__);
1018*4882a593Smuzhiyun 		return;
1019*4882a593Smuzhiyun 	}
1020*4882a593Smuzhiyun 	fw_event->event = -1;
1021*4882a593Smuzhiyun 	fw_event->ioc = ioc;
1022*4882a593Smuzhiyun 	mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1023*4882a593Smuzhiyun }
1024*4882a593Smuzhiyun 
1025*4882a593Smuzhiyun 
1026*4882a593Smuzhiyun /**
1027*4882a593Smuzhiyun  * mptsas_target_reset
1028*4882a593Smuzhiyun  *
1029*4882a593Smuzhiyun  * Issues TARGET_RESET to end device using handshaking method
1030*4882a593Smuzhiyun  *
1031*4882a593Smuzhiyun  * @ioc
1032*4882a593Smuzhiyun  * @channel
1033*4882a593Smuzhiyun  * @id
1034*4882a593Smuzhiyun  *
1035*4882a593Smuzhiyun  * Returns (1) success
1036*4882a593Smuzhiyun  *         (0) failure
1037*4882a593Smuzhiyun  *
1038*4882a593Smuzhiyun  **/
1039*4882a593Smuzhiyun static int
mptsas_target_reset(MPT_ADAPTER * ioc,u8 channel,u8 id)1040*4882a593Smuzhiyun mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1041*4882a593Smuzhiyun {
1042*4882a593Smuzhiyun 	MPT_FRAME_HDR	*mf;
1043*4882a593Smuzhiyun 	SCSITaskMgmt_t	*pScsiTm;
1044*4882a593Smuzhiyun 	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1045*4882a593Smuzhiyun 		return 0;
1046*4882a593Smuzhiyun 
1047*4882a593Smuzhiyun 
1048*4882a593Smuzhiyun 	mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1049*4882a593Smuzhiyun 	if (mf == NULL) {
1050*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1051*4882a593Smuzhiyun 			"%s, no msg frames @%d!!\n", ioc->name,
1052*4882a593Smuzhiyun 			__func__, __LINE__));
1053*4882a593Smuzhiyun 		goto out_fail;
1054*4882a593Smuzhiyun 	}
1055*4882a593Smuzhiyun 
1056*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1057*4882a593Smuzhiyun 		ioc->name, mf));
1058*4882a593Smuzhiyun 
1059*4882a593Smuzhiyun 	/* Format the Request
1060*4882a593Smuzhiyun 	 */
1061*4882a593Smuzhiyun 	pScsiTm = (SCSITaskMgmt_t *) mf;
1062*4882a593Smuzhiyun 	memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1063*4882a593Smuzhiyun 	pScsiTm->TargetID = id;
1064*4882a593Smuzhiyun 	pScsiTm->Bus = channel;
1065*4882a593Smuzhiyun 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1066*4882a593Smuzhiyun 	pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1067*4882a593Smuzhiyun 	pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1068*4882a593Smuzhiyun 
1069*4882a593Smuzhiyun 	DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
1070*4882a593Smuzhiyun 
1071*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1072*4882a593Smuzhiyun 	   "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1073*4882a593Smuzhiyun 	   ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1074*4882a593Smuzhiyun 
1075*4882a593Smuzhiyun 	mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
1076*4882a593Smuzhiyun 
1077*4882a593Smuzhiyun 	return 1;
1078*4882a593Smuzhiyun 
1079*4882a593Smuzhiyun  out_fail:
1080*4882a593Smuzhiyun 
1081*4882a593Smuzhiyun 	mpt_clear_taskmgmt_in_progress_flag(ioc);
1082*4882a593Smuzhiyun 	return 0;
1083*4882a593Smuzhiyun }
1084*4882a593Smuzhiyun 
1085*4882a593Smuzhiyun static void
mptsas_block_io_sdev(struct scsi_device * sdev,void * data)1086*4882a593Smuzhiyun mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1087*4882a593Smuzhiyun {
1088*4882a593Smuzhiyun 	scsi_device_set_state(sdev, SDEV_BLOCK);
1089*4882a593Smuzhiyun }
1090*4882a593Smuzhiyun 
1091*4882a593Smuzhiyun static void
mptsas_block_io_starget(struct scsi_target * starget)1092*4882a593Smuzhiyun mptsas_block_io_starget(struct scsi_target *starget)
1093*4882a593Smuzhiyun {
1094*4882a593Smuzhiyun 	if (starget)
1095*4882a593Smuzhiyun 		starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1096*4882a593Smuzhiyun }
1097*4882a593Smuzhiyun 
1098*4882a593Smuzhiyun /**
1099*4882a593Smuzhiyun  * mptsas_target_reset_queue
1100*4882a593Smuzhiyun  *
1101*4882a593Smuzhiyun  * Receive request for TARGET_RESET after receiving an firmware
1102*4882a593Smuzhiyun  * event NOT_RESPONDING_EVENT, then put command in link list
1103*4882a593Smuzhiyun  * and queue if task_queue already in use.
1104*4882a593Smuzhiyun  *
1105*4882a593Smuzhiyun  * @ioc
1106*4882a593Smuzhiyun  * @sas_event_data
1107*4882a593Smuzhiyun  *
1108*4882a593Smuzhiyun  **/
1109*4882a593Smuzhiyun static void
mptsas_target_reset_queue(MPT_ADAPTER * ioc,EVENT_DATA_SAS_DEVICE_STATUS_CHANGE * sas_event_data)1110*4882a593Smuzhiyun mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1111*4882a593Smuzhiyun     EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1112*4882a593Smuzhiyun {
1113*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
1114*4882a593Smuzhiyun 	VirtTarget *vtarget = NULL;
1115*4882a593Smuzhiyun 	struct mptsas_target_reset_event *target_reset_list;
1116*4882a593Smuzhiyun 	u8		id, channel;
1117*4882a593Smuzhiyun 
1118*4882a593Smuzhiyun 	id = sas_event_data->TargetID;
1119*4882a593Smuzhiyun 	channel = sas_event_data->Bus;
1120*4882a593Smuzhiyun 
1121*4882a593Smuzhiyun 	vtarget = mptsas_find_vtarget(ioc, channel, id);
1122*4882a593Smuzhiyun 	if (vtarget) {
1123*4882a593Smuzhiyun 		mptsas_block_io_starget(vtarget->starget);
1124*4882a593Smuzhiyun 		vtarget->deleted = 1; /* block IO */
1125*4882a593Smuzhiyun 	}
1126*4882a593Smuzhiyun 
1127*4882a593Smuzhiyun 	target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
1128*4882a593Smuzhiyun 	    GFP_ATOMIC);
1129*4882a593Smuzhiyun 	if (!target_reset_list) {
1130*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1131*4882a593Smuzhiyun 			"%s, failed to allocate mem @%d..!!\n",
1132*4882a593Smuzhiyun 			ioc->name, __func__, __LINE__));
1133*4882a593Smuzhiyun 		return;
1134*4882a593Smuzhiyun 	}
1135*4882a593Smuzhiyun 
1136*4882a593Smuzhiyun 	memcpy(&target_reset_list->sas_event_data, sas_event_data,
1137*4882a593Smuzhiyun 		sizeof(*sas_event_data));
1138*4882a593Smuzhiyun 	list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1139*4882a593Smuzhiyun 
1140*4882a593Smuzhiyun 	target_reset_list->time_count = jiffies;
1141*4882a593Smuzhiyun 
1142*4882a593Smuzhiyun 	if (mptsas_target_reset(ioc, channel, id)) {
1143*4882a593Smuzhiyun 		target_reset_list->target_reset_issued = 1;
1144*4882a593Smuzhiyun 	}
1145*4882a593Smuzhiyun }
1146*4882a593Smuzhiyun 
1147*4882a593Smuzhiyun /**
1148*4882a593Smuzhiyun  * mptsas_schedule_target_reset- send pending target reset
1149*4882a593Smuzhiyun  * @iocp: per adapter object
1150*4882a593Smuzhiyun  *
1151*4882a593Smuzhiyun  * This function will delete scheduled target reset from the list and
1152*4882a593Smuzhiyun  * try to send next target reset. This will be called from completion
1153*4882a593Smuzhiyun  * context of any Task management command.
1154*4882a593Smuzhiyun  */
1155*4882a593Smuzhiyun 
1156*4882a593Smuzhiyun void
mptsas_schedule_target_reset(void * iocp)1157*4882a593Smuzhiyun mptsas_schedule_target_reset(void *iocp)
1158*4882a593Smuzhiyun {
1159*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
1160*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
1161*4882a593Smuzhiyun 	struct list_head *head = &hd->target_reset_list;
1162*4882a593Smuzhiyun 	struct mptsas_target_reset_event	*target_reset_list;
1163*4882a593Smuzhiyun 	u8		id, channel;
1164*4882a593Smuzhiyun 	/*
1165*4882a593Smuzhiyun 	 * issue target reset to next device in the queue
1166*4882a593Smuzhiyun 	 */
1167*4882a593Smuzhiyun 
1168*4882a593Smuzhiyun 	if (list_empty(head))
1169*4882a593Smuzhiyun 		return;
1170*4882a593Smuzhiyun 
1171*4882a593Smuzhiyun 	target_reset_list = list_entry(head->next,
1172*4882a593Smuzhiyun 		struct mptsas_target_reset_event, list);
1173*4882a593Smuzhiyun 
1174*4882a593Smuzhiyun 	id = target_reset_list->sas_event_data.TargetID;
1175*4882a593Smuzhiyun 	channel = target_reset_list->sas_event_data.Bus;
1176*4882a593Smuzhiyun 	target_reset_list->time_count = jiffies;
1177*4882a593Smuzhiyun 
1178*4882a593Smuzhiyun 	if (mptsas_target_reset(ioc, channel, id))
1179*4882a593Smuzhiyun 		target_reset_list->target_reset_issued = 1;
1180*4882a593Smuzhiyun 	return;
1181*4882a593Smuzhiyun }
1182*4882a593Smuzhiyun 
1183*4882a593Smuzhiyun 
1184*4882a593Smuzhiyun /**
1185*4882a593Smuzhiyun  *	mptsas_taskmgmt_complete - complete SAS task management function
1186*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
1187*4882a593Smuzhiyun  *
1188*4882a593Smuzhiyun  *	Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1189*4882a593Smuzhiyun  *	queue to finish off removing device from upper layers. then send next
1190*4882a593Smuzhiyun  *	TARGET_RESET in the queue.
1191*4882a593Smuzhiyun  **/
1192*4882a593Smuzhiyun static int
mptsas_taskmgmt_complete(MPT_ADAPTER * ioc,MPT_FRAME_HDR * mf,MPT_FRAME_HDR * mr)1193*4882a593Smuzhiyun mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
1194*4882a593Smuzhiyun {
1195*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd = shost_priv(ioc->sh);
1196*4882a593Smuzhiyun         struct list_head *head = &hd->target_reset_list;
1197*4882a593Smuzhiyun 	u8		id, channel;
1198*4882a593Smuzhiyun 	struct mptsas_target_reset_event	*target_reset_list;
1199*4882a593Smuzhiyun 	SCSITaskMgmtReply_t *pScsiTmReply;
1200*4882a593Smuzhiyun 
1201*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1202*4882a593Smuzhiyun 	    "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1203*4882a593Smuzhiyun 
1204*4882a593Smuzhiyun 	pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1205*4882a593Smuzhiyun 	if (!pScsiTmReply)
1206*4882a593Smuzhiyun 		return 0;
1207*4882a593Smuzhiyun 
1208*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1209*4882a593Smuzhiyun 	    "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1210*4882a593Smuzhiyun 	    "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1211*4882a593Smuzhiyun 	    "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1212*4882a593Smuzhiyun 	    "term_cmnds = %d\n", ioc->name,
1213*4882a593Smuzhiyun 	    pScsiTmReply->Bus, pScsiTmReply->TargetID,
1214*4882a593Smuzhiyun 	    pScsiTmReply->TaskType,
1215*4882a593Smuzhiyun 	    le16_to_cpu(pScsiTmReply->IOCStatus),
1216*4882a593Smuzhiyun 	    le32_to_cpu(pScsiTmReply->IOCLogInfo),
1217*4882a593Smuzhiyun 	    pScsiTmReply->ResponseCode,
1218*4882a593Smuzhiyun 	    le32_to_cpu(pScsiTmReply->TerminationCount)));
1219*4882a593Smuzhiyun 
1220*4882a593Smuzhiyun 	if (pScsiTmReply->ResponseCode)
1221*4882a593Smuzhiyun 		mptscsih_taskmgmt_response_code(ioc,
1222*4882a593Smuzhiyun 		pScsiTmReply->ResponseCode);
1223*4882a593Smuzhiyun 
1224*4882a593Smuzhiyun 	if (pScsiTmReply->TaskType ==
1225*4882a593Smuzhiyun 	    MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1226*4882a593Smuzhiyun 	     MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {
1227*4882a593Smuzhiyun 		ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1228*4882a593Smuzhiyun 		ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1229*4882a593Smuzhiyun 		memcpy(ioc->taskmgmt_cmds.reply, mr,
1230*4882a593Smuzhiyun 		    min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1231*4882a593Smuzhiyun 		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1232*4882a593Smuzhiyun 			ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1233*4882a593Smuzhiyun 			complete(&ioc->taskmgmt_cmds.done);
1234*4882a593Smuzhiyun 			return 1;
1235*4882a593Smuzhiyun 		}
1236*4882a593Smuzhiyun 		return 0;
1237*4882a593Smuzhiyun 	}
1238*4882a593Smuzhiyun 
1239*4882a593Smuzhiyun 	mpt_clear_taskmgmt_in_progress_flag(ioc);
1240*4882a593Smuzhiyun 
1241*4882a593Smuzhiyun 	if (list_empty(head))
1242*4882a593Smuzhiyun 		return 1;
1243*4882a593Smuzhiyun 
1244*4882a593Smuzhiyun 	target_reset_list = list_entry(head->next,
1245*4882a593Smuzhiyun 	    struct mptsas_target_reset_event, list);
1246*4882a593Smuzhiyun 
1247*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1248*4882a593Smuzhiyun 	    "TaskMgmt: completed (%d seconds)\n",
1249*4882a593Smuzhiyun 	    ioc->name, jiffies_to_msecs(jiffies -
1250*4882a593Smuzhiyun 	    target_reset_list->time_count)/1000));
1251*4882a593Smuzhiyun 
1252*4882a593Smuzhiyun 	id = pScsiTmReply->TargetID;
1253*4882a593Smuzhiyun 	channel = pScsiTmReply->Bus;
1254*4882a593Smuzhiyun 	target_reset_list->time_count = jiffies;
1255*4882a593Smuzhiyun 
1256*4882a593Smuzhiyun 	/*
1257*4882a593Smuzhiyun 	 * retry target reset
1258*4882a593Smuzhiyun 	 */
1259*4882a593Smuzhiyun 	if (!target_reset_list->target_reset_issued) {
1260*4882a593Smuzhiyun 		if (mptsas_target_reset(ioc, channel, id))
1261*4882a593Smuzhiyun 			target_reset_list->target_reset_issued = 1;
1262*4882a593Smuzhiyun 		return 1;
1263*4882a593Smuzhiyun 	}
1264*4882a593Smuzhiyun 
1265*4882a593Smuzhiyun 	/*
1266*4882a593Smuzhiyun 	 * enable work queue to remove device from upper layers
1267*4882a593Smuzhiyun 	 */
1268*4882a593Smuzhiyun 	list_del(&target_reset_list->list);
1269*4882a593Smuzhiyun 	if (!ioc->fw_events_off)
1270*4882a593Smuzhiyun 		mptsas_queue_device_delete(ioc,
1271*4882a593Smuzhiyun 			&target_reset_list->sas_event_data);
1272*4882a593Smuzhiyun 
1273*4882a593Smuzhiyun 
1274*4882a593Smuzhiyun 	ioc->schedule_target_reset(ioc);
1275*4882a593Smuzhiyun 
1276*4882a593Smuzhiyun 	return 1;
1277*4882a593Smuzhiyun }
1278*4882a593Smuzhiyun 
1279*4882a593Smuzhiyun /**
1280*4882a593Smuzhiyun  * mptscsih_ioc_reset
1281*4882a593Smuzhiyun  *
1282*4882a593Smuzhiyun  * @ioc
1283*4882a593Smuzhiyun  * @reset_phase
1284*4882a593Smuzhiyun  *
1285*4882a593Smuzhiyun  **/
1286*4882a593Smuzhiyun static int
mptsas_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)1287*4882a593Smuzhiyun mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1288*4882a593Smuzhiyun {
1289*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd;
1290*4882a593Smuzhiyun 	int rc;
1291*4882a593Smuzhiyun 
1292*4882a593Smuzhiyun 	rc = mptscsih_ioc_reset(ioc, reset_phase);
1293*4882a593Smuzhiyun 	if ((ioc->bus_type != SAS) || (!rc))
1294*4882a593Smuzhiyun 		return rc;
1295*4882a593Smuzhiyun 
1296*4882a593Smuzhiyun 	hd = shost_priv(ioc->sh);
1297*4882a593Smuzhiyun 	if (!hd->ioc)
1298*4882a593Smuzhiyun 		goto out;
1299*4882a593Smuzhiyun 
1300*4882a593Smuzhiyun 	switch (reset_phase) {
1301*4882a593Smuzhiyun 	case MPT_IOC_SETUP_RESET:
1302*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1303*4882a593Smuzhiyun 		    "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1304*4882a593Smuzhiyun 		mptsas_fw_event_off(ioc);
1305*4882a593Smuzhiyun 		break;
1306*4882a593Smuzhiyun 	case MPT_IOC_PRE_RESET:
1307*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1308*4882a593Smuzhiyun 		    "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1309*4882a593Smuzhiyun 		break;
1310*4882a593Smuzhiyun 	case MPT_IOC_POST_RESET:
1311*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1312*4882a593Smuzhiyun 		    "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1313*4882a593Smuzhiyun 		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1314*4882a593Smuzhiyun 			ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1315*4882a593Smuzhiyun 			complete(&ioc->sas_mgmt.done);
1316*4882a593Smuzhiyun 		}
1317*4882a593Smuzhiyun 		mptsas_cleanup_fw_event_q(ioc);
1318*4882a593Smuzhiyun 		mptsas_queue_rescan(ioc);
1319*4882a593Smuzhiyun 		break;
1320*4882a593Smuzhiyun 	default:
1321*4882a593Smuzhiyun 		break;
1322*4882a593Smuzhiyun 	}
1323*4882a593Smuzhiyun 
1324*4882a593Smuzhiyun  out:
1325*4882a593Smuzhiyun 	return rc;
1326*4882a593Smuzhiyun }
1327*4882a593Smuzhiyun 
1328*4882a593Smuzhiyun 
1329*4882a593Smuzhiyun /**
1330*4882a593Smuzhiyun  * enum device_state -
1331*4882a593Smuzhiyun  * @DEVICE_RETRY: need to retry the TUR
1332*4882a593Smuzhiyun  * @DEVICE_ERROR: TUR return error, don't add device
1333*4882a593Smuzhiyun  * @DEVICE_READY: device can be added
1334*4882a593Smuzhiyun  *
1335*4882a593Smuzhiyun  */
1336*4882a593Smuzhiyun enum device_state{
1337*4882a593Smuzhiyun 	DEVICE_RETRY,
1338*4882a593Smuzhiyun 	DEVICE_ERROR,
1339*4882a593Smuzhiyun 	DEVICE_READY,
1340*4882a593Smuzhiyun };
1341*4882a593Smuzhiyun 
1342*4882a593Smuzhiyun static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER * ioc,struct mptsas_enclosure * enclosure,u32 form,u32 form_specific)1343*4882a593Smuzhiyun mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
1344*4882a593Smuzhiyun 		u32 form, u32 form_specific)
1345*4882a593Smuzhiyun {
1346*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
1347*4882a593Smuzhiyun 	CONFIGPARMS cfg;
1348*4882a593Smuzhiyun 	SasEnclosurePage0_t *buffer;
1349*4882a593Smuzhiyun 	dma_addr_t dma_handle;
1350*4882a593Smuzhiyun 	int error;
1351*4882a593Smuzhiyun 	__le64 le_identifier;
1352*4882a593Smuzhiyun 
1353*4882a593Smuzhiyun 	memset(&hdr, 0, sizeof(hdr));
1354*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1355*4882a593Smuzhiyun 	hdr.PageNumber = 0;
1356*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1357*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1358*4882a593Smuzhiyun 
1359*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
1360*4882a593Smuzhiyun 	cfg.physAddr = -1;
1361*4882a593Smuzhiyun 	cfg.pageAddr = form + form_specific;
1362*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1363*4882a593Smuzhiyun 	cfg.dir = 0;	/* read */
1364*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
1365*4882a593Smuzhiyun 
1366*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
1367*4882a593Smuzhiyun 	if (error)
1368*4882a593Smuzhiyun 		goto out;
1369*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
1370*4882a593Smuzhiyun 		error = -ENXIO;
1371*4882a593Smuzhiyun 		goto out;
1372*4882a593Smuzhiyun 	}
1373*4882a593Smuzhiyun 
1374*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1375*4882a593Smuzhiyun 			&dma_handle);
1376*4882a593Smuzhiyun 	if (!buffer) {
1377*4882a593Smuzhiyun 		error = -ENOMEM;
1378*4882a593Smuzhiyun 		goto out;
1379*4882a593Smuzhiyun 	}
1380*4882a593Smuzhiyun 
1381*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
1382*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1383*4882a593Smuzhiyun 
1384*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
1385*4882a593Smuzhiyun 	if (error)
1386*4882a593Smuzhiyun 		goto out_free_consistent;
1387*4882a593Smuzhiyun 
1388*4882a593Smuzhiyun 	/* save config data */
1389*4882a593Smuzhiyun 	memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1390*4882a593Smuzhiyun 	enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1391*4882a593Smuzhiyun 	enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1392*4882a593Smuzhiyun 	enclosure->flags = le16_to_cpu(buffer->Flags);
1393*4882a593Smuzhiyun 	enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1394*4882a593Smuzhiyun 	enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1395*4882a593Smuzhiyun 	enclosure->start_id = buffer->StartTargetID;
1396*4882a593Smuzhiyun 	enclosure->start_channel = buffer->StartBus;
1397*4882a593Smuzhiyun 	enclosure->sep_id = buffer->SEPTargetID;
1398*4882a593Smuzhiyun 	enclosure->sep_channel = buffer->SEPBus;
1399*4882a593Smuzhiyun 
1400*4882a593Smuzhiyun  out_free_consistent:
1401*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1402*4882a593Smuzhiyun 			    buffer, dma_handle);
1403*4882a593Smuzhiyun  out:
1404*4882a593Smuzhiyun 	return error;
1405*4882a593Smuzhiyun }
1406*4882a593Smuzhiyun 
1407*4882a593Smuzhiyun /**
1408*4882a593Smuzhiyun  *	mptsas_add_end_device - report a new end device to sas transport layer
1409*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
1410*4882a593Smuzhiyun  *	@phy_info: describes attached device
1411*4882a593Smuzhiyun  *
1412*4882a593Smuzhiyun  *	return (0) success (1) failure
1413*4882a593Smuzhiyun  *
1414*4882a593Smuzhiyun  **/
1415*4882a593Smuzhiyun static int
mptsas_add_end_device(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info)1416*4882a593Smuzhiyun mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1417*4882a593Smuzhiyun {
1418*4882a593Smuzhiyun 	struct sas_rphy *rphy;
1419*4882a593Smuzhiyun 	struct sas_port *port;
1420*4882a593Smuzhiyun 	struct sas_identify identify;
1421*4882a593Smuzhiyun 	char *ds = NULL;
1422*4882a593Smuzhiyun 	u8 fw_id;
1423*4882a593Smuzhiyun 
1424*4882a593Smuzhiyun 	if (!phy_info) {
1425*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1426*4882a593Smuzhiyun 			"%s: exit at line=%d\n", ioc->name,
1427*4882a593Smuzhiyun 			 __func__, __LINE__));
1428*4882a593Smuzhiyun 		return 1;
1429*4882a593Smuzhiyun 	}
1430*4882a593Smuzhiyun 
1431*4882a593Smuzhiyun 	fw_id = phy_info->attached.id;
1432*4882a593Smuzhiyun 
1433*4882a593Smuzhiyun 	if (mptsas_get_rphy(phy_info)) {
1434*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1435*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1436*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1437*4882a593Smuzhiyun 		return 2;
1438*4882a593Smuzhiyun 	}
1439*4882a593Smuzhiyun 
1440*4882a593Smuzhiyun 	port = mptsas_get_port(phy_info);
1441*4882a593Smuzhiyun 	if (!port) {
1442*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1443*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1444*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1445*4882a593Smuzhiyun 		return 3;
1446*4882a593Smuzhiyun 	}
1447*4882a593Smuzhiyun 
1448*4882a593Smuzhiyun 	if (phy_info->attached.device_info &
1449*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_SSP_TARGET)
1450*4882a593Smuzhiyun 		ds = "ssp";
1451*4882a593Smuzhiyun 	if (phy_info->attached.device_info &
1452*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_STP_TARGET)
1453*4882a593Smuzhiyun 		ds = "stp";
1454*4882a593Smuzhiyun 	if (phy_info->attached.device_info &
1455*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1456*4882a593Smuzhiyun 		ds = "sata";
1457*4882a593Smuzhiyun 
1458*4882a593Smuzhiyun 	printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1459*4882a593Smuzhiyun 	    " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1460*4882a593Smuzhiyun 	    phy_info->attached.channel, phy_info->attached.id,
1461*4882a593Smuzhiyun 	    phy_info->attached.phy_id, (unsigned long long)
1462*4882a593Smuzhiyun 	    phy_info->attached.sas_address);
1463*4882a593Smuzhiyun 
1464*4882a593Smuzhiyun 	mptsas_parse_device_info(&identify, &phy_info->attached);
1465*4882a593Smuzhiyun 	rphy = sas_end_device_alloc(port);
1466*4882a593Smuzhiyun 	if (!rphy) {
1467*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1468*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1469*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1470*4882a593Smuzhiyun 		return 5; /* non-fatal: an rphy can be added later */
1471*4882a593Smuzhiyun 	}
1472*4882a593Smuzhiyun 
1473*4882a593Smuzhiyun 	rphy->identify = identify;
1474*4882a593Smuzhiyun 	if (sas_rphy_add(rphy)) {
1475*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1476*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1477*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1478*4882a593Smuzhiyun 		sas_rphy_free(rphy);
1479*4882a593Smuzhiyun 		return 6;
1480*4882a593Smuzhiyun 	}
1481*4882a593Smuzhiyun 	mptsas_set_rphy(ioc, phy_info, rphy);
1482*4882a593Smuzhiyun 	return 0;
1483*4882a593Smuzhiyun }
1484*4882a593Smuzhiyun 
1485*4882a593Smuzhiyun /**
1486*4882a593Smuzhiyun  *	mptsas_del_end_device - report a deleted end device to sas transport layer
1487*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
1488*4882a593Smuzhiyun  *	@phy_info: describes attached device
1489*4882a593Smuzhiyun  *
1490*4882a593Smuzhiyun  **/
1491*4882a593Smuzhiyun static void
mptsas_del_end_device(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info)1492*4882a593Smuzhiyun mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1493*4882a593Smuzhiyun {
1494*4882a593Smuzhiyun 	struct sas_rphy *rphy;
1495*4882a593Smuzhiyun 	struct sas_port *port;
1496*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
1497*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info_parent;
1498*4882a593Smuzhiyun 	int i;
1499*4882a593Smuzhiyun 	char *ds = NULL;
1500*4882a593Smuzhiyun 	u8 fw_id;
1501*4882a593Smuzhiyun 	u64 sas_address;
1502*4882a593Smuzhiyun 
1503*4882a593Smuzhiyun 	if (!phy_info)
1504*4882a593Smuzhiyun 		return;
1505*4882a593Smuzhiyun 
1506*4882a593Smuzhiyun 	fw_id = phy_info->attached.id;
1507*4882a593Smuzhiyun 	sas_address = phy_info->attached.sas_address;
1508*4882a593Smuzhiyun 
1509*4882a593Smuzhiyun 	if (!phy_info->port_details) {
1510*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1511*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1512*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1513*4882a593Smuzhiyun 		return;
1514*4882a593Smuzhiyun 	}
1515*4882a593Smuzhiyun 	rphy = mptsas_get_rphy(phy_info);
1516*4882a593Smuzhiyun 	if (!rphy) {
1517*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1518*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1519*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1520*4882a593Smuzhiyun 		return;
1521*4882a593Smuzhiyun 	}
1522*4882a593Smuzhiyun 
1523*4882a593Smuzhiyun 	if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1524*4882a593Smuzhiyun 		|| phy_info->attached.device_info
1525*4882a593Smuzhiyun 			& MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1526*4882a593Smuzhiyun 		|| phy_info->attached.device_info
1527*4882a593Smuzhiyun 			& MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1528*4882a593Smuzhiyun 		ds = "initiator";
1529*4882a593Smuzhiyun 	if (phy_info->attached.device_info &
1530*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_SSP_TARGET)
1531*4882a593Smuzhiyun 		ds = "ssp";
1532*4882a593Smuzhiyun 	if (phy_info->attached.device_info &
1533*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_STP_TARGET)
1534*4882a593Smuzhiyun 		ds = "stp";
1535*4882a593Smuzhiyun 	if (phy_info->attached.device_info &
1536*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1537*4882a593Smuzhiyun 		ds = "sata";
1538*4882a593Smuzhiyun 
1539*4882a593Smuzhiyun 	dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1540*4882a593Smuzhiyun 	    "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1541*4882a593Smuzhiyun 	    "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1542*4882a593Smuzhiyun 	    phy_info->attached.id, phy_info->attached.phy_id,
1543*4882a593Smuzhiyun 	    (unsigned long long) sas_address);
1544*4882a593Smuzhiyun 
1545*4882a593Smuzhiyun 	port = mptsas_get_port(phy_info);
1546*4882a593Smuzhiyun 	if (!port) {
1547*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1548*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
1549*4882a593Smuzhiyun 			 __func__, fw_id, __LINE__));
1550*4882a593Smuzhiyun 		return;
1551*4882a593Smuzhiyun 	}
1552*4882a593Smuzhiyun 	port_info = phy_info->portinfo;
1553*4882a593Smuzhiyun 	phy_info_parent = port_info->phy_info;
1554*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1555*4882a593Smuzhiyun 		if (!phy_info_parent->phy)
1556*4882a593Smuzhiyun 			continue;
1557*4882a593Smuzhiyun 		if (phy_info_parent->attached.sas_address !=
1558*4882a593Smuzhiyun 		    sas_address)
1559*4882a593Smuzhiyun 			continue;
1560*4882a593Smuzhiyun 		dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1561*4882a593Smuzhiyun 		    MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1562*4882a593Smuzhiyun 		    ioc->name, phy_info_parent->phy_id,
1563*4882a593Smuzhiyun 		    phy_info_parent->phy);
1564*4882a593Smuzhiyun 		sas_port_delete_phy(port, phy_info_parent->phy);
1565*4882a593Smuzhiyun 	}
1566*4882a593Smuzhiyun 
1567*4882a593Smuzhiyun 	dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1568*4882a593Smuzhiyun 	    "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1569*4882a593Smuzhiyun 	     port->port_identifier, (unsigned long long)sas_address);
1570*4882a593Smuzhiyun 	sas_port_delete(port);
1571*4882a593Smuzhiyun 	mptsas_set_port(ioc, phy_info, NULL);
1572*4882a593Smuzhiyun 	mptsas_port_delete(ioc, phy_info->port_details);
1573*4882a593Smuzhiyun }
1574*4882a593Smuzhiyun 
1575*4882a593Smuzhiyun static struct mptsas_phyinfo *
mptsas_refreshing_device_handles(MPT_ADAPTER * ioc,struct mptsas_devinfo * sas_device)1576*4882a593Smuzhiyun mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1577*4882a593Smuzhiyun 	struct mptsas_devinfo *sas_device)
1578*4882a593Smuzhiyun {
1579*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
1580*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
1581*4882a593Smuzhiyun 	int i;
1582*4882a593Smuzhiyun 
1583*4882a593Smuzhiyun 	phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1584*4882a593Smuzhiyun 	    sas_device->sas_address);
1585*4882a593Smuzhiyun 	if (!phy_info)
1586*4882a593Smuzhiyun 		goto out;
1587*4882a593Smuzhiyun 	port_info = phy_info->portinfo;
1588*4882a593Smuzhiyun 	if (!port_info)
1589*4882a593Smuzhiyun 		goto out;
1590*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
1591*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
1592*4882a593Smuzhiyun 		if (port_info->phy_info[i].attached.sas_address !=
1593*4882a593Smuzhiyun 			sas_device->sas_address)
1594*4882a593Smuzhiyun 			continue;
1595*4882a593Smuzhiyun 		port_info->phy_info[i].attached.channel = sas_device->channel;
1596*4882a593Smuzhiyun 		port_info->phy_info[i].attached.id = sas_device->id;
1597*4882a593Smuzhiyun 		port_info->phy_info[i].attached.sas_address =
1598*4882a593Smuzhiyun 		    sas_device->sas_address;
1599*4882a593Smuzhiyun 		port_info->phy_info[i].attached.handle = sas_device->handle;
1600*4882a593Smuzhiyun 		port_info->phy_info[i].attached.handle_parent =
1601*4882a593Smuzhiyun 		    sas_device->handle_parent;
1602*4882a593Smuzhiyun 		port_info->phy_info[i].attached.handle_enclosure =
1603*4882a593Smuzhiyun 		    sas_device->handle_enclosure;
1604*4882a593Smuzhiyun 	}
1605*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
1606*4882a593Smuzhiyun  out:
1607*4882a593Smuzhiyun 	return phy_info;
1608*4882a593Smuzhiyun }
1609*4882a593Smuzhiyun 
1610*4882a593Smuzhiyun /**
1611*4882a593Smuzhiyun  * mptsas_firmware_event_work - work thread for processing fw events
1612*4882a593Smuzhiyun  * @work: work queue payload containing info describing the event
1613*4882a593Smuzhiyun  * Context: user
1614*4882a593Smuzhiyun  *
1615*4882a593Smuzhiyun  */
1616*4882a593Smuzhiyun static void
mptsas_firmware_event_work(struct work_struct * work)1617*4882a593Smuzhiyun mptsas_firmware_event_work(struct work_struct *work)
1618*4882a593Smuzhiyun {
1619*4882a593Smuzhiyun 	struct fw_event_work *fw_event =
1620*4882a593Smuzhiyun 		container_of(work, struct fw_event_work, work.work);
1621*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = fw_event->ioc;
1622*4882a593Smuzhiyun 
1623*4882a593Smuzhiyun 	/* special rescan topology handling */
1624*4882a593Smuzhiyun 	if (fw_event->event == -1) {
1625*4882a593Smuzhiyun 		if (ioc->in_rescan) {
1626*4882a593Smuzhiyun 			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1627*4882a593Smuzhiyun 				"%s: rescan ignored as it is in progress\n",
1628*4882a593Smuzhiyun 				ioc->name, __func__));
1629*4882a593Smuzhiyun 			return;
1630*4882a593Smuzhiyun 		}
1631*4882a593Smuzhiyun 		devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1632*4882a593Smuzhiyun 		    "reset\n", ioc->name, __func__));
1633*4882a593Smuzhiyun 		ioc->in_rescan = 1;
1634*4882a593Smuzhiyun 		mptsas_not_responding_devices(ioc);
1635*4882a593Smuzhiyun 		mptsas_scan_sas_topology(ioc);
1636*4882a593Smuzhiyun 		ioc->in_rescan = 0;
1637*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
1638*4882a593Smuzhiyun 		mptsas_fw_event_on(ioc);
1639*4882a593Smuzhiyun 		return;
1640*4882a593Smuzhiyun 	}
1641*4882a593Smuzhiyun 
1642*4882a593Smuzhiyun 	/* events handling turned off during host reset */
1643*4882a593Smuzhiyun 	if (ioc->fw_events_off) {
1644*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
1645*4882a593Smuzhiyun 		return;
1646*4882a593Smuzhiyun 	}
1647*4882a593Smuzhiyun 
1648*4882a593Smuzhiyun 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1649*4882a593Smuzhiyun 	    "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1650*4882a593Smuzhiyun 	    (fw_event->event & 0xFF)));
1651*4882a593Smuzhiyun 
1652*4882a593Smuzhiyun 	switch (fw_event->event) {
1653*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1654*4882a593Smuzhiyun 		mptsas_send_sas_event(fw_event);
1655*4882a593Smuzhiyun 		break;
1656*4882a593Smuzhiyun 	case MPI_EVENT_INTEGRATED_RAID:
1657*4882a593Smuzhiyun 		mptsas_send_raid_event(fw_event);
1658*4882a593Smuzhiyun 		break;
1659*4882a593Smuzhiyun 	case MPI_EVENT_IR2:
1660*4882a593Smuzhiyun 		mptsas_send_ir2_event(fw_event);
1661*4882a593Smuzhiyun 		break;
1662*4882a593Smuzhiyun 	case MPI_EVENT_PERSISTENT_TABLE_FULL:
1663*4882a593Smuzhiyun 		mptbase_sas_persist_operation(ioc,
1664*4882a593Smuzhiyun 		    MPI_SAS_OP_CLEAR_NOT_PRESENT);
1665*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
1666*4882a593Smuzhiyun 		break;
1667*4882a593Smuzhiyun 	case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1668*4882a593Smuzhiyun 		mptsas_broadcast_primitive_work(fw_event);
1669*4882a593Smuzhiyun 		break;
1670*4882a593Smuzhiyun 	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1671*4882a593Smuzhiyun 		mptsas_send_expander_event(fw_event);
1672*4882a593Smuzhiyun 		break;
1673*4882a593Smuzhiyun 	case MPI_EVENT_SAS_PHY_LINK_STATUS:
1674*4882a593Smuzhiyun 		mptsas_send_link_status_event(fw_event);
1675*4882a593Smuzhiyun 		break;
1676*4882a593Smuzhiyun 	case MPI_EVENT_QUEUE_FULL:
1677*4882a593Smuzhiyun 		mptsas_handle_queue_full_event(fw_event);
1678*4882a593Smuzhiyun 		break;
1679*4882a593Smuzhiyun 	}
1680*4882a593Smuzhiyun }
1681*4882a593Smuzhiyun 
1682*4882a593Smuzhiyun 
1683*4882a593Smuzhiyun 
1684*4882a593Smuzhiyun static int
mptsas_slave_configure(struct scsi_device * sdev)1685*4882a593Smuzhiyun mptsas_slave_configure(struct scsi_device *sdev)
1686*4882a593Smuzhiyun {
1687*4882a593Smuzhiyun 	struct Scsi_Host	*host = sdev->host;
1688*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd = shost_priv(host);
1689*4882a593Smuzhiyun 	MPT_ADAPTER	*ioc = hd->ioc;
1690*4882a593Smuzhiyun 	VirtDevice	*vdevice = sdev->hostdata;
1691*4882a593Smuzhiyun 
1692*4882a593Smuzhiyun 	if (vdevice->vtarget->deleted) {
1693*4882a593Smuzhiyun 		sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1694*4882a593Smuzhiyun 		vdevice->vtarget->deleted = 0;
1695*4882a593Smuzhiyun 	}
1696*4882a593Smuzhiyun 
1697*4882a593Smuzhiyun 	/*
1698*4882a593Smuzhiyun 	 * RAID volumes placed beyond the last expected port.
1699*4882a593Smuzhiyun 	 * Ignore sending sas mode pages in that case..
1700*4882a593Smuzhiyun 	 */
1701*4882a593Smuzhiyun 	if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1702*4882a593Smuzhiyun 		mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
1703*4882a593Smuzhiyun 		goto out;
1704*4882a593Smuzhiyun 	}
1705*4882a593Smuzhiyun 
1706*4882a593Smuzhiyun 	sas_read_port_mode_page(sdev);
1707*4882a593Smuzhiyun 
1708*4882a593Smuzhiyun 	mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1709*4882a593Smuzhiyun 
1710*4882a593Smuzhiyun  out:
1711*4882a593Smuzhiyun 	return mptscsih_slave_configure(sdev);
1712*4882a593Smuzhiyun }
1713*4882a593Smuzhiyun 
1714*4882a593Smuzhiyun static int
mptsas_target_alloc(struct scsi_target * starget)1715*4882a593Smuzhiyun mptsas_target_alloc(struct scsi_target *starget)
1716*4882a593Smuzhiyun {
1717*4882a593Smuzhiyun 	struct Scsi_Host *host = dev_to_shost(&starget->dev);
1718*4882a593Smuzhiyun 	MPT_SCSI_HOST		*hd = shost_priv(host);
1719*4882a593Smuzhiyun 	VirtTarget		*vtarget;
1720*4882a593Smuzhiyun 	u8			id, channel;
1721*4882a593Smuzhiyun 	struct sas_rphy		*rphy;
1722*4882a593Smuzhiyun 	struct mptsas_portinfo	*p;
1723*4882a593Smuzhiyun 	int 			 i;
1724*4882a593Smuzhiyun 	MPT_ADAPTER		*ioc = hd->ioc;
1725*4882a593Smuzhiyun 
1726*4882a593Smuzhiyun 	vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1727*4882a593Smuzhiyun 	if (!vtarget)
1728*4882a593Smuzhiyun 		return -ENOMEM;
1729*4882a593Smuzhiyun 
1730*4882a593Smuzhiyun 	vtarget->starget = starget;
1731*4882a593Smuzhiyun 	vtarget->ioc_id = ioc->id;
1732*4882a593Smuzhiyun 	vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1733*4882a593Smuzhiyun 	id = starget->id;
1734*4882a593Smuzhiyun 	channel = 0;
1735*4882a593Smuzhiyun 
1736*4882a593Smuzhiyun 	/*
1737*4882a593Smuzhiyun 	 * RAID volumes placed beyond the last expected port.
1738*4882a593Smuzhiyun 	 */
1739*4882a593Smuzhiyun 	if (starget->channel == MPTSAS_RAID_CHANNEL) {
1740*4882a593Smuzhiyun 		if (!ioc->raid_data.pIocPg2) {
1741*4882a593Smuzhiyun 			kfree(vtarget);
1742*4882a593Smuzhiyun 			return -ENXIO;
1743*4882a593Smuzhiyun 		}
1744*4882a593Smuzhiyun 		for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1745*4882a593Smuzhiyun 			if (id == ioc->raid_data.pIocPg2->
1746*4882a593Smuzhiyun 					RaidVolume[i].VolumeID) {
1747*4882a593Smuzhiyun 				channel = ioc->raid_data.pIocPg2->
1748*4882a593Smuzhiyun 					RaidVolume[i].VolumeBus;
1749*4882a593Smuzhiyun 			}
1750*4882a593Smuzhiyun 		}
1751*4882a593Smuzhiyun 		vtarget->raidVolume = 1;
1752*4882a593Smuzhiyun 		goto out;
1753*4882a593Smuzhiyun 	}
1754*4882a593Smuzhiyun 
1755*4882a593Smuzhiyun 	rphy = dev_to_rphy(starget->dev.parent);
1756*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
1757*4882a593Smuzhiyun 	list_for_each_entry(p, &ioc->sas_topology, list) {
1758*4882a593Smuzhiyun 		for (i = 0; i < p->num_phys; i++) {
1759*4882a593Smuzhiyun 			if (p->phy_info[i].attached.sas_address !=
1760*4882a593Smuzhiyun 					rphy->identify.sas_address)
1761*4882a593Smuzhiyun 				continue;
1762*4882a593Smuzhiyun 			id = p->phy_info[i].attached.id;
1763*4882a593Smuzhiyun 			channel = p->phy_info[i].attached.channel;
1764*4882a593Smuzhiyun 			mptsas_set_starget(&p->phy_info[i], starget);
1765*4882a593Smuzhiyun 
1766*4882a593Smuzhiyun 			/*
1767*4882a593Smuzhiyun 			 * Exposing hidden raid components
1768*4882a593Smuzhiyun 			 */
1769*4882a593Smuzhiyun 			if (mptscsih_is_phys_disk(ioc, channel, id)) {
1770*4882a593Smuzhiyun 				id = mptscsih_raid_id_to_num(ioc,
1771*4882a593Smuzhiyun 						channel, id);
1772*4882a593Smuzhiyun 				vtarget->tflags |=
1773*4882a593Smuzhiyun 				    MPT_TARGET_FLAGS_RAID_COMPONENT;
1774*4882a593Smuzhiyun 				p->phy_info[i].attached.phys_disk_num = id;
1775*4882a593Smuzhiyun 			}
1776*4882a593Smuzhiyun 			mutex_unlock(&ioc->sas_topology_mutex);
1777*4882a593Smuzhiyun 			goto out;
1778*4882a593Smuzhiyun 		}
1779*4882a593Smuzhiyun 	}
1780*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
1781*4882a593Smuzhiyun 
1782*4882a593Smuzhiyun 	kfree(vtarget);
1783*4882a593Smuzhiyun 	return -ENXIO;
1784*4882a593Smuzhiyun 
1785*4882a593Smuzhiyun  out:
1786*4882a593Smuzhiyun 	vtarget->id = id;
1787*4882a593Smuzhiyun 	vtarget->channel = channel;
1788*4882a593Smuzhiyun 	starget->hostdata = vtarget;
1789*4882a593Smuzhiyun 	return 0;
1790*4882a593Smuzhiyun }
1791*4882a593Smuzhiyun 
1792*4882a593Smuzhiyun static void
mptsas_target_destroy(struct scsi_target * starget)1793*4882a593Smuzhiyun mptsas_target_destroy(struct scsi_target *starget)
1794*4882a593Smuzhiyun {
1795*4882a593Smuzhiyun 	struct Scsi_Host *host = dev_to_shost(&starget->dev);
1796*4882a593Smuzhiyun 	MPT_SCSI_HOST		*hd = shost_priv(host);
1797*4882a593Smuzhiyun 	struct sas_rphy		*rphy;
1798*4882a593Smuzhiyun 	struct mptsas_portinfo	*p;
1799*4882a593Smuzhiyun 	int 			 i;
1800*4882a593Smuzhiyun 	MPT_ADAPTER	*ioc = hd->ioc;
1801*4882a593Smuzhiyun 	VirtTarget	*vtarget;
1802*4882a593Smuzhiyun 
1803*4882a593Smuzhiyun 	if (!starget->hostdata)
1804*4882a593Smuzhiyun 		return;
1805*4882a593Smuzhiyun 
1806*4882a593Smuzhiyun 	vtarget = starget->hostdata;
1807*4882a593Smuzhiyun 
1808*4882a593Smuzhiyun 	mptsas_del_device_component_by_os(ioc, starget->channel,
1809*4882a593Smuzhiyun 	    starget->id);
1810*4882a593Smuzhiyun 
1811*4882a593Smuzhiyun 
1812*4882a593Smuzhiyun 	if (starget->channel == MPTSAS_RAID_CHANNEL)
1813*4882a593Smuzhiyun 		goto out;
1814*4882a593Smuzhiyun 
1815*4882a593Smuzhiyun 	rphy = dev_to_rphy(starget->dev.parent);
1816*4882a593Smuzhiyun 	list_for_each_entry(p, &ioc->sas_topology, list) {
1817*4882a593Smuzhiyun 		for (i = 0; i < p->num_phys; i++) {
1818*4882a593Smuzhiyun 			if (p->phy_info[i].attached.sas_address !=
1819*4882a593Smuzhiyun 					rphy->identify.sas_address)
1820*4882a593Smuzhiyun 				continue;
1821*4882a593Smuzhiyun 
1822*4882a593Smuzhiyun 			starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1823*4882a593Smuzhiyun 			"delete device: fw_channel %d, fw_id %d, phy %d, "
1824*4882a593Smuzhiyun 			"sas_addr 0x%llx\n", ioc->name,
1825*4882a593Smuzhiyun 			p->phy_info[i].attached.channel,
1826*4882a593Smuzhiyun 			p->phy_info[i].attached.id,
1827*4882a593Smuzhiyun 			p->phy_info[i].attached.phy_id, (unsigned long long)
1828*4882a593Smuzhiyun 			p->phy_info[i].attached.sas_address);
1829*4882a593Smuzhiyun 
1830*4882a593Smuzhiyun 			mptsas_set_starget(&p->phy_info[i], NULL);
1831*4882a593Smuzhiyun 		}
1832*4882a593Smuzhiyun 	}
1833*4882a593Smuzhiyun 
1834*4882a593Smuzhiyun  out:
1835*4882a593Smuzhiyun 	vtarget->starget = NULL;
1836*4882a593Smuzhiyun 	kfree(starget->hostdata);
1837*4882a593Smuzhiyun 	starget->hostdata = NULL;
1838*4882a593Smuzhiyun }
1839*4882a593Smuzhiyun 
1840*4882a593Smuzhiyun 
1841*4882a593Smuzhiyun static int
mptsas_slave_alloc(struct scsi_device * sdev)1842*4882a593Smuzhiyun mptsas_slave_alloc(struct scsi_device *sdev)
1843*4882a593Smuzhiyun {
1844*4882a593Smuzhiyun 	struct Scsi_Host	*host = sdev->host;
1845*4882a593Smuzhiyun 	MPT_SCSI_HOST		*hd = shost_priv(host);
1846*4882a593Smuzhiyun 	struct sas_rphy		*rphy;
1847*4882a593Smuzhiyun 	struct mptsas_portinfo	*p;
1848*4882a593Smuzhiyun 	VirtDevice		*vdevice;
1849*4882a593Smuzhiyun 	struct scsi_target 	*starget;
1850*4882a593Smuzhiyun 	int 			i;
1851*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = hd->ioc;
1852*4882a593Smuzhiyun 
1853*4882a593Smuzhiyun 	vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1854*4882a593Smuzhiyun 	if (!vdevice) {
1855*4882a593Smuzhiyun 		printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
1856*4882a593Smuzhiyun 				ioc->name, sizeof(VirtDevice));
1857*4882a593Smuzhiyun 		return -ENOMEM;
1858*4882a593Smuzhiyun 	}
1859*4882a593Smuzhiyun 	starget = scsi_target(sdev);
1860*4882a593Smuzhiyun 	vdevice->vtarget = starget->hostdata;
1861*4882a593Smuzhiyun 
1862*4882a593Smuzhiyun 	if (sdev->channel == MPTSAS_RAID_CHANNEL)
1863*4882a593Smuzhiyun 		goto out;
1864*4882a593Smuzhiyun 
1865*4882a593Smuzhiyun 	rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
1866*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
1867*4882a593Smuzhiyun 	list_for_each_entry(p, &ioc->sas_topology, list) {
1868*4882a593Smuzhiyun 		for (i = 0; i < p->num_phys; i++) {
1869*4882a593Smuzhiyun 			if (p->phy_info[i].attached.sas_address !=
1870*4882a593Smuzhiyun 					rphy->identify.sas_address)
1871*4882a593Smuzhiyun 				continue;
1872*4882a593Smuzhiyun 			vdevice->lun = sdev->lun;
1873*4882a593Smuzhiyun 			/*
1874*4882a593Smuzhiyun 			 * Exposing hidden raid components
1875*4882a593Smuzhiyun 			 */
1876*4882a593Smuzhiyun 			if (mptscsih_is_phys_disk(ioc,
1877*4882a593Smuzhiyun 			    p->phy_info[i].attached.channel,
1878*4882a593Smuzhiyun 			    p->phy_info[i].attached.id))
1879*4882a593Smuzhiyun 				sdev->no_uld_attach = 1;
1880*4882a593Smuzhiyun 			mutex_unlock(&ioc->sas_topology_mutex);
1881*4882a593Smuzhiyun 			goto out;
1882*4882a593Smuzhiyun 		}
1883*4882a593Smuzhiyun 	}
1884*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
1885*4882a593Smuzhiyun 
1886*4882a593Smuzhiyun 	kfree(vdevice);
1887*4882a593Smuzhiyun 	return -ENXIO;
1888*4882a593Smuzhiyun 
1889*4882a593Smuzhiyun  out:
1890*4882a593Smuzhiyun 	vdevice->vtarget->num_luns++;
1891*4882a593Smuzhiyun 	sdev->hostdata = vdevice;
1892*4882a593Smuzhiyun 	return 0;
1893*4882a593Smuzhiyun }
1894*4882a593Smuzhiyun 
1895*4882a593Smuzhiyun static int
mptsas_qcmd(struct Scsi_Host * shost,struct scsi_cmnd * SCpnt)1896*4882a593Smuzhiyun mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
1897*4882a593Smuzhiyun {
1898*4882a593Smuzhiyun 	MPT_SCSI_HOST	*hd;
1899*4882a593Smuzhiyun 	MPT_ADAPTER	*ioc;
1900*4882a593Smuzhiyun 	VirtDevice	*vdevice = SCpnt->device->hostdata;
1901*4882a593Smuzhiyun 
1902*4882a593Smuzhiyun 	if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
1903*4882a593Smuzhiyun 		SCpnt->result = DID_NO_CONNECT << 16;
1904*4882a593Smuzhiyun 		SCpnt->scsi_done(SCpnt);
1905*4882a593Smuzhiyun 		return 0;
1906*4882a593Smuzhiyun 	}
1907*4882a593Smuzhiyun 
1908*4882a593Smuzhiyun 	hd = shost_priv(shost);
1909*4882a593Smuzhiyun 	ioc = hd->ioc;
1910*4882a593Smuzhiyun 
1911*4882a593Smuzhiyun 	if (ioc->sas_discovery_quiesce_io)
1912*4882a593Smuzhiyun 		return SCSI_MLQUEUE_HOST_BUSY;
1913*4882a593Smuzhiyun 
1914*4882a593Smuzhiyun 	if (ioc->debug_level & MPT_DEBUG_SCSI)
1915*4882a593Smuzhiyun 		scsi_print_command(SCpnt);
1916*4882a593Smuzhiyun 
1917*4882a593Smuzhiyun 	return mptscsih_qcmd(SCpnt);
1918*4882a593Smuzhiyun }
1919*4882a593Smuzhiyun 
1920*4882a593Smuzhiyun /**
1921*4882a593Smuzhiyun  *	mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
1922*4882a593Smuzhiyun  *		if the device under question is currently in the
1923*4882a593Smuzhiyun  *		device removal delay.
1924*4882a593Smuzhiyun  *	@sc: scsi command that the midlayer is about to time out
1925*4882a593Smuzhiyun  *
1926*4882a593Smuzhiyun  **/
mptsas_eh_timed_out(struct scsi_cmnd * sc)1927*4882a593Smuzhiyun static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
1928*4882a593Smuzhiyun {
1929*4882a593Smuzhiyun 	MPT_SCSI_HOST *hd;
1930*4882a593Smuzhiyun 	MPT_ADAPTER   *ioc;
1931*4882a593Smuzhiyun 	VirtDevice    *vdevice;
1932*4882a593Smuzhiyun 	enum blk_eh_timer_return rc = BLK_EH_DONE;
1933*4882a593Smuzhiyun 
1934*4882a593Smuzhiyun 	hd = shost_priv(sc->device->host);
1935*4882a593Smuzhiyun 	if (hd == NULL) {
1936*4882a593Smuzhiyun 		printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
1937*4882a593Smuzhiyun 		    __func__, sc);
1938*4882a593Smuzhiyun 		goto done;
1939*4882a593Smuzhiyun 	}
1940*4882a593Smuzhiyun 
1941*4882a593Smuzhiyun 	ioc = hd->ioc;
1942*4882a593Smuzhiyun 	if (ioc->bus_type != SAS) {
1943*4882a593Smuzhiyun 		printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
1944*4882a593Smuzhiyun 		    __func__, sc);
1945*4882a593Smuzhiyun 		goto done;
1946*4882a593Smuzhiyun 	}
1947*4882a593Smuzhiyun 
1948*4882a593Smuzhiyun 	/* In case if IOC is in reset from internal context.
1949*4882a593Smuzhiyun 	*  Do not execute EEH for the same IOC. SML should to reset timer.
1950*4882a593Smuzhiyun 	*/
1951*4882a593Smuzhiyun 	if (ioc->ioc_reset_in_progress) {
1952*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset,"
1953*4882a593Smuzhiyun 		    "SML need to reset the timer (sc=%p)\n",
1954*4882a593Smuzhiyun 		    ioc->name, __func__, sc));
1955*4882a593Smuzhiyun 		rc = BLK_EH_RESET_TIMER;
1956*4882a593Smuzhiyun 	}
1957*4882a593Smuzhiyun 	vdevice = sc->device->hostdata;
1958*4882a593Smuzhiyun 	if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
1959*4882a593Smuzhiyun 		|| vdevice->vtarget->deleted)) {
1960*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
1961*4882a593Smuzhiyun 		    "or in device removal delay (sc=%p)\n",
1962*4882a593Smuzhiyun 		    ioc->name, __func__, sc));
1963*4882a593Smuzhiyun 		rc = BLK_EH_RESET_TIMER;
1964*4882a593Smuzhiyun 		goto done;
1965*4882a593Smuzhiyun 	}
1966*4882a593Smuzhiyun 
1967*4882a593Smuzhiyun done:
1968*4882a593Smuzhiyun 	return rc;
1969*4882a593Smuzhiyun }
1970*4882a593Smuzhiyun 
1971*4882a593Smuzhiyun 
1972*4882a593Smuzhiyun static struct scsi_host_template mptsas_driver_template = {
1973*4882a593Smuzhiyun 	.module				= THIS_MODULE,
1974*4882a593Smuzhiyun 	.proc_name			= "mptsas",
1975*4882a593Smuzhiyun 	.show_info			= mptscsih_show_info,
1976*4882a593Smuzhiyun 	.name				= "MPT SAS Host",
1977*4882a593Smuzhiyun 	.info				= mptscsih_info,
1978*4882a593Smuzhiyun 	.queuecommand			= mptsas_qcmd,
1979*4882a593Smuzhiyun 	.target_alloc			= mptsas_target_alloc,
1980*4882a593Smuzhiyun 	.slave_alloc			= mptsas_slave_alloc,
1981*4882a593Smuzhiyun 	.slave_configure		= mptsas_slave_configure,
1982*4882a593Smuzhiyun 	.target_destroy			= mptsas_target_destroy,
1983*4882a593Smuzhiyun 	.slave_destroy			= mptscsih_slave_destroy,
1984*4882a593Smuzhiyun 	.change_queue_depth 		= mptscsih_change_queue_depth,
1985*4882a593Smuzhiyun 	.eh_timed_out			= mptsas_eh_timed_out,
1986*4882a593Smuzhiyun 	.eh_abort_handler		= mptscsih_abort,
1987*4882a593Smuzhiyun 	.eh_device_reset_handler	= mptscsih_dev_reset,
1988*4882a593Smuzhiyun 	.eh_host_reset_handler		= mptscsih_host_reset,
1989*4882a593Smuzhiyun 	.bios_param			= mptscsih_bios_param,
1990*4882a593Smuzhiyun 	.can_queue			= MPT_SAS_CAN_QUEUE,
1991*4882a593Smuzhiyun 	.this_id			= -1,
1992*4882a593Smuzhiyun 	.sg_tablesize			= MPT_SCSI_SG_DEPTH,
1993*4882a593Smuzhiyun 	.max_sectors			= 8192,
1994*4882a593Smuzhiyun 	.cmd_per_lun			= 7,
1995*4882a593Smuzhiyun 	.shost_attrs			= mptscsih_host_attrs,
1996*4882a593Smuzhiyun 	.no_write_same			= 1,
1997*4882a593Smuzhiyun };
1998*4882a593Smuzhiyun 
mptsas_get_linkerrors(struct sas_phy * phy)1999*4882a593Smuzhiyun static int mptsas_get_linkerrors(struct sas_phy *phy)
2000*4882a593Smuzhiyun {
2001*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = phy_to_ioc(phy);
2002*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2003*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2004*4882a593Smuzhiyun 	SasPhyPage1_t *buffer;
2005*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2006*4882a593Smuzhiyun 	int error;
2007*4882a593Smuzhiyun 
2008*4882a593Smuzhiyun 	/* FIXME: only have link errors on local phys */
2009*4882a593Smuzhiyun 	if (!scsi_is_sas_phy_local(phy))
2010*4882a593Smuzhiyun 		return -EINVAL;
2011*4882a593Smuzhiyun 
2012*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
2013*4882a593Smuzhiyun 	hdr.ExtPageLength = 0;
2014*4882a593Smuzhiyun 	hdr.PageNumber = 1 /* page number 1*/;
2015*4882a593Smuzhiyun 	hdr.Reserved1 = 0;
2016*4882a593Smuzhiyun 	hdr.Reserved2 = 0;
2017*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2018*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2019*4882a593Smuzhiyun 
2020*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2021*4882a593Smuzhiyun 	cfg.physAddr = -1;
2022*4882a593Smuzhiyun 	cfg.pageAddr = phy->identify.phy_identifier;
2023*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2024*4882a593Smuzhiyun 	cfg.dir = 0;    /* read */
2025*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2026*4882a593Smuzhiyun 
2027*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2028*4882a593Smuzhiyun 	if (error)
2029*4882a593Smuzhiyun 		return error;
2030*4882a593Smuzhiyun 	if (!hdr.ExtPageLength)
2031*4882a593Smuzhiyun 		return -ENXIO;
2032*4882a593Smuzhiyun 
2033*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2034*4882a593Smuzhiyun 				      &dma_handle);
2035*4882a593Smuzhiyun 	if (!buffer)
2036*4882a593Smuzhiyun 		return -ENOMEM;
2037*4882a593Smuzhiyun 
2038*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2039*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2040*4882a593Smuzhiyun 
2041*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2042*4882a593Smuzhiyun 	if (error)
2043*4882a593Smuzhiyun 		goto out_free_consistent;
2044*4882a593Smuzhiyun 
2045*4882a593Smuzhiyun 	mptsas_print_phy_pg1(ioc, buffer);
2046*4882a593Smuzhiyun 
2047*4882a593Smuzhiyun 	phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
2048*4882a593Smuzhiyun 	phy->running_disparity_error_count =
2049*4882a593Smuzhiyun 		le32_to_cpu(buffer->RunningDisparityErrorCount);
2050*4882a593Smuzhiyun 	phy->loss_of_dword_sync_count =
2051*4882a593Smuzhiyun 		le32_to_cpu(buffer->LossDwordSynchCount);
2052*4882a593Smuzhiyun 	phy->phy_reset_problem_count =
2053*4882a593Smuzhiyun 		le32_to_cpu(buffer->PhyResetProblemCount);
2054*4882a593Smuzhiyun 
2055*4882a593Smuzhiyun  out_free_consistent:
2056*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2057*4882a593Smuzhiyun 			    buffer, dma_handle);
2058*4882a593Smuzhiyun 	return error;
2059*4882a593Smuzhiyun }
2060*4882a593Smuzhiyun 
mptsas_mgmt_done(MPT_ADAPTER * ioc,MPT_FRAME_HDR * req,MPT_FRAME_HDR * reply)2061*4882a593Smuzhiyun static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2062*4882a593Smuzhiyun 		MPT_FRAME_HDR *reply)
2063*4882a593Smuzhiyun {
2064*4882a593Smuzhiyun 	ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2065*4882a593Smuzhiyun 	if (reply != NULL) {
2066*4882a593Smuzhiyun 		ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
2067*4882a593Smuzhiyun 		memcpy(ioc->sas_mgmt.reply, reply,
2068*4882a593Smuzhiyun 		    min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
2069*4882a593Smuzhiyun 	}
2070*4882a593Smuzhiyun 
2071*4882a593Smuzhiyun 	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
2072*4882a593Smuzhiyun 		ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
2073*4882a593Smuzhiyun 		complete(&ioc->sas_mgmt.done);
2074*4882a593Smuzhiyun 		return 1;
2075*4882a593Smuzhiyun 	}
2076*4882a593Smuzhiyun 	return 0;
2077*4882a593Smuzhiyun }
2078*4882a593Smuzhiyun 
mptsas_phy_reset(struct sas_phy * phy,int hard_reset)2079*4882a593Smuzhiyun static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2080*4882a593Smuzhiyun {
2081*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = phy_to_ioc(phy);
2082*4882a593Smuzhiyun 	SasIoUnitControlRequest_t *req;
2083*4882a593Smuzhiyun 	SasIoUnitControlReply_t *reply;
2084*4882a593Smuzhiyun 	MPT_FRAME_HDR *mf;
2085*4882a593Smuzhiyun 	MPIHeader_t *hdr;
2086*4882a593Smuzhiyun 	unsigned long timeleft;
2087*4882a593Smuzhiyun 	int error = -ERESTARTSYS;
2088*4882a593Smuzhiyun 
2089*4882a593Smuzhiyun 	/* FIXME: fusion doesn't allow non-local phy reset */
2090*4882a593Smuzhiyun 	if (!scsi_is_sas_phy_local(phy))
2091*4882a593Smuzhiyun 		return -EINVAL;
2092*4882a593Smuzhiyun 
2093*4882a593Smuzhiyun 	/* not implemented for expanders */
2094*4882a593Smuzhiyun 	if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2095*4882a593Smuzhiyun 		return -ENXIO;
2096*4882a593Smuzhiyun 
2097*4882a593Smuzhiyun 	if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
2098*4882a593Smuzhiyun 		goto out;
2099*4882a593Smuzhiyun 
2100*4882a593Smuzhiyun 	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2101*4882a593Smuzhiyun 	if (!mf) {
2102*4882a593Smuzhiyun 		error = -ENOMEM;
2103*4882a593Smuzhiyun 		goto out_unlock;
2104*4882a593Smuzhiyun 	}
2105*4882a593Smuzhiyun 
2106*4882a593Smuzhiyun 	hdr = (MPIHeader_t *) mf;
2107*4882a593Smuzhiyun 	req = (SasIoUnitControlRequest_t *)mf;
2108*4882a593Smuzhiyun 	memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2109*4882a593Smuzhiyun 	req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2110*4882a593Smuzhiyun 	req->MsgContext = hdr->MsgContext;
2111*4882a593Smuzhiyun 	req->Operation = hard_reset ?
2112*4882a593Smuzhiyun 		MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2113*4882a593Smuzhiyun 	req->PhyNum = phy->identify.phy_identifier;
2114*4882a593Smuzhiyun 
2115*4882a593Smuzhiyun 	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2116*4882a593Smuzhiyun 	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2117*4882a593Smuzhiyun 
2118*4882a593Smuzhiyun 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2119*4882a593Smuzhiyun 			10 * HZ);
2120*4882a593Smuzhiyun 	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2121*4882a593Smuzhiyun 		error = -ETIME;
2122*4882a593Smuzhiyun 		mpt_free_msg_frame(ioc, mf);
2123*4882a593Smuzhiyun 		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2124*4882a593Smuzhiyun 			goto out_unlock;
2125*4882a593Smuzhiyun 		if (!timeleft)
2126*4882a593Smuzhiyun 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
2127*4882a593Smuzhiyun 		goto out_unlock;
2128*4882a593Smuzhiyun 	}
2129*4882a593Smuzhiyun 
2130*4882a593Smuzhiyun 	/* a reply frame is expected */
2131*4882a593Smuzhiyun 	if ((ioc->sas_mgmt.status &
2132*4882a593Smuzhiyun 	    MPT_MGMT_STATUS_RF_VALID) == 0) {
2133*4882a593Smuzhiyun 		error = -ENXIO;
2134*4882a593Smuzhiyun 		goto out_unlock;
2135*4882a593Smuzhiyun 	}
2136*4882a593Smuzhiyun 
2137*4882a593Smuzhiyun 	/* process the completed Reply Message Frame */
2138*4882a593Smuzhiyun 	reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2139*4882a593Smuzhiyun 	if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
2140*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
2141*4882a593Smuzhiyun 		    ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
2142*4882a593Smuzhiyun 		error = -ENXIO;
2143*4882a593Smuzhiyun 		goto out_unlock;
2144*4882a593Smuzhiyun 	}
2145*4882a593Smuzhiyun 
2146*4882a593Smuzhiyun 	error = 0;
2147*4882a593Smuzhiyun 
2148*4882a593Smuzhiyun  out_unlock:
2149*4882a593Smuzhiyun 	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2150*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_mgmt.mutex);
2151*4882a593Smuzhiyun  out:
2152*4882a593Smuzhiyun 	return error;
2153*4882a593Smuzhiyun }
2154*4882a593Smuzhiyun 
2155*4882a593Smuzhiyun static int
mptsas_get_enclosure_identifier(struct sas_rphy * rphy,u64 * identifier)2156*4882a593Smuzhiyun mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2157*4882a593Smuzhiyun {
2158*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2159*4882a593Smuzhiyun 	int i, error;
2160*4882a593Smuzhiyun 	struct mptsas_portinfo *p;
2161*4882a593Smuzhiyun 	struct mptsas_enclosure enclosure_info;
2162*4882a593Smuzhiyun 	u64 enclosure_handle;
2163*4882a593Smuzhiyun 
2164*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
2165*4882a593Smuzhiyun 	list_for_each_entry(p, &ioc->sas_topology, list) {
2166*4882a593Smuzhiyun 		for (i = 0; i < p->num_phys; i++) {
2167*4882a593Smuzhiyun 			if (p->phy_info[i].attached.sas_address ==
2168*4882a593Smuzhiyun 			    rphy->identify.sas_address) {
2169*4882a593Smuzhiyun 				enclosure_handle = p->phy_info[i].
2170*4882a593Smuzhiyun 					attached.handle_enclosure;
2171*4882a593Smuzhiyun 				goto found_info;
2172*4882a593Smuzhiyun 			}
2173*4882a593Smuzhiyun 		}
2174*4882a593Smuzhiyun 	}
2175*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
2176*4882a593Smuzhiyun 	return -ENXIO;
2177*4882a593Smuzhiyun 
2178*4882a593Smuzhiyun  found_info:
2179*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
2180*4882a593Smuzhiyun 	memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
2181*4882a593Smuzhiyun 	error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
2182*4882a593Smuzhiyun 			(MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2183*4882a593Smuzhiyun 			 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2184*4882a593Smuzhiyun 	if (!error)
2185*4882a593Smuzhiyun 		*identifier = enclosure_info.enclosure_logical_id;
2186*4882a593Smuzhiyun 	return error;
2187*4882a593Smuzhiyun }
2188*4882a593Smuzhiyun 
2189*4882a593Smuzhiyun static int
mptsas_get_bay_identifier(struct sas_rphy * rphy)2190*4882a593Smuzhiyun mptsas_get_bay_identifier(struct sas_rphy *rphy)
2191*4882a593Smuzhiyun {
2192*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2193*4882a593Smuzhiyun 	struct mptsas_portinfo *p;
2194*4882a593Smuzhiyun 	int i, rc;
2195*4882a593Smuzhiyun 
2196*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
2197*4882a593Smuzhiyun 	list_for_each_entry(p, &ioc->sas_topology, list) {
2198*4882a593Smuzhiyun 		for (i = 0; i < p->num_phys; i++) {
2199*4882a593Smuzhiyun 			if (p->phy_info[i].attached.sas_address ==
2200*4882a593Smuzhiyun 			    rphy->identify.sas_address) {
2201*4882a593Smuzhiyun 				rc = p->phy_info[i].attached.slot;
2202*4882a593Smuzhiyun 				goto out;
2203*4882a593Smuzhiyun 			}
2204*4882a593Smuzhiyun 		}
2205*4882a593Smuzhiyun 	}
2206*4882a593Smuzhiyun 	rc = -ENXIO;
2207*4882a593Smuzhiyun  out:
2208*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
2209*4882a593Smuzhiyun 	return rc;
2210*4882a593Smuzhiyun }
2211*4882a593Smuzhiyun 
mptsas_smp_handler(struct bsg_job * job,struct Scsi_Host * shost,struct sas_rphy * rphy)2212*4882a593Smuzhiyun static void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
2213*4882a593Smuzhiyun 		struct sas_rphy *rphy)
2214*4882a593Smuzhiyun {
2215*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2216*4882a593Smuzhiyun 	MPT_FRAME_HDR *mf;
2217*4882a593Smuzhiyun 	SmpPassthroughRequest_t *smpreq;
2218*4882a593Smuzhiyun 	int flagsLength;
2219*4882a593Smuzhiyun 	unsigned long timeleft;
2220*4882a593Smuzhiyun 	char *psge;
2221*4882a593Smuzhiyun 	u64 sas_address = 0;
2222*4882a593Smuzhiyun 	unsigned int reslen = 0;
2223*4882a593Smuzhiyun 	int ret = -EINVAL;
2224*4882a593Smuzhiyun 
2225*4882a593Smuzhiyun 	/* do we need to support multiple segments? */
2226*4882a593Smuzhiyun 	if (job->request_payload.sg_cnt > 1 ||
2227*4882a593Smuzhiyun 	    job->reply_payload.sg_cnt > 1) {
2228*4882a593Smuzhiyun 		printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n",
2229*4882a593Smuzhiyun 		    ioc->name, __func__, job->request_payload.payload_len,
2230*4882a593Smuzhiyun 		    job->reply_payload.payload_len);
2231*4882a593Smuzhiyun 		goto out;
2232*4882a593Smuzhiyun 	}
2233*4882a593Smuzhiyun 
2234*4882a593Smuzhiyun 	ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2235*4882a593Smuzhiyun 	if (ret)
2236*4882a593Smuzhiyun 		goto out;
2237*4882a593Smuzhiyun 
2238*4882a593Smuzhiyun 	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2239*4882a593Smuzhiyun 	if (!mf) {
2240*4882a593Smuzhiyun 		ret = -ENOMEM;
2241*4882a593Smuzhiyun 		goto out_unlock;
2242*4882a593Smuzhiyun 	}
2243*4882a593Smuzhiyun 
2244*4882a593Smuzhiyun 	smpreq = (SmpPassthroughRequest_t *)mf;
2245*4882a593Smuzhiyun 	memset(smpreq, 0, sizeof(*smpreq));
2246*4882a593Smuzhiyun 
2247*4882a593Smuzhiyun 	smpreq->RequestDataLength =
2248*4882a593Smuzhiyun 		cpu_to_le16(job->request_payload.payload_len - 4);
2249*4882a593Smuzhiyun 	smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2250*4882a593Smuzhiyun 
2251*4882a593Smuzhiyun 	if (rphy)
2252*4882a593Smuzhiyun 		sas_address = rphy->identify.sas_address;
2253*4882a593Smuzhiyun 	else {
2254*4882a593Smuzhiyun 		struct mptsas_portinfo *port_info;
2255*4882a593Smuzhiyun 
2256*4882a593Smuzhiyun 		mutex_lock(&ioc->sas_topology_mutex);
2257*4882a593Smuzhiyun 		port_info = ioc->hba_port_info;
2258*4882a593Smuzhiyun 		if (port_info && port_info->phy_info)
2259*4882a593Smuzhiyun 			sas_address =
2260*4882a593Smuzhiyun 				port_info->phy_info[0].phy->identify.sas_address;
2261*4882a593Smuzhiyun 		mutex_unlock(&ioc->sas_topology_mutex);
2262*4882a593Smuzhiyun 	}
2263*4882a593Smuzhiyun 
2264*4882a593Smuzhiyun 	*((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2265*4882a593Smuzhiyun 
2266*4882a593Smuzhiyun 	psge = (char *)
2267*4882a593Smuzhiyun 		(((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2268*4882a593Smuzhiyun 
2269*4882a593Smuzhiyun 	/* request */
2270*4882a593Smuzhiyun 	flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2271*4882a593Smuzhiyun 		       MPI_SGE_FLAGS_END_OF_BUFFER |
2272*4882a593Smuzhiyun 		       MPI_SGE_FLAGS_DIRECTION)
2273*4882a593Smuzhiyun 		       << MPI_SGE_FLAGS_SHIFT;
2274*4882a593Smuzhiyun 
2275*4882a593Smuzhiyun 	if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list,
2276*4882a593Smuzhiyun 			1, PCI_DMA_BIDIRECTIONAL))
2277*4882a593Smuzhiyun 		goto put_mf;
2278*4882a593Smuzhiyun 
2279*4882a593Smuzhiyun 	flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4);
2280*4882a593Smuzhiyun 	ioc->add_sge(psge, flagsLength,
2281*4882a593Smuzhiyun 			sg_dma_address(job->request_payload.sg_list));
2282*4882a593Smuzhiyun 	psge += ioc->SGE_size;
2283*4882a593Smuzhiyun 
2284*4882a593Smuzhiyun 	/* response */
2285*4882a593Smuzhiyun 	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2286*4882a593Smuzhiyun 		MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2287*4882a593Smuzhiyun 		MPI_SGE_FLAGS_IOC_TO_HOST |
2288*4882a593Smuzhiyun 		MPI_SGE_FLAGS_END_OF_BUFFER;
2289*4882a593Smuzhiyun 
2290*4882a593Smuzhiyun 	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2291*4882a593Smuzhiyun 
2292*4882a593Smuzhiyun 	if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list,
2293*4882a593Smuzhiyun 			1, PCI_DMA_BIDIRECTIONAL))
2294*4882a593Smuzhiyun 		goto unmap_out;
2295*4882a593Smuzhiyun 	flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4;
2296*4882a593Smuzhiyun 	ioc->add_sge(psge, flagsLength,
2297*4882a593Smuzhiyun 			sg_dma_address(job->reply_payload.sg_list));
2298*4882a593Smuzhiyun 
2299*4882a593Smuzhiyun 	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2300*4882a593Smuzhiyun 	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2301*4882a593Smuzhiyun 
2302*4882a593Smuzhiyun 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2303*4882a593Smuzhiyun 	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2304*4882a593Smuzhiyun 		ret = -ETIME;
2305*4882a593Smuzhiyun 		mpt_free_msg_frame(ioc, mf);
2306*4882a593Smuzhiyun 		mf = NULL;
2307*4882a593Smuzhiyun 		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2308*4882a593Smuzhiyun 			goto unmap_in;
2309*4882a593Smuzhiyun 		if (!timeleft)
2310*4882a593Smuzhiyun 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
2311*4882a593Smuzhiyun 		goto unmap_in;
2312*4882a593Smuzhiyun 	}
2313*4882a593Smuzhiyun 	mf = NULL;
2314*4882a593Smuzhiyun 
2315*4882a593Smuzhiyun 	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2316*4882a593Smuzhiyun 		SmpPassthroughReply_t *smprep;
2317*4882a593Smuzhiyun 
2318*4882a593Smuzhiyun 		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2319*4882a593Smuzhiyun 		memcpy(job->reply, smprep, sizeof(*smprep));
2320*4882a593Smuzhiyun 		job->reply_len = sizeof(*smprep);
2321*4882a593Smuzhiyun 		reslen = smprep->ResponseDataLength;
2322*4882a593Smuzhiyun 	} else {
2323*4882a593Smuzhiyun 		printk(MYIOC_s_ERR_FMT
2324*4882a593Smuzhiyun 		    "%s: smp passthru reply failed to be returned\n",
2325*4882a593Smuzhiyun 		    ioc->name, __func__);
2326*4882a593Smuzhiyun 		ret = -ENXIO;
2327*4882a593Smuzhiyun 	}
2328*4882a593Smuzhiyun 
2329*4882a593Smuzhiyun unmap_in:
2330*4882a593Smuzhiyun 	dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1,
2331*4882a593Smuzhiyun 			PCI_DMA_BIDIRECTIONAL);
2332*4882a593Smuzhiyun unmap_out:
2333*4882a593Smuzhiyun 	dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1,
2334*4882a593Smuzhiyun 			PCI_DMA_BIDIRECTIONAL);
2335*4882a593Smuzhiyun put_mf:
2336*4882a593Smuzhiyun 	if (mf)
2337*4882a593Smuzhiyun 		mpt_free_msg_frame(ioc, mf);
2338*4882a593Smuzhiyun out_unlock:
2339*4882a593Smuzhiyun 	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2340*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_mgmt.mutex);
2341*4882a593Smuzhiyun out:
2342*4882a593Smuzhiyun 	bsg_job_done(job, ret, reslen);
2343*4882a593Smuzhiyun }
2344*4882a593Smuzhiyun 
2345*4882a593Smuzhiyun static struct sas_function_template mptsas_transport_functions = {
2346*4882a593Smuzhiyun 	.get_linkerrors		= mptsas_get_linkerrors,
2347*4882a593Smuzhiyun 	.get_enclosure_identifier = mptsas_get_enclosure_identifier,
2348*4882a593Smuzhiyun 	.get_bay_identifier	= mptsas_get_bay_identifier,
2349*4882a593Smuzhiyun 	.phy_reset		= mptsas_phy_reset,
2350*4882a593Smuzhiyun 	.smp_handler		= mptsas_smp_handler,
2351*4882a593Smuzhiyun };
2352*4882a593Smuzhiyun 
2353*4882a593Smuzhiyun static struct scsi_transport_template *mptsas_transport_template;
2354*4882a593Smuzhiyun 
2355*4882a593Smuzhiyun static int
mptsas_sas_io_unit_pg0(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info)2356*4882a593Smuzhiyun mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2357*4882a593Smuzhiyun {
2358*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2359*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2360*4882a593Smuzhiyun 	SasIOUnitPage0_t *buffer;
2361*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2362*4882a593Smuzhiyun 	int error, i;
2363*4882a593Smuzhiyun 
2364*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2365*4882a593Smuzhiyun 	hdr.ExtPageLength = 0;
2366*4882a593Smuzhiyun 	hdr.PageNumber = 0;
2367*4882a593Smuzhiyun 	hdr.Reserved1 = 0;
2368*4882a593Smuzhiyun 	hdr.Reserved2 = 0;
2369*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2370*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2371*4882a593Smuzhiyun 
2372*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2373*4882a593Smuzhiyun 	cfg.physAddr = -1;
2374*4882a593Smuzhiyun 	cfg.pageAddr = 0;
2375*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2376*4882a593Smuzhiyun 	cfg.dir = 0;	/* read */
2377*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2378*4882a593Smuzhiyun 
2379*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2380*4882a593Smuzhiyun 	if (error)
2381*4882a593Smuzhiyun 		goto out;
2382*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
2383*4882a593Smuzhiyun 		error = -ENXIO;
2384*4882a593Smuzhiyun 		goto out;
2385*4882a593Smuzhiyun 	}
2386*4882a593Smuzhiyun 
2387*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2388*4882a593Smuzhiyun 					    &dma_handle);
2389*4882a593Smuzhiyun 	if (!buffer) {
2390*4882a593Smuzhiyun 		error = -ENOMEM;
2391*4882a593Smuzhiyun 		goto out;
2392*4882a593Smuzhiyun 	}
2393*4882a593Smuzhiyun 
2394*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2395*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2396*4882a593Smuzhiyun 
2397*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2398*4882a593Smuzhiyun 	if (error)
2399*4882a593Smuzhiyun 		goto out_free_consistent;
2400*4882a593Smuzhiyun 
2401*4882a593Smuzhiyun 	port_info->num_phys = buffer->NumPhys;
2402*4882a593Smuzhiyun 	port_info->phy_info = kcalloc(port_info->num_phys,
2403*4882a593Smuzhiyun 		sizeof(struct mptsas_phyinfo), GFP_KERNEL);
2404*4882a593Smuzhiyun 	if (!port_info->phy_info) {
2405*4882a593Smuzhiyun 		error = -ENOMEM;
2406*4882a593Smuzhiyun 		goto out_free_consistent;
2407*4882a593Smuzhiyun 	}
2408*4882a593Smuzhiyun 
2409*4882a593Smuzhiyun 	ioc->nvdata_version_persistent =
2410*4882a593Smuzhiyun 	    le16_to_cpu(buffer->NvdataVersionPersistent);
2411*4882a593Smuzhiyun 	ioc->nvdata_version_default =
2412*4882a593Smuzhiyun 	    le16_to_cpu(buffer->NvdataVersionDefault);
2413*4882a593Smuzhiyun 
2414*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
2415*4882a593Smuzhiyun 		mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
2416*4882a593Smuzhiyun 		port_info->phy_info[i].phy_id = i;
2417*4882a593Smuzhiyun 		port_info->phy_info[i].port_id =
2418*4882a593Smuzhiyun 		    buffer->PhyData[i].Port;
2419*4882a593Smuzhiyun 		port_info->phy_info[i].negotiated_link_rate =
2420*4882a593Smuzhiyun 		    buffer->PhyData[i].NegotiatedLinkRate;
2421*4882a593Smuzhiyun 		port_info->phy_info[i].portinfo = port_info;
2422*4882a593Smuzhiyun 		port_info->phy_info[i].handle =
2423*4882a593Smuzhiyun 		    le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
2424*4882a593Smuzhiyun 	}
2425*4882a593Smuzhiyun 
2426*4882a593Smuzhiyun  out_free_consistent:
2427*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2428*4882a593Smuzhiyun 			    buffer, dma_handle);
2429*4882a593Smuzhiyun  out:
2430*4882a593Smuzhiyun 	return error;
2431*4882a593Smuzhiyun }
2432*4882a593Smuzhiyun 
2433*4882a593Smuzhiyun static int
mptsas_sas_io_unit_pg1(MPT_ADAPTER * ioc)2434*4882a593Smuzhiyun mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2435*4882a593Smuzhiyun {
2436*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2437*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2438*4882a593Smuzhiyun 	SasIOUnitPage1_t *buffer;
2439*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2440*4882a593Smuzhiyun 	int error;
2441*4882a593Smuzhiyun 	u8 device_missing_delay;
2442*4882a593Smuzhiyun 
2443*4882a593Smuzhiyun 	memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2444*4882a593Smuzhiyun 	memset(&cfg, 0, sizeof(CONFIGPARMS));
2445*4882a593Smuzhiyun 
2446*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2447*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2448*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2449*4882a593Smuzhiyun 	cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2450*4882a593Smuzhiyun 	cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2451*4882a593Smuzhiyun 	cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2452*4882a593Smuzhiyun 	cfg.cfghdr.ehdr->PageNumber = 1;
2453*4882a593Smuzhiyun 
2454*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2455*4882a593Smuzhiyun 	if (error)
2456*4882a593Smuzhiyun 		goto out;
2457*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
2458*4882a593Smuzhiyun 		error = -ENXIO;
2459*4882a593Smuzhiyun 		goto out;
2460*4882a593Smuzhiyun 	}
2461*4882a593Smuzhiyun 
2462*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2463*4882a593Smuzhiyun 					    &dma_handle);
2464*4882a593Smuzhiyun 	if (!buffer) {
2465*4882a593Smuzhiyun 		error = -ENOMEM;
2466*4882a593Smuzhiyun 		goto out;
2467*4882a593Smuzhiyun 	}
2468*4882a593Smuzhiyun 
2469*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2470*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2471*4882a593Smuzhiyun 
2472*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2473*4882a593Smuzhiyun 	if (error)
2474*4882a593Smuzhiyun 		goto out_free_consistent;
2475*4882a593Smuzhiyun 
2476*4882a593Smuzhiyun 	ioc->io_missing_delay  =
2477*4882a593Smuzhiyun 	    le16_to_cpu(buffer->IODeviceMissingDelay);
2478*4882a593Smuzhiyun 	device_missing_delay = buffer->ReportDeviceMissingDelay;
2479*4882a593Smuzhiyun 	ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2480*4882a593Smuzhiyun 	    (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2481*4882a593Smuzhiyun 	    device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2482*4882a593Smuzhiyun 
2483*4882a593Smuzhiyun  out_free_consistent:
2484*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2485*4882a593Smuzhiyun 			    buffer, dma_handle);
2486*4882a593Smuzhiyun  out:
2487*4882a593Smuzhiyun 	return error;
2488*4882a593Smuzhiyun }
2489*4882a593Smuzhiyun 
2490*4882a593Smuzhiyun static int
mptsas_sas_phy_pg0(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,u32 form,u32 form_specific)2491*4882a593Smuzhiyun mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2492*4882a593Smuzhiyun 		u32 form, u32 form_specific)
2493*4882a593Smuzhiyun {
2494*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2495*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2496*4882a593Smuzhiyun 	SasPhyPage0_t *buffer;
2497*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2498*4882a593Smuzhiyun 	int error;
2499*4882a593Smuzhiyun 
2500*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2501*4882a593Smuzhiyun 	hdr.ExtPageLength = 0;
2502*4882a593Smuzhiyun 	hdr.PageNumber = 0;
2503*4882a593Smuzhiyun 	hdr.Reserved1 = 0;
2504*4882a593Smuzhiyun 	hdr.Reserved2 = 0;
2505*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2506*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2507*4882a593Smuzhiyun 
2508*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2509*4882a593Smuzhiyun 	cfg.dir = 0;	/* read */
2510*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2511*4882a593Smuzhiyun 
2512*4882a593Smuzhiyun 	/* Get Phy Pg 0 for each Phy. */
2513*4882a593Smuzhiyun 	cfg.physAddr = -1;
2514*4882a593Smuzhiyun 	cfg.pageAddr = form + form_specific;
2515*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2516*4882a593Smuzhiyun 
2517*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2518*4882a593Smuzhiyun 	if (error)
2519*4882a593Smuzhiyun 		goto out;
2520*4882a593Smuzhiyun 
2521*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
2522*4882a593Smuzhiyun 		error = -ENXIO;
2523*4882a593Smuzhiyun 		goto out;
2524*4882a593Smuzhiyun 	}
2525*4882a593Smuzhiyun 
2526*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2527*4882a593Smuzhiyun 				      &dma_handle);
2528*4882a593Smuzhiyun 	if (!buffer) {
2529*4882a593Smuzhiyun 		error = -ENOMEM;
2530*4882a593Smuzhiyun 		goto out;
2531*4882a593Smuzhiyun 	}
2532*4882a593Smuzhiyun 
2533*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2534*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2535*4882a593Smuzhiyun 
2536*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2537*4882a593Smuzhiyun 	if (error)
2538*4882a593Smuzhiyun 		goto out_free_consistent;
2539*4882a593Smuzhiyun 
2540*4882a593Smuzhiyun 	mptsas_print_phy_pg0(ioc, buffer);
2541*4882a593Smuzhiyun 
2542*4882a593Smuzhiyun 	phy_info->hw_link_rate = buffer->HwLinkRate;
2543*4882a593Smuzhiyun 	phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2544*4882a593Smuzhiyun 	phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2545*4882a593Smuzhiyun 	phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2546*4882a593Smuzhiyun 
2547*4882a593Smuzhiyun  out_free_consistent:
2548*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2549*4882a593Smuzhiyun 			    buffer, dma_handle);
2550*4882a593Smuzhiyun  out:
2551*4882a593Smuzhiyun 	return error;
2552*4882a593Smuzhiyun }
2553*4882a593Smuzhiyun 
2554*4882a593Smuzhiyun static int
mptsas_sas_device_pg0(MPT_ADAPTER * ioc,struct mptsas_devinfo * device_info,u32 form,u32 form_specific)2555*4882a593Smuzhiyun mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2556*4882a593Smuzhiyun 		u32 form, u32 form_specific)
2557*4882a593Smuzhiyun {
2558*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2559*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2560*4882a593Smuzhiyun 	SasDevicePage0_t *buffer;
2561*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2562*4882a593Smuzhiyun 	__le64 sas_address;
2563*4882a593Smuzhiyun 	int error=0;
2564*4882a593Smuzhiyun 
2565*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2566*4882a593Smuzhiyun 	hdr.ExtPageLength = 0;
2567*4882a593Smuzhiyun 	hdr.PageNumber = 0;
2568*4882a593Smuzhiyun 	hdr.Reserved1 = 0;
2569*4882a593Smuzhiyun 	hdr.Reserved2 = 0;
2570*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2571*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2572*4882a593Smuzhiyun 
2573*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2574*4882a593Smuzhiyun 	cfg.pageAddr = form + form_specific;
2575*4882a593Smuzhiyun 	cfg.physAddr = -1;
2576*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2577*4882a593Smuzhiyun 	cfg.dir = 0;	/* read */
2578*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2579*4882a593Smuzhiyun 
2580*4882a593Smuzhiyun 	memset(device_info, 0, sizeof(struct mptsas_devinfo));
2581*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2582*4882a593Smuzhiyun 	if (error)
2583*4882a593Smuzhiyun 		goto out;
2584*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
2585*4882a593Smuzhiyun 		error = -ENXIO;
2586*4882a593Smuzhiyun 		goto out;
2587*4882a593Smuzhiyun 	}
2588*4882a593Smuzhiyun 
2589*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2590*4882a593Smuzhiyun 				      &dma_handle);
2591*4882a593Smuzhiyun 	if (!buffer) {
2592*4882a593Smuzhiyun 		error = -ENOMEM;
2593*4882a593Smuzhiyun 		goto out;
2594*4882a593Smuzhiyun 	}
2595*4882a593Smuzhiyun 
2596*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2597*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2598*4882a593Smuzhiyun 
2599*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2600*4882a593Smuzhiyun 
2601*4882a593Smuzhiyun 	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2602*4882a593Smuzhiyun 		error = -ENODEV;
2603*4882a593Smuzhiyun 		goto out_free_consistent;
2604*4882a593Smuzhiyun 	}
2605*4882a593Smuzhiyun 
2606*4882a593Smuzhiyun 	if (error)
2607*4882a593Smuzhiyun 		goto out_free_consistent;
2608*4882a593Smuzhiyun 
2609*4882a593Smuzhiyun 	mptsas_print_device_pg0(ioc, buffer);
2610*4882a593Smuzhiyun 
2611*4882a593Smuzhiyun 	memset(device_info, 0, sizeof(struct mptsas_devinfo));
2612*4882a593Smuzhiyun 	device_info->handle = le16_to_cpu(buffer->DevHandle);
2613*4882a593Smuzhiyun 	device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
2614*4882a593Smuzhiyun 	device_info->handle_enclosure =
2615*4882a593Smuzhiyun 	    le16_to_cpu(buffer->EnclosureHandle);
2616*4882a593Smuzhiyun 	device_info->slot = le16_to_cpu(buffer->Slot);
2617*4882a593Smuzhiyun 	device_info->phy_id = buffer->PhyNum;
2618*4882a593Smuzhiyun 	device_info->port_id = buffer->PhysicalPort;
2619*4882a593Smuzhiyun 	device_info->id = buffer->TargetID;
2620*4882a593Smuzhiyun 	device_info->phys_disk_num = ~0;
2621*4882a593Smuzhiyun 	device_info->channel = buffer->Bus;
2622*4882a593Smuzhiyun 	memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2623*4882a593Smuzhiyun 	device_info->sas_address = le64_to_cpu(sas_address);
2624*4882a593Smuzhiyun 	device_info->device_info =
2625*4882a593Smuzhiyun 	    le32_to_cpu(buffer->DeviceInfo);
2626*4882a593Smuzhiyun 	device_info->flags = le16_to_cpu(buffer->Flags);
2627*4882a593Smuzhiyun 
2628*4882a593Smuzhiyun  out_free_consistent:
2629*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2630*4882a593Smuzhiyun 			    buffer, dma_handle);
2631*4882a593Smuzhiyun  out:
2632*4882a593Smuzhiyun 	return error;
2633*4882a593Smuzhiyun }
2634*4882a593Smuzhiyun 
2635*4882a593Smuzhiyun static int
mptsas_sas_expander_pg0(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info,u32 form,u32 form_specific)2636*4882a593Smuzhiyun mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2637*4882a593Smuzhiyun 		u32 form, u32 form_specific)
2638*4882a593Smuzhiyun {
2639*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2640*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2641*4882a593Smuzhiyun 	SasExpanderPage0_t *buffer;
2642*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2643*4882a593Smuzhiyun 	int i, error;
2644*4882a593Smuzhiyun 	__le64 sas_address;
2645*4882a593Smuzhiyun 
2646*4882a593Smuzhiyun 	memset(port_info, 0, sizeof(struct mptsas_portinfo));
2647*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2648*4882a593Smuzhiyun 	hdr.ExtPageLength = 0;
2649*4882a593Smuzhiyun 	hdr.PageNumber = 0;
2650*4882a593Smuzhiyun 	hdr.Reserved1 = 0;
2651*4882a593Smuzhiyun 	hdr.Reserved2 = 0;
2652*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2653*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2654*4882a593Smuzhiyun 
2655*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2656*4882a593Smuzhiyun 	cfg.physAddr = -1;
2657*4882a593Smuzhiyun 	cfg.pageAddr = form + form_specific;
2658*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2659*4882a593Smuzhiyun 	cfg.dir = 0;	/* read */
2660*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2661*4882a593Smuzhiyun 
2662*4882a593Smuzhiyun 	memset(port_info, 0, sizeof(struct mptsas_portinfo));
2663*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2664*4882a593Smuzhiyun 	if (error)
2665*4882a593Smuzhiyun 		goto out;
2666*4882a593Smuzhiyun 
2667*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
2668*4882a593Smuzhiyun 		error = -ENXIO;
2669*4882a593Smuzhiyun 		goto out;
2670*4882a593Smuzhiyun 	}
2671*4882a593Smuzhiyun 
2672*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2673*4882a593Smuzhiyun 				      &dma_handle);
2674*4882a593Smuzhiyun 	if (!buffer) {
2675*4882a593Smuzhiyun 		error = -ENOMEM;
2676*4882a593Smuzhiyun 		goto out;
2677*4882a593Smuzhiyun 	}
2678*4882a593Smuzhiyun 
2679*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2680*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2681*4882a593Smuzhiyun 
2682*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2683*4882a593Smuzhiyun 	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2684*4882a593Smuzhiyun 		error = -ENODEV;
2685*4882a593Smuzhiyun 		goto out_free_consistent;
2686*4882a593Smuzhiyun 	}
2687*4882a593Smuzhiyun 
2688*4882a593Smuzhiyun 	if (error)
2689*4882a593Smuzhiyun 		goto out_free_consistent;
2690*4882a593Smuzhiyun 
2691*4882a593Smuzhiyun 	/* save config data */
2692*4882a593Smuzhiyun 	port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
2693*4882a593Smuzhiyun 	port_info->phy_info = kcalloc(port_info->num_phys,
2694*4882a593Smuzhiyun 		sizeof(struct mptsas_phyinfo), GFP_KERNEL);
2695*4882a593Smuzhiyun 	if (!port_info->phy_info) {
2696*4882a593Smuzhiyun 		error = -ENOMEM;
2697*4882a593Smuzhiyun 		goto out_free_consistent;
2698*4882a593Smuzhiyun 	}
2699*4882a593Smuzhiyun 
2700*4882a593Smuzhiyun 	memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2701*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
2702*4882a593Smuzhiyun 		port_info->phy_info[i].portinfo = port_info;
2703*4882a593Smuzhiyun 		port_info->phy_info[i].handle =
2704*4882a593Smuzhiyun 		    le16_to_cpu(buffer->DevHandle);
2705*4882a593Smuzhiyun 		port_info->phy_info[i].identify.sas_address =
2706*4882a593Smuzhiyun 		    le64_to_cpu(sas_address);
2707*4882a593Smuzhiyun 		port_info->phy_info[i].identify.handle_parent =
2708*4882a593Smuzhiyun 		    le16_to_cpu(buffer->ParentDevHandle);
2709*4882a593Smuzhiyun 	}
2710*4882a593Smuzhiyun 
2711*4882a593Smuzhiyun  out_free_consistent:
2712*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2713*4882a593Smuzhiyun 			    buffer, dma_handle);
2714*4882a593Smuzhiyun  out:
2715*4882a593Smuzhiyun 	return error;
2716*4882a593Smuzhiyun }
2717*4882a593Smuzhiyun 
2718*4882a593Smuzhiyun static int
mptsas_sas_expander_pg1(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,u32 form,u32 form_specific)2719*4882a593Smuzhiyun mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2720*4882a593Smuzhiyun 		u32 form, u32 form_specific)
2721*4882a593Smuzhiyun {
2722*4882a593Smuzhiyun 	ConfigExtendedPageHeader_t hdr;
2723*4882a593Smuzhiyun 	CONFIGPARMS cfg;
2724*4882a593Smuzhiyun 	SasExpanderPage1_t *buffer;
2725*4882a593Smuzhiyun 	dma_addr_t dma_handle;
2726*4882a593Smuzhiyun 	int error=0;
2727*4882a593Smuzhiyun 
2728*4882a593Smuzhiyun 	hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
2729*4882a593Smuzhiyun 	hdr.ExtPageLength = 0;
2730*4882a593Smuzhiyun 	hdr.PageNumber = 1;
2731*4882a593Smuzhiyun 	hdr.Reserved1 = 0;
2732*4882a593Smuzhiyun 	hdr.Reserved2 = 0;
2733*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2734*4882a593Smuzhiyun 	hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2735*4882a593Smuzhiyun 
2736*4882a593Smuzhiyun 	cfg.cfghdr.ehdr = &hdr;
2737*4882a593Smuzhiyun 	cfg.physAddr = -1;
2738*4882a593Smuzhiyun 	cfg.pageAddr = form + form_specific;
2739*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2740*4882a593Smuzhiyun 	cfg.dir = 0;	/* read */
2741*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2742*4882a593Smuzhiyun 
2743*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2744*4882a593Smuzhiyun 	if (error)
2745*4882a593Smuzhiyun 		goto out;
2746*4882a593Smuzhiyun 
2747*4882a593Smuzhiyun 	if (!hdr.ExtPageLength) {
2748*4882a593Smuzhiyun 		error = -ENXIO;
2749*4882a593Smuzhiyun 		goto out;
2750*4882a593Smuzhiyun 	}
2751*4882a593Smuzhiyun 
2752*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2753*4882a593Smuzhiyun 				      &dma_handle);
2754*4882a593Smuzhiyun 	if (!buffer) {
2755*4882a593Smuzhiyun 		error = -ENOMEM;
2756*4882a593Smuzhiyun 		goto out;
2757*4882a593Smuzhiyun 	}
2758*4882a593Smuzhiyun 
2759*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
2760*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2761*4882a593Smuzhiyun 
2762*4882a593Smuzhiyun 	error = mpt_config(ioc, &cfg);
2763*4882a593Smuzhiyun 
2764*4882a593Smuzhiyun 	if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2765*4882a593Smuzhiyun 		error = -ENODEV;
2766*4882a593Smuzhiyun 		goto out_free_consistent;
2767*4882a593Smuzhiyun 	}
2768*4882a593Smuzhiyun 
2769*4882a593Smuzhiyun 	if (error)
2770*4882a593Smuzhiyun 		goto out_free_consistent;
2771*4882a593Smuzhiyun 
2772*4882a593Smuzhiyun 
2773*4882a593Smuzhiyun 	mptsas_print_expander_pg1(ioc, buffer);
2774*4882a593Smuzhiyun 
2775*4882a593Smuzhiyun 	/* save config data */
2776*4882a593Smuzhiyun 	phy_info->phy_id = buffer->PhyIdentifier;
2777*4882a593Smuzhiyun 	phy_info->port_id = buffer->PhysicalPort;
2778*4882a593Smuzhiyun 	phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2779*4882a593Smuzhiyun 	phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2780*4882a593Smuzhiyun 	phy_info->hw_link_rate = buffer->HwLinkRate;
2781*4882a593Smuzhiyun 	phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2782*4882a593Smuzhiyun 	phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2783*4882a593Smuzhiyun 
2784*4882a593Smuzhiyun  out_free_consistent:
2785*4882a593Smuzhiyun 	pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2786*4882a593Smuzhiyun 			    buffer, dma_handle);
2787*4882a593Smuzhiyun  out:
2788*4882a593Smuzhiyun 	return error;
2789*4882a593Smuzhiyun }
2790*4882a593Smuzhiyun 
2791*4882a593Smuzhiyun struct rep_manu_request{
2792*4882a593Smuzhiyun 	u8 smp_frame_type;
2793*4882a593Smuzhiyun 	u8 function;
2794*4882a593Smuzhiyun 	u8 reserved;
2795*4882a593Smuzhiyun 	u8 request_length;
2796*4882a593Smuzhiyun };
2797*4882a593Smuzhiyun 
2798*4882a593Smuzhiyun struct rep_manu_reply{
2799*4882a593Smuzhiyun 	u8 smp_frame_type; /* 0x41 */
2800*4882a593Smuzhiyun 	u8 function; /* 0x01 */
2801*4882a593Smuzhiyun 	u8 function_result;
2802*4882a593Smuzhiyun 	u8 response_length;
2803*4882a593Smuzhiyun 	u16 expander_change_count;
2804*4882a593Smuzhiyun 	u8 reserved0[2];
2805*4882a593Smuzhiyun 	u8 sas_format:1;
2806*4882a593Smuzhiyun 	u8 reserved1:7;
2807*4882a593Smuzhiyun 	u8 reserved2[3];
2808*4882a593Smuzhiyun 	u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2809*4882a593Smuzhiyun 	u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2810*4882a593Smuzhiyun 	u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2811*4882a593Smuzhiyun 	u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2812*4882a593Smuzhiyun 	u16 component_id;
2813*4882a593Smuzhiyun 	u8 component_revision_id;
2814*4882a593Smuzhiyun 	u8 reserved3;
2815*4882a593Smuzhiyun 	u8 vendor_specific[8];
2816*4882a593Smuzhiyun };
2817*4882a593Smuzhiyun 
2818*4882a593Smuzhiyun /**
2819*4882a593Smuzhiyun   * mptsas_exp_repmanufacture_info -
2820*4882a593Smuzhiyun   * @ioc: per adapter object
2821*4882a593Smuzhiyun   * @sas_address: expander sas address
2822*4882a593Smuzhiyun   * @edev: the sas_expander_device object
2823*4882a593Smuzhiyun   *
2824*4882a593Smuzhiyun   * Fills in the sas_expander_device object when SMP port is created.
2825*4882a593Smuzhiyun   *
2826*4882a593Smuzhiyun   * Returns 0 for success, non-zero for failure.
2827*4882a593Smuzhiyun   */
2828*4882a593Smuzhiyun static int
mptsas_exp_repmanufacture_info(MPT_ADAPTER * ioc,u64 sas_address,struct sas_expander_device * edev)2829*4882a593Smuzhiyun mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2830*4882a593Smuzhiyun 	u64 sas_address, struct sas_expander_device *edev)
2831*4882a593Smuzhiyun {
2832*4882a593Smuzhiyun 	MPT_FRAME_HDR *mf;
2833*4882a593Smuzhiyun 	SmpPassthroughRequest_t *smpreq;
2834*4882a593Smuzhiyun 	SmpPassthroughReply_t *smprep;
2835*4882a593Smuzhiyun 	struct rep_manu_reply *manufacture_reply;
2836*4882a593Smuzhiyun 	struct rep_manu_request *manufacture_request;
2837*4882a593Smuzhiyun 	int ret;
2838*4882a593Smuzhiyun 	int flagsLength;
2839*4882a593Smuzhiyun 	unsigned long timeleft;
2840*4882a593Smuzhiyun 	char *psge;
2841*4882a593Smuzhiyun 	unsigned long flags;
2842*4882a593Smuzhiyun 	void *data_out = NULL;
2843*4882a593Smuzhiyun 	dma_addr_t data_out_dma = 0;
2844*4882a593Smuzhiyun 	u32 sz;
2845*4882a593Smuzhiyun 
2846*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2847*4882a593Smuzhiyun 	if (ioc->ioc_reset_in_progress) {
2848*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2849*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2850*4882a593Smuzhiyun 			__func__, ioc->name);
2851*4882a593Smuzhiyun 		return -EFAULT;
2852*4882a593Smuzhiyun 	}
2853*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2854*4882a593Smuzhiyun 
2855*4882a593Smuzhiyun 	ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2856*4882a593Smuzhiyun 	if (ret)
2857*4882a593Smuzhiyun 		goto out;
2858*4882a593Smuzhiyun 
2859*4882a593Smuzhiyun 	mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2860*4882a593Smuzhiyun 	if (!mf) {
2861*4882a593Smuzhiyun 		ret = -ENOMEM;
2862*4882a593Smuzhiyun 		goto out_unlock;
2863*4882a593Smuzhiyun 	}
2864*4882a593Smuzhiyun 
2865*4882a593Smuzhiyun 	smpreq = (SmpPassthroughRequest_t *)mf;
2866*4882a593Smuzhiyun 	memset(smpreq, 0, sizeof(*smpreq));
2867*4882a593Smuzhiyun 
2868*4882a593Smuzhiyun 	sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2869*4882a593Smuzhiyun 
2870*4882a593Smuzhiyun 	data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2871*4882a593Smuzhiyun 	if (!data_out) {
2872*4882a593Smuzhiyun 		printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2873*4882a593Smuzhiyun 			__FILE__, __LINE__, __func__);
2874*4882a593Smuzhiyun 		ret = -ENOMEM;
2875*4882a593Smuzhiyun 		goto put_mf;
2876*4882a593Smuzhiyun 	}
2877*4882a593Smuzhiyun 
2878*4882a593Smuzhiyun 	manufacture_request = data_out;
2879*4882a593Smuzhiyun 	manufacture_request->smp_frame_type = 0x40;
2880*4882a593Smuzhiyun 	manufacture_request->function = 1;
2881*4882a593Smuzhiyun 	manufacture_request->reserved = 0;
2882*4882a593Smuzhiyun 	manufacture_request->request_length = 0;
2883*4882a593Smuzhiyun 
2884*4882a593Smuzhiyun 	smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2885*4882a593Smuzhiyun 	smpreq->PhysicalPort = 0xFF;
2886*4882a593Smuzhiyun 	*((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2887*4882a593Smuzhiyun 	smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2888*4882a593Smuzhiyun 
2889*4882a593Smuzhiyun 	psge = (char *)
2890*4882a593Smuzhiyun 		(((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2891*4882a593Smuzhiyun 
2892*4882a593Smuzhiyun 	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2893*4882a593Smuzhiyun 		MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2894*4882a593Smuzhiyun 		MPI_SGE_FLAGS_HOST_TO_IOC |
2895*4882a593Smuzhiyun 		MPI_SGE_FLAGS_END_OF_BUFFER;
2896*4882a593Smuzhiyun 	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2897*4882a593Smuzhiyun 	flagsLength |= sizeof(struct rep_manu_request);
2898*4882a593Smuzhiyun 
2899*4882a593Smuzhiyun 	ioc->add_sge(psge, flagsLength, data_out_dma);
2900*4882a593Smuzhiyun 	psge += ioc->SGE_size;
2901*4882a593Smuzhiyun 
2902*4882a593Smuzhiyun 	flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2903*4882a593Smuzhiyun 		MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2904*4882a593Smuzhiyun 		MPI_SGE_FLAGS_IOC_TO_HOST |
2905*4882a593Smuzhiyun 		MPI_SGE_FLAGS_END_OF_BUFFER;
2906*4882a593Smuzhiyun 	flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2907*4882a593Smuzhiyun 	flagsLength |= sizeof(struct rep_manu_reply);
2908*4882a593Smuzhiyun 	ioc->add_sge(psge, flagsLength, data_out_dma +
2909*4882a593Smuzhiyun 	sizeof(struct rep_manu_request));
2910*4882a593Smuzhiyun 
2911*4882a593Smuzhiyun 	INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2912*4882a593Smuzhiyun 	mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2913*4882a593Smuzhiyun 
2914*4882a593Smuzhiyun 	timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2915*4882a593Smuzhiyun 	if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2916*4882a593Smuzhiyun 		ret = -ETIME;
2917*4882a593Smuzhiyun 		mpt_free_msg_frame(ioc, mf);
2918*4882a593Smuzhiyun 		mf = NULL;
2919*4882a593Smuzhiyun 		if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2920*4882a593Smuzhiyun 			goto out_free;
2921*4882a593Smuzhiyun 		if (!timeleft)
2922*4882a593Smuzhiyun 			mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
2923*4882a593Smuzhiyun 		goto out_free;
2924*4882a593Smuzhiyun 	}
2925*4882a593Smuzhiyun 
2926*4882a593Smuzhiyun 	mf = NULL;
2927*4882a593Smuzhiyun 
2928*4882a593Smuzhiyun 	if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2929*4882a593Smuzhiyun 		u8 *tmp;
2930*4882a593Smuzhiyun 
2931*4882a593Smuzhiyun 		smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2932*4882a593Smuzhiyun 		if (le16_to_cpu(smprep->ResponseDataLength) !=
2933*4882a593Smuzhiyun 		    sizeof(struct rep_manu_reply))
2934*4882a593Smuzhiyun 			goto out_free;
2935*4882a593Smuzhiyun 
2936*4882a593Smuzhiyun 		manufacture_reply = data_out + sizeof(struct rep_manu_request);
2937*4882a593Smuzhiyun 		strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2938*4882a593Smuzhiyun 			SAS_EXPANDER_VENDOR_ID_LEN);
2939*4882a593Smuzhiyun 		strncpy(edev->product_id, manufacture_reply->product_id,
2940*4882a593Smuzhiyun 			SAS_EXPANDER_PRODUCT_ID_LEN);
2941*4882a593Smuzhiyun 		strncpy(edev->product_rev, manufacture_reply->product_rev,
2942*4882a593Smuzhiyun 			SAS_EXPANDER_PRODUCT_REV_LEN);
2943*4882a593Smuzhiyun 		edev->level = manufacture_reply->sas_format;
2944*4882a593Smuzhiyun 		if (manufacture_reply->sas_format) {
2945*4882a593Smuzhiyun 			strncpy(edev->component_vendor_id,
2946*4882a593Smuzhiyun 				manufacture_reply->component_vendor_id,
2947*4882a593Smuzhiyun 				SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2948*4882a593Smuzhiyun 			tmp = (u8 *)&manufacture_reply->component_id;
2949*4882a593Smuzhiyun 			edev->component_id = tmp[0] << 8 | tmp[1];
2950*4882a593Smuzhiyun 			edev->component_revision_id =
2951*4882a593Smuzhiyun 				manufacture_reply->component_revision_id;
2952*4882a593Smuzhiyun 		}
2953*4882a593Smuzhiyun 	} else {
2954*4882a593Smuzhiyun 		printk(MYIOC_s_ERR_FMT
2955*4882a593Smuzhiyun 			"%s: smp passthru reply failed to be returned\n",
2956*4882a593Smuzhiyun 			ioc->name, __func__);
2957*4882a593Smuzhiyun 		ret = -ENXIO;
2958*4882a593Smuzhiyun 	}
2959*4882a593Smuzhiyun out_free:
2960*4882a593Smuzhiyun 	if (data_out_dma)
2961*4882a593Smuzhiyun 		pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2962*4882a593Smuzhiyun put_mf:
2963*4882a593Smuzhiyun 	if (mf)
2964*4882a593Smuzhiyun 		mpt_free_msg_frame(ioc, mf);
2965*4882a593Smuzhiyun out_unlock:
2966*4882a593Smuzhiyun 	CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2967*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_mgmt.mutex);
2968*4882a593Smuzhiyun out:
2969*4882a593Smuzhiyun 	return ret;
2970*4882a593Smuzhiyun }
2971*4882a593Smuzhiyun 
2972*4882a593Smuzhiyun static void
mptsas_parse_device_info(struct sas_identify * identify,struct mptsas_devinfo * device_info)2973*4882a593Smuzhiyun mptsas_parse_device_info(struct sas_identify *identify,
2974*4882a593Smuzhiyun 		struct mptsas_devinfo *device_info)
2975*4882a593Smuzhiyun {
2976*4882a593Smuzhiyun 	u16 protocols;
2977*4882a593Smuzhiyun 
2978*4882a593Smuzhiyun 	identify->sas_address = device_info->sas_address;
2979*4882a593Smuzhiyun 	identify->phy_identifier = device_info->phy_id;
2980*4882a593Smuzhiyun 
2981*4882a593Smuzhiyun 	/*
2982*4882a593Smuzhiyun 	 * Fill in Phy Initiator Port Protocol.
2983*4882a593Smuzhiyun 	 * Bits 6:3, more than one bit can be set, fall through cases.
2984*4882a593Smuzhiyun 	 */
2985*4882a593Smuzhiyun 	protocols = device_info->device_info & 0x78;
2986*4882a593Smuzhiyun 	identify->initiator_port_protocols = 0;
2987*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2988*4882a593Smuzhiyun 		identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2989*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2990*4882a593Smuzhiyun 		identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2991*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2992*4882a593Smuzhiyun 		identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2993*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2994*4882a593Smuzhiyun 		identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2995*4882a593Smuzhiyun 
2996*4882a593Smuzhiyun 	/*
2997*4882a593Smuzhiyun 	 * Fill in Phy Target Port Protocol.
2998*4882a593Smuzhiyun 	 * Bits 10:7, more than one bit can be set, fall through cases.
2999*4882a593Smuzhiyun 	 */
3000*4882a593Smuzhiyun 	protocols = device_info->device_info & 0x780;
3001*4882a593Smuzhiyun 	identify->target_port_protocols = 0;
3002*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
3003*4882a593Smuzhiyun 		identify->target_port_protocols |= SAS_PROTOCOL_SSP;
3004*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
3005*4882a593Smuzhiyun 		identify->target_port_protocols |= SAS_PROTOCOL_STP;
3006*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
3007*4882a593Smuzhiyun 		identify->target_port_protocols |= SAS_PROTOCOL_SMP;
3008*4882a593Smuzhiyun 	if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
3009*4882a593Smuzhiyun 		identify->target_port_protocols |= SAS_PROTOCOL_SATA;
3010*4882a593Smuzhiyun 
3011*4882a593Smuzhiyun 	/*
3012*4882a593Smuzhiyun 	 * Fill in Attached device type.
3013*4882a593Smuzhiyun 	 */
3014*4882a593Smuzhiyun 	switch (device_info->device_info &
3015*4882a593Smuzhiyun 			MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
3016*4882a593Smuzhiyun 	case MPI_SAS_DEVICE_INFO_NO_DEVICE:
3017*4882a593Smuzhiyun 		identify->device_type = SAS_PHY_UNUSED;
3018*4882a593Smuzhiyun 		break;
3019*4882a593Smuzhiyun 	case MPI_SAS_DEVICE_INFO_END_DEVICE:
3020*4882a593Smuzhiyun 		identify->device_type = SAS_END_DEVICE;
3021*4882a593Smuzhiyun 		break;
3022*4882a593Smuzhiyun 	case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
3023*4882a593Smuzhiyun 		identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
3024*4882a593Smuzhiyun 		break;
3025*4882a593Smuzhiyun 	case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
3026*4882a593Smuzhiyun 		identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
3027*4882a593Smuzhiyun 		break;
3028*4882a593Smuzhiyun 	}
3029*4882a593Smuzhiyun }
3030*4882a593Smuzhiyun 
mptsas_probe_one_phy(struct device * dev,struct mptsas_phyinfo * phy_info,int index,int local)3031*4882a593Smuzhiyun static int mptsas_probe_one_phy(struct device *dev,
3032*4882a593Smuzhiyun 		struct mptsas_phyinfo *phy_info, int index, int local)
3033*4882a593Smuzhiyun {
3034*4882a593Smuzhiyun 	MPT_ADAPTER *ioc;
3035*4882a593Smuzhiyun 	struct sas_phy *phy;
3036*4882a593Smuzhiyun 	struct sas_port *port;
3037*4882a593Smuzhiyun 	int error = 0;
3038*4882a593Smuzhiyun 	VirtTarget *vtarget;
3039*4882a593Smuzhiyun 
3040*4882a593Smuzhiyun 	if (!dev) {
3041*4882a593Smuzhiyun 		error = -ENODEV;
3042*4882a593Smuzhiyun 		goto out;
3043*4882a593Smuzhiyun 	}
3044*4882a593Smuzhiyun 
3045*4882a593Smuzhiyun 	if (!phy_info->phy) {
3046*4882a593Smuzhiyun 		phy = sas_phy_alloc(dev, index);
3047*4882a593Smuzhiyun 		if (!phy) {
3048*4882a593Smuzhiyun 			error = -ENOMEM;
3049*4882a593Smuzhiyun 			goto out;
3050*4882a593Smuzhiyun 		}
3051*4882a593Smuzhiyun 	} else
3052*4882a593Smuzhiyun 		phy = phy_info->phy;
3053*4882a593Smuzhiyun 
3054*4882a593Smuzhiyun 	mptsas_parse_device_info(&phy->identify, &phy_info->identify);
3055*4882a593Smuzhiyun 
3056*4882a593Smuzhiyun 	/*
3057*4882a593Smuzhiyun 	 * Set Negotiated link rate.
3058*4882a593Smuzhiyun 	 */
3059*4882a593Smuzhiyun 	switch (phy_info->negotiated_link_rate) {
3060*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
3061*4882a593Smuzhiyun 		phy->negotiated_linkrate = SAS_PHY_DISABLED;
3062*4882a593Smuzhiyun 		break;
3063*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
3064*4882a593Smuzhiyun 		phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
3065*4882a593Smuzhiyun 		break;
3066*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_1_5:
3067*4882a593Smuzhiyun 		phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
3068*4882a593Smuzhiyun 		break;
3069*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_3_0:
3070*4882a593Smuzhiyun 		phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
3071*4882a593Smuzhiyun 		break;
3072*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_6_0:
3073*4882a593Smuzhiyun 		phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
3074*4882a593Smuzhiyun 		break;
3075*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
3076*4882a593Smuzhiyun 	case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
3077*4882a593Smuzhiyun 	default:
3078*4882a593Smuzhiyun 		phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
3079*4882a593Smuzhiyun 		break;
3080*4882a593Smuzhiyun 	}
3081*4882a593Smuzhiyun 
3082*4882a593Smuzhiyun 	/*
3083*4882a593Smuzhiyun 	 * Set Max hardware link rate.
3084*4882a593Smuzhiyun 	 */
3085*4882a593Smuzhiyun 	switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3086*4882a593Smuzhiyun 	case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
3087*4882a593Smuzhiyun 		phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
3088*4882a593Smuzhiyun 		break;
3089*4882a593Smuzhiyun 	case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
3090*4882a593Smuzhiyun 		phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
3091*4882a593Smuzhiyun 		break;
3092*4882a593Smuzhiyun 	default:
3093*4882a593Smuzhiyun 		break;
3094*4882a593Smuzhiyun 	}
3095*4882a593Smuzhiyun 
3096*4882a593Smuzhiyun 	/*
3097*4882a593Smuzhiyun 	 * Set Max programmed link rate.
3098*4882a593Smuzhiyun 	 */
3099*4882a593Smuzhiyun 	switch (phy_info->programmed_link_rate &
3100*4882a593Smuzhiyun 			MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3101*4882a593Smuzhiyun 	case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
3102*4882a593Smuzhiyun 		phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
3103*4882a593Smuzhiyun 		break;
3104*4882a593Smuzhiyun 	case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
3105*4882a593Smuzhiyun 		phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
3106*4882a593Smuzhiyun 		break;
3107*4882a593Smuzhiyun 	default:
3108*4882a593Smuzhiyun 		break;
3109*4882a593Smuzhiyun 	}
3110*4882a593Smuzhiyun 
3111*4882a593Smuzhiyun 	/*
3112*4882a593Smuzhiyun 	 * Set Min hardware link rate.
3113*4882a593Smuzhiyun 	 */
3114*4882a593Smuzhiyun 	switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3115*4882a593Smuzhiyun 	case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
3116*4882a593Smuzhiyun 		phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
3117*4882a593Smuzhiyun 		break;
3118*4882a593Smuzhiyun 	case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
3119*4882a593Smuzhiyun 		phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
3120*4882a593Smuzhiyun 		break;
3121*4882a593Smuzhiyun 	default:
3122*4882a593Smuzhiyun 		break;
3123*4882a593Smuzhiyun 	}
3124*4882a593Smuzhiyun 
3125*4882a593Smuzhiyun 	/*
3126*4882a593Smuzhiyun 	 * Set Min programmed link rate.
3127*4882a593Smuzhiyun 	 */
3128*4882a593Smuzhiyun 	switch (phy_info->programmed_link_rate &
3129*4882a593Smuzhiyun 			MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3130*4882a593Smuzhiyun 	case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
3131*4882a593Smuzhiyun 		phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
3132*4882a593Smuzhiyun 		break;
3133*4882a593Smuzhiyun 	case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
3134*4882a593Smuzhiyun 		phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
3135*4882a593Smuzhiyun 		break;
3136*4882a593Smuzhiyun 	default:
3137*4882a593Smuzhiyun 		break;
3138*4882a593Smuzhiyun 	}
3139*4882a593Smuzhiyun 
3140*4882a593Smuzhiyun 	if (!phy_info->phy) {
3141*4882a593Smuzhiyun 
3142*4882a593Smuzhiyun 		error = sas_phy_add(phy);
3143*4882a593Smuzhiyun 		if (error) {
3144*4882a593Smuzhiyun 			sas_phy_free(phy);
3145*4882a593Smuzhiyun 			goto out;
3146*4882a593Smuzhiyun 		}
3147*4882a593Smuzhiyun 		phy_info->phy = phy;
3148*4882a593Smuzhiyun 	}
3149*4882a593Smuzhiyun 
3150*4882a593Smuzhiyun 	if (!phy_info->attached.handle ||
3151*4882a593Smuzhiyun 			!phy_info->port_details)
3152*4882a593Smuzhiyun 		goto out;
3153*4882a593Smuzhiyun 
3154*4882a593Smuzhiyun 	port = mptsas_get_port(phy_info);
3155*4882a593Smuzhiyun 	ioc = phy_to_ioc(phy_info->phy);
3156*4882a593Smuzhiyun 
3157*4882a593Smuzhiyun 	if (phy_info->sas_port_add_phy) {
3158*4882a593Smuzhiyun 
3159*4882a593Smuzhiyun 		if (!port) {
3160*4882a593Smuzhiyun 			port = sas_port_alloc_num(dev);
3161*4882a593Smuzhiyun 			if (!port) {
3162*4882a593Smuzhiyun 				error = -ENOMEM;
3163*4882a593Smuzhiyun 				goto out;
3164*4882a593Smuzhiyun 			}
3165*4882a593Smuzhiyun 			error = sas_port_add(port);
3166*4882a593Smuzhiyun 			if (error) {
3167*4882a593Smuzhiyun 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3168*4882a593Smuzhiyun 					"%s: exit at line=%d\n", ioc->name,
3169*4882a593Smuzhiyun 					__func__, __LINE__));
3170*4882a593Smuzhiyun 				goto out;
3171*4882a593Smuzhiyun 			}
3172*4882a593Smuzhiyun 			mptsas_set_port(ioc, phy_info, port);
3173*4882a593Smuzhiyun 			devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3174*4882a593Smuzhiyun 			    MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3175*4882a593Smuzhiyun 			    ioc->name, port->port_identifier,
3176*4882a593Smuzhiyun 			    (unsigned long long)phy_info->
3177*4882a593Smuzhiyun 			    attached.sas_address));
3178*4882a593Smuzhiyun 		}
3179*4882a593Smuzhiyun 		dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3180*4882a593Smuzhiyun 			"sas_port_add_phy: phy_id=%d\n",
3181*4882a593Smuzhiyun 			ioc->name, phy_info->phy_id));
3182*4882a593Smuzhiyun 		sas_port_add_phy(port, phy_info->phy);
3183*4882a593Smuzhiyun 		phy_info->sas_port_add_phy = 0;
3184*4882a593Smuzhiyun 		devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3185*4882a593Smuzhiyun 		    MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3186*4882a593Smuzhiyun 		     phy_info->phy_id, phy_info->phy));
3187*4882a593Smuzhiyun 	}
3188*4882a593Smuzhiyun 	if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
3189*4882a593Smuzhiyun 
3190*4882a593Smuzhiyun 		struct sas_rphy *rphy;
3191*4882a593Smuzhiyun 		struct device *parent;
3192*4882a593Smuzhiyun 		struct sas_identify identify;
3193*4882a593Smuzhiyun 
3194*4882a593Smuzhiyun 		parent = dev->parent->parent;
3195*4882a593Smuzhiyun 		/*
3196*4882a593Smuzhiyun 		 * Let the hotplug_work thread handle processing
3197*4882a593Smuzhiyun 		 * the adding/removing of devices that occur
3198*4882a593Smuzhiyun 		 * after start of day.
3199*4882a593Smuzhiyun 		 */
3200*4882a593Smuzhiyun 		if (mptsas_is_end_device(&phy_info->attached) &&
3201*4882a593Smuzhiyun 		    phy_info->attached.handle_parent) {
3202*4882a593Smuzhiyun 			goto out;
3203*4882a593Smuzhiyun 		}
3204*4882a593Smuzhiyun 
3205*4882a593Smuzhiyun 		mptsas_parse_device_info(&identify, &phy_info->attached);
3206*4882a593Smuzhiyun 		if (scsi_is_host_device(parent)) {
3207*4882a593Smuzhiyun 			struct mptsas_portinfo *port_info;
3208*4882a593Smuzhiyun 			int i;
3209*4882a593Smuzhiyun 
3210*4882a593Smuzhiyun 			port_info = ioc->hba_port_info;
3211*4882a593Smuzhiyun 
3212*4882a593Smuzhiyun 			for (i = 0; i < port_info->num_phys; i++)
3213*4882a593Smuzhiyun 				if (port_info->phy_info[i].identify.sas_address ==
3214*4882a593Smuzhiyun 				    identify.sas_address) {
3215*4882a593Smuzhiyun 					sas_port_mark_backlink(port);
3216*4882a593Smuzhiyun 					goto out;
3217*4882a593Smuzhiyun 				}
3218*4882a593Smuzhiyun 
3219*4882a593Smuzhiyun 		} else if (scsi_is_sas_rphy(parent)) {
3220*4882a593Smuzhiyun 			struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3221*4882a593Smuzhiyun 			if (identify.sas_address ==
3222*4882a593Smuzhiyun 			    parent_rphy->identify.sas_address) {
3223*4882a593Smuzhiyun 				sas_port_mark_backlink(port);
3224*4882a593Smuzhiyun 				goto out;
3225*4882a593Smuzhiyun 			}
3226*4882a593Smuzhiyun 		}
3227*4882a593Smuzhiyun 
3228*4882a593Smuzhiyun 		switch (identify.device_type) {
3229*4882a593Smuzhiyun 		case SAS_END_DEVICE:
3230*4882a593Smuzhiyun 			rphy = sas_end_device_alloc(port);
3231*4882a593Smuzhiyun 			break;
3232*4882a593Smuzhiyun 		case SAS_EDGE_EXPANDER_DEVICE:
3233*4882a593Smuzhiyun 		case SAS_FANOUT_EXPANDER_DEVICE:
3234*4882a593Smuzhiyun 			rphy = sas_expander_alloc(port, identify.device_type);
3235*4882a593Smuzhiyun 			break;
3236*4882a593Smuzhiyun 		default:
3237*4882a593Smuzhiyun 			rphy = NULL;
3238*4882a593Smuzhiyun 			break;
3239*4882a593Smuzhiyun 		}
3240*4882a593Smuzhiyun 		if (!rphy) {
3241*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3242*4882a593Smuzhiyun 				"%s: exit at line=%d\n", ioc->name,
3243*4882a593Smuzhiyun 				__func__, __LINE__));
3244*4882a593Smuzhiyun 			goto out;
3245*4882a593Smuzhiyun 		}
3246*4882a593Smuzhiyun 
3247*4882a593Smuzhiyun 		rphy->identify = identify;
3248*4882a593Smuzhiyun 		error = sas_rphy_add(rphy);
3249*4882a593Smuzhiyun 		if (error) {
3250*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3251*4882a593Smuzhiyun 				"%s: exit at line=%d\n", ioc->name,
3252*4882a593Smuzhiyun 				__func__, __LINE__));
3253*4882a593Smuzhiyun 			sas_rphy_free(rphy);
3254*4882a593Smuzhiyun 			goto out;
3255*4882a593Smuzhiyun 		}
3256*4882a593Smuzhiyun 		mptsas_set_rphy(ioc, phy_info, rphy);
3257*4882a593Smuzhiyun 		if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3258*4882a593Smuzhiyun 			identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3259*4882a593Smuzhiyun 				mptsas_exp_repmanufacture_info(ioc,
3260*4882a593Smuzhiyun 					identify.sas_address,
3261*4882a593Smuzhiyun 					rphy_to_expander_device(rphy));
3262*4882a593Smuzhiyun 	}
3263*4882a593Smuzhiyun 
3264*4882a593Smuzhiyun 	/* If the device exists,verify it wasn't previously flagged
3265*4882a593Smuzhiyun 	as a missing device.  If so, clear it */
3266*4882a593Smuzhiyun 	vtarget = mptsas_find_vtarget(ioc,
3267*4882a593Smuzhiyun 	    phy_info->attached.channel,
3268*4882a593Smuzhiyun 	    phy_info->attached.id);
3269*4882a593Smuzhiyun 	if (vtarget && vtarget->inDMD) {
3270*4882a593Smuzhiyun 		printk(KERN_INFO "Device returned, unsetting inDMD\n");
3271*4882a593Smuzhiyun 		vtarget->inDMD = 0;
3272*4882a593Smuzhiyun 	}
3273*4882a593Smuzhiyun 
3274*4882a593Smuzhiyun  out:
3275*4882a593Smuzhiyun 	return error;
3276*4882a593Smuzhiyun }
3277*4882a593Smuzhiyun 
3278*4882a593Smuzhiyun static int
mptsas_probe_hba_phys(MPT_ADAPTER * ioc)3279*4882a593Smuzhiyun mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
3280*4882a593Smuzhiyun {
3281*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info, *hba;
3282*4882a593Smuzhiyun 	int error = -ENOMEM, i;
3283*4882a593Smuzhiyun 
3284*4882a593Smuzhiyun 	hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3285*4882a593Smuzhiyun 	if (! hba)
3286*4882a593Smuzhiyun 		goto out;
3287*4882a593Smuzhiyun 
3288*4882a593Smuzhiyun 	error = mptsas_sas_io_unit_pg0(ioc, hba);
3289*4882a593Smuzhiyun 	if (error)
3290*4882a593Smuzhiyun 		goto out_free_port_info;
3291*4882a593Smuzhiyun 
3292*4882a593Smuzhiyun 	mptsas_sas_io_unit_pg1(ioc);
3293*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
3294*4882a593Smuzhiyun 	port_info = ioc->hba_port_info;
3295*4882a593Smuzhiyun 	if (!port_info) {
3296*4882a593Smuzhiyun 		ioc->hba_port_info = port_info = hba;
3297*4882a593Smuzhiyun 		ioc->hba_port_num_phy = port_info->num_phys;
3298*4882a593Smuzhiyun 		list_add_tail(&port_info->list, &ioc->sas_topology);
3299*4882a593Smuzhiyun 	} else {
3300*4882a593Smuzhiyun 		for (i = 0; i < hba->num_phys; i++) {
3301*4882a593Smuzhiyun 			port_info->phy_info[i].negotiated_link_rate =
3302*4882a593Smuzhiyun 				hba->phy_info[i].negotiated_link_rate;
3303*4882a593Smuzhiyun 			port_info->phy_info[i].handle =
3304*4882a593Smuzhiyun 				hba->phy_info[i].handle;
3305*4882a593Smuzhiyun 			port_info->phy_info[i].port_id =
3306*4882a593Smuzhiyun 				hba->phy_info[i].port_id;
3307*4882a593Smuzhiyun 		}
3308*4882a593Smuzhiyun 		kfree(hba->phy_info);
3309*4882a593Smuzhiyun 		kfree(hba);
3310*4882a593Smuzhiyun 		hba = NULL;
3311*4882a593Smuzhiyun 	}
3312*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
3313*4882a593Smuzhiyun #if defined(CPQ_CIM)
3314*4882a593Smuzhiyun 	ioc->num_ports = port_info->num_phys;
3315*4882a593Smuzhiyun #endif
3316*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
3317*4882a593Smuzhiyun 		mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3318*4882a593Smuzhiyun 			(MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3319*4882a593Smuzhiyun 			 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
3320*4882a593Smuzhiyun 		port_info->phy_info[i].identify.handle =
3321*4882a593Smuzhiyun 		    port_info->phy_info[i].handle;
3322*4882a593Smuzhiyun 		mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
3323*4882a593Smuzhiyun 			(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3324*4882a593Smuzhiyun 			 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3325*4882a593Smuzhiyun 			 port_info->phy_info[i].identify.handle);
3326*4882a593Smuzhiyun 		if (!ioc->hba_port_sas_addr)
3327*4882a593Smuzhiyun 			ioc->hba_port_sas_addr =
3328*4882a593Smuzhiyun 			    port_info->phy_info[i].identify.sas_address;
3329*4882a593Smuzhiyun 		port_info->phy_info[i].identify.phy_id =
3330*4882a593Smuzhiyun 		    port_info->phy_info[i].phy_id = i;
3331*4882a593Smuzhiyun 		if (port_info->phy_info[i].attached.handle)
3332*4882a593Smuzhiyun 			mptsas_sas_device_pg0(ioc,
3333*4882a593Smuzhiyun 				&port_info->phy_info[i].attached,
3334*4882a593Smuzhiyun 				(MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3335*4882a593Smuzhiyun 				 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3336*4882a593Smuzhiyun 				port_info->phy_info[i].attached.handle);
3337*4882a593Smuzhiyun 	}
3338*4882a593Smuzhiyun 
3339*4882a593Smuzhiyun 	mptsas_setup_wide_ports(ioc, port_info);
3340*4882a593Smuzhiyun 
3341*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3342*4882a593Smuzhiyun 		mptsas_probe_one_phy(&ioc->sh->shost_gendev,
3343*4882a593Smuzhiyun 		    &port_info->phy_info[i], ioc->sas_index, 1);
3344*4882a593Smuzhiyun 
3345*4882a593Smuzhiyun 	return 0;
3346*4882a593Smuzhiyun 
3347*4882a593Smuzhiyun  out_free_port_info:
3348*4882a593Smuzhiyun 	kfree(hba);
3349*4882a593Smuzhiyun  out:
3350*4882a593Smuzhiyun 	return error;
3351*4882a593Smuzhiyun }
3352*4882a593Smuzhiyun 
3353*4882a593Smuzhiyun static void
mptsas_expander_refresh(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info)3354*4882a593Smuzhiyun mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
3355*4882a593Smuzhiyun {
3356*4882a593Smuzhiyun 	struct mptsas_portinfo *parent;
3357*4882a593Smuzhiyun 	struct device *parent_dev;
3358*4882a593Smuzhiyun 	struct sas_rphy	*rphy;
3359*4882a593Smuzhiyun 	int		i;
3360*4882a593Smuzhiyun 	u64		sas_address; /* expander sas address */
3361*4882a593Smuzhiyun 	u32		handle;
3362*4882a593Smuzhiyun 
3363*4882a593Smuzhiyun 	handle = port_info->phy_info[0].handle;
3364*4882a593Smuzhiyun 	sas_address = port_info->phy_info[0].identify.sas_address;
3365*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
3366*4882a593Smuzhiyun 		mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
3367*4882a593Smuzhiyun 		    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3368*4882a593Smuzhiyun 		    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
3369*4882a593Smuzhiyun 
3370*4882a593Smuzhiyun 		mptsas_sas_device_pg0(ioc,
3371*4882a593Smuzhiyun 		    &port_info->phy_info[i].identify,
3372*4882a593Smuzhiyun 		    (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3373*4882a593Smuzhiyun 		    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3374*4882a593Smuzhiyun 		    port_info->phy_info[i].identify.handle);
3375*4882a593Smuzhiyun 		port_info->phy_info[i].identify.phy_id =
3376*4882a593Smuzhiyun 		    port_info->phy_info[i].phy_id;
3377*4882a593Smuzhiyun 
3378*4882a593Smuzhiyun 		if (port_info->phy_info[i].attached.handle) {
3379*4882a593Smuzhiyun 			mptsas_sas_device_pg0(ioc,
3380*4882a593Smuzhiyun 			    &port_info->phy_info[i].attached,
3381*4882a593Smuzhiyun 			    (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3382*4882a593Smuzhiyun 			     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3383*4882a593Smuzhiyun 			    port_info->phy_info[i].attached.handle);
3384*4882a593Smuzhiyun 			port_info->phy_info[i].attached.phy_id =
3385*4882a593Smuzhiyun 			    port_info->phy_info[i].phy_id;
3386*4882a593Smuzhiyun 		}
3387*4882a593Smuzhiyun 	}
3388*4882a593Smuzhiyun 
3389*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
3390*4882a593Smuzhiyun 	parent = mptsas_find_portinfo_by_handle(ioc,
3391*4882a593Smuzhiyun 	    port_info->phy_info[0].identify.handle_parent);
3392*4882a593Smuzhiyun 	if (!parent) {
3393*4882a593Smuzhiyun 		mutex_unlock(&ioc->sas_topology_mutex);
3394*4882a593Smuzhiyun 		return;
3395*4882a593Smuzhiyun 	}
3396*4882a593Smuzhiyun 	for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3397*4882a593Smuzhiyun 	    i++) {
3398*4882a593Smuzhiyun 		if (parent->phy_info[i].attached.sas_address == sas_address) {
3399*4882a593Smuzhiyun 			rphy = mptsas_get_rphy(&parent->phy_info[i]);
3400*4882a593Smuzhiyun 			parent_dev = &rphy->dev;
3401*4882a593Smuzhiyun 		}
3402*4882a593Smuzhiyun 	}
3403*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
3404*4882a593Smuzhiyun 
3405*4882a593Smuzhiyun 	mptsas_setup_wide_ports(ioc, port_info);
3406*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3407*4882a593Smuzhiyun 		mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3408*4882a593Smuzhiyun 		    ioc->sas_index, 0);
3409*4882a593Smuzhiyun }
3410*4882a593Smuzhiyun 
3411*4882a593Smuzhiyun static void
mptsas_expander_event_add(MPT_ADAPTER * ioc,MpiEventDataSasExpanderStatusChange_t * expander_data)3412*4882a593Smuzhiyun mptsas_expander_event_add(MPT_ADAPTER *ioc,
3413*4882a593Smuzhiyun     MpiEventDataSasExpanderStatusChange_t *expander_data)
3414*4882a593Smuzhiyun {
3415*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
3416*4882a593Smuzhiyun 	int i;
3417*4882a593Smuzhiyun 	__le64 sas_address;
3418*4882a593Smuzhiyun 
3419*4882a593Smuzhiyun 	port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3420*4882a593Smuzhiyun 	if (!port_info)
3421*4882a593Smuzhiyun 		BUG();
3422*4882a593Smuzhiyun 	port_info->num_phys = (expander_data->NumPhys) ?
3423*4882a593Smuzhiyun 	    expander_data->NumPhys : 1;
3424*4882a593Smuzhiyun 	port_info->phy_info = kcalloc(port_info->num_phys,
3425*4882a593Smuzhiyun 	    sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3426*4882a593Smuzhiyun 	if (!port_info->phy_info)
3427*4882a593Smuzhiyun 		BUG();
3428*4882a593Smuzhiyun 	memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3429*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++) {
3430*4882a593Smuzhiyun 		port_info->phy_info[i].portinfo = port_info;
3431*4882a593Smuzhiyun 		port_info->phy_info[i].handle =
3432*4882a593Smuzhiyun 		    le16_to_cpu(expander_data->DevHandle);
3433*4882a593Smuzhiyun 		port_info->phy_info[i].identify.sas_address =
3434*4882a593Smuzhiyun 		    le64_to_cpu(sas_address);
3435*4882a593Smuzhiyun 		port_info->phy_info[i].identify.handle_parent =
3436*4882a593Smuzhiyun 		    le16_to_cpu(expander_data->ParentDevHandle);
3437*4882a593Smuzhiyun 	}
3438*4882a593Smuzhiyun 
3439*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
3440*4882a593Smuzhiyun 	list_add_tail(&port_info->list, &ioc->sas_topology);
3441*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
3442*4882a593Smuzhiyun 
3443*4882a593Smuzhiyun 	printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3444*4882a593Smuzhiyun 	    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3445*4882a593Smuzhiyun 	    (unsigned long long)sas_address);
3446*4882a593Smuzhiyun 
3447*4882a593Smuzhiyun 	mptsas_expander_refresh(ioc, port_info);
3448*4882a593Smuzhiyun }
3449*4882a593Smuzhiyun 
3450*4882a593Smuzhiyun /**
3451*4882a593Smuzhiyun  * mptsas_delete_expander_siblings - remove siblings attached to expander
3452*4882a593Smuzhiyun  * @ioc: Pointer to MPT_ADAPTER structure
3453*4882a593Smuzhiyun  * @parent: the parent port_info object
3454*4882a593Smuzhiyun  * @expander: the expander port_info object
3455*4882a593Smuzhiyun  **/
3456*4882a593Smuzhiyun static void
mptsas_delete_expander_siblings(MPT_ADAPTER * ioc,struct mptsas_portinfo * parent,struct mptsas_portinfo * expander)3457*4882a593Smuzhiyun mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3458*4882a593Smuzhiyun     *parent, struct mptsas_portinfo *expander)
3459*4882a593Smuzhiyun {
3460*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
3461*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
3462*4882a593Smuzhiyun 	struct sas_rphy *rphy;
3463*4882a593Smuzhiyun 	int i;
3464*4882a593Smuzhiyun 
3465*4882a593Smuzhiyun 	phy_info = expander->phy_info;
3466*4882a593Smuzhiyun 	for (i = 0; i < expander->num_phys; i++, phy_info++) {
3467*4882a593Smuzhiyun 		rphy = mptsas_get_rphy(phy_info);
3468*4882a593Smuzhiyun 		if (!rphy)
3469*4882a593Smuzhiyun 			continue;
3470*4882a593Smuzhiyun 		if (rphy->identify.device_type == SAS_END_DEVICE)
3471*4882a593Smuzhiyun 			mptsas_del_end_device(ioc, phy_info);
3472*4882a593Smuzhiyun 	}
3473*4882a593Smuzhiyun 
3474*4882a593Smuzhiyun 	phy_info = expander->phy_info;
3475*4882a593Smuzhiyun 	for (i = 0; i < expander->num_phys; i++, phy_info++) {
3476*4882a593Smuzhiyun 		rphy = mptsas_get_rphy(phy_info);
3477*4882a593Smuzhiyun 		if (!rphy)
3478*4882a593Smuzhiyun 			continue;
3479*4882a593Smuzhiyun 		if (rphy->identify.device_type ==
3480*4882a593Smuzhiyun 		    MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3481*4882a593Smuzhiyun 		    rphy->identify.device_type ==
3482*4882a593Smuzhiyun 		    MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3483*4882a593Smuzhiyun 			port_info = mptsas_find_portinfo_by_sas_address(ioc,
3484*4882a593Smuzhiyun 			    rphy->identify.sas_address);
3485*4882a593Smuzhiyun 			if (!port_info)
3486*4882a593Smuzhiyun 				continue;
3487*4882a593Smuzhiyun 			if (port_info == parent) /* backlink rphy */
3488*4882a593Smuzhiyun 				continue;
3489*4882a593Smuzhiyun 			/*
3490*4882a593Smuzhiyun 			Delete this expander even if the expdevpage is exists
3491*4882a593Smuzhiyun 			because the parent expander is already deleted
3492*4882a593Smuzhiyun 			*/
3493*4882a593Smuzhiyun 			mptsas_expander_delete(ioc, port_info, 1);
3494*4882a593Smuzhiyun 		}
3495*4882a593Smuzhiyun 	}
3496*4882a593Smuzhiyun }
3497*4882a593Smuzhiyun 
3498*4882a593Smuzhiyun 
3499*4882a593Smuzhiyun /**
3500*4882a593Smuzhiyun  *	mptsas_expander_delete - remove this expander
3501*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
3502*4882a593Smuzhiyun  *	@port_info: expander port_info struct
3503*4882a593Smuzhiyun  *	@force: Flag to forcefully delete the expander
3504*4882a593Smuzhiyun  *
3505*4882a593Smuzhiyun  **/
3506*4882a593Smuzhiyun 
mptsas_expander_delete(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info,u8 force)3507*4882a593Smuzhiyun static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3508*4882a593Smuzhiyun 		struct mptsas_portinfo *port_info, u8 force)
3509*4882a593Smuzhiyun {
3510*4882a593Smuzhiyun 
3511*4882a593Smuzhiyun 	struct mptsas_portinfo *parent;
3512*4882a593Smuzhiyun 	int		i;
3513*4882a593Smuzhiyun 	u64		expander_sas_address;
3514*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
3515*4882a593Smuzhiyun 	struct mptsas_portinfo buffer;
3516*4882a593Smuzhiyun 	struct mptsas_portinfo_details *port_details;
3517*4882a593Smuzhiyun 	struct sas_port *port;
3518*4882a593Smuzhiyun 
3519*4882a593Smuzhiyun 	if (!port_info)
3520*4882a593Smuzhiyun 		return;
3521*4882a593Smuzhiyun 
3522*4882a593Smuzhiyun 	/* see if expander is still there before deleting */
3523*4882a593Smuzhiyun 	mptsas_sas_expander_pg0(ioc, &buffer,
3524*4882a593Smuzhiyun 	    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3525*4882a593Smuzhiyun 	    MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3526*4882a593Smuzhiyun 	    port_info->phy_info[0].identify.handle);
3527*4882a593Smuzhiyun 
3528*4882a593Smuzhiyun 	if (buffer.num_phys) {
3529*4882a593Smuzhiyun 		kfree(buffer.phy_info);
3530*4882a593Smuzhiyun 		if (!force)
3531*4882a593Smuzhiyun 			return;
3532*4882a593Smuzhiyun 	}
3533*4882a593Smuzhiyun 
3534*4882a593Smuzhiyun 
3535*4882a593Smuzhiyun 	/*
3536*4882a593Smuzhiyun 	 * Obtain the port_info instance to the parent port
3537*4882a593Smuzhiyun 	 */
3538*4882a593Smuzhiyun 	port_details = NULL;
3539*4882a593Smuzhiyun 	expander_sas_address =
3540*4882a593Smuzhiyun 	    port_info->phy_info[0].identify.sas_address;
3541*4882a593Smuzhiyun 	parent = mptsas_find_portinfo_by_handle(ioc,
3542*4882a593Smuzhiyun 	    port_info->phy_info[0].identify.handle_parent);
3543*4882a593Smuzhiyun 	mptsas_delete_expander_siblings(ioc, parent, port_info);
3544*4882a593Smuzhiyun 	if (!parent)
3545*4882a593Smuzhiyun 		goto out;
3546*4882a593Smuzhiyun 
3547*4882a593Smuzhiyun 	/*
3548*4882a593Smuzhiyun 	 * Delete rphys in the parent that point
3549*4882a593Smuzhiyun 	 * to this expander.
3550*4882a593Smuzhiyun 	 */
3551*4882a593Smuzhiyun 	phy_info = parent->phy_info;
3552*4882a593Smuzhiyun 	port = NULL;
3553*4882a593Smuzhiyun 	for (i = 0; i < parent->num_phys; i++, phy_info++) {
3554*4882a593Smuzhiyun 		if (!phy_info->phy)
3555*4882a593Smuzhiyun 			continue;
3556*4882a593Smuzhiyun 		if (phy_info->attached.sas_address !=
3557*4882a593Smuzhiyun 		    expander_sas_address)
3558*4882a593Smuzhiyun 			continue;
3559*4882a593Smuzhiyun 		if (!port) {
3560*4882a593Smuzhiyun 			port = mptsas_get_port(phy_info);
3561*4882a593Smuzhiyun 			port_details = phy_info->port_details;
3562*4882a593Smuzhiyun 		}
3563*4882a593Smuzhiyun 		dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3564*4882a593Smuzhiyun 		    MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3565*4882a593Smuzhiyun 		    phy_info->phy_id, phy_info->phy);
3566*4882a593Smuzhiyun 		sas_port_delete_phy(port, phy_info->phy);
3567*4882a593Smuzhiyun 	}
3568*4882a593Smuzhiyun 	if (port) {
3569*4882a593Smuzhiyun 		dev_printk(KERN_DEBUG, &port->dev,
3570*4882a593Smuzhiyun 		    MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3571*4882a593Smuzhiyun 		    ioc->name, port->port_identifier,
3572*4882a593Smuzhiyun 		    (unsigned long long)expander_sas_address);
3573*4882a593Smuzhiyun 		sas_port_delete(port);
3574*4882a593Smuzhiyun 		mptsas_port_delete(ioc, port_details);
3575*4882a593Smuzhiyun 	}
3576*4882a593Smuzhiyun  out:
3577*4882a593Smuzhiyun 
3578*4882a593Smuzhiyun 	printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3579*4882a593Smuzhiyun 	    "sas_addr (0x%llx)\n",  ioc->name, port_info->num_phys,
3580*4882a593Smuzhiyun 	    (unsigned long long)expander_sas_address);
3581*4882a593Smuzhiyun 
3582*4882a593Smuzhiyun 	/*
3583*4882a593Smuzhiyun 	 * free link
3584*4882a593Smuzhiyun 	 */
3585*4882a593Smuzhiyun 	list_del(&port_info->list);
3586*4882a593Smuzhiyun 	kfree(port_info->phy_info);
3587*4882a593Smuzhiyun 	kfree(port_info);
3588*4882a593Smuzhiyun }
3589*4882a593Smuzhiyun 
3590*4882a593Smuzhiyun 
3591*4882a593Smuzhiyun /**
3592*4882a593Smuzhiyun  * mptsas_send_expander_event - expanders events
3593*4882a593Smuzhiyun  * @ioc: Pointer to MPT_ADAPTER structure
3594*4882a593Smuzhiyun  * @expander_data: event data
3595*4882a593Smuzhiyun  *
3596*4882a593Smuzhiyun  *
3597*4882a593Smuzhiyun  * This function handles adding, removing, and refreshing
3598*4882a593Smuzhiyun  * device handles within the expander objects.
3599*4882a593Smuzhiyun  */
3600*4882a593Smuzhiyun static void
mptsas_send_expander_event(struct fw_event_work * fw_event)3601*4882a593Smuzhiyun mptsas_send_expander_event(struct fw_event_work *fw_event)
3602*4882a593Smuzhiyun {
3603*4882a593Smuzhiyun 	MPT_ADAPTER *ioc;
3604*4882a593Smuzhiyun 	MpiEventDataSasExpanderStatusChange_t *expander_data;
3605*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
3606*4882a593Smuzhiyun 	__le64 sas_address;
3607*4882a593Smuzhiyun 	int i;
3608*4882a593Smuzhiyun 
3609*4882a593Smuzhiyun 	ioc = fw_event->ioc;
3610*4882a593Smuzhiyun 	expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3611*4882a593Smuzhiyun 	    fw_event->event_data;
3612*4882a593Smuzhiyun 	memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3613*4882a593Smuzhiyun 	sas_address = le64_to_cpu(sas_address);
3614*4882a593Smuzhiyun 	port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3615*4882a593Smuzhiyun 
3616*4882a593Smuzhiyun 	if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3617*4882a593Smuzhiyun 		if (port_info) {
3618*4882a593Smuzhiyun 			for (i = 0; i < port_info->num_phys; i++) {
3619*4882a593Smuzhiyun 				port_info->phy_info[i].portinfo = port_info;
3620*4882a593Smuzhiyun 				port_info->phy_info[i].handle =
3621*4882a593Smuzhiyun 				    le16_to_cpu(expander_data->DevHandle);
3622*4882a593Smuzhiyun 				port_info->phy_info[i].identify.sas_address =
3623*4882a593Smuzhiyun 				    le64_to_cpu(sas_address);
3624*4882a593Smuzhiyun 				port_info->phy_info[i].identify.handle_parent =
3625*4882a593Smuzhiyun 				    le16_to_cpu(expander_data->ParentDevHandle);
3626*4882a593Smuzhiyun 			}
3627*4882a593Smuzhiyun 			mptsas_expander_refresh(ioc, port_info);
3628*4882a593Smuzhiyun 		} else if (!port_info && expander_data->NumPhys)
3629*4882a593Smuzhiyun 			mptsas_expander_event_add(ioc, expander_data);
3630*4882a593Smuzhiyun 	} else if (expander_data->ReasonCode ==
3631*4882a593Smuzhiyun 	    MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3632*4882a593Smuzhiyun 		mptsas_expander_delete(ioc, port_info, 0);
3633*4882a593Smuzhiyun 
3634*4882a593Smuzhiyun 	mptsas_free_fw_event(ioc, fw_event);
3635*4882a593Smuzhiyun }
3636*4882a593Smuzhiyun 
3637*4882a593Smuzhiyun 
3638*4882a593Smuzhiyun /**
3639*4882a593Smuzhiyun  * mptsas_expander_add -
3640*4882a593Smuzhiyun  * @ioc: Pointer to MPT_ADAPTER structure
3641*4882a593Smuzhiyun  * @handle:
3642*4882a593Smuzhiyun  *
3643*4882a593Smuzhiyun  */
3644*4882a593Smuzhiyun static struct mptsas_portinfo *
mptsas_expander_add(MPT_ADAPTER * ioc,u16 handle)3645*4882a593Smuzhiyun mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3646*4882a593Smuzhiyun {
3647*4882a593Smuzhiyun 	struct mptsas_portinfo buffer, *port_info;
3648*4882a593Smuzhiyun 	int i;
3649*4882a593Smuzhiyun 
3650*4882a593Smuzhiyun 	if ((mptsas_sas_expander_pg0(ioc, &buffer,
3651*4882a593Smuzhiyun 	    (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3652*4882a593Smuzhiyun 	    MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3653*4882a593Smuzhiyun 		return NULL;
3654*4882a593Smuzhiyun 
3655*4882a593Smuzhiyun 	port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3656*4882a593Smuzhiyun 	if (!port_info) {
3657*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3658*4882a593Smuzhiyun 		"%s: exit at line=%d\n", ioc->name,
3659*4882a593Smuzhiyun 		__func__, __LINE__));
3660*4882a593Smuzhiyun 		return NULL;
3661*4882a593Smuzhiyun 	}
3662*4882a593Smuzhiyun 	port_info->num_phys = buffer.num_phys;
3663*4882a593Smuzhiyun 	port_info->phy_info = buffer.phy_info;
3664*4882a593Smuzhiyun 	for (i = 0; i < port_info->num_phys; i++)
3665*4882a593Smuzhiyun 		port_info->phy_info[i].portinfo = port_info;
3666*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
3667*4882a593Smuzhiyun 	list_add_tail(&port_info->list, &ioc->sas_topology);
3668*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
3669*4882a593Smuzhiyun 	printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3670*4882a593Smuzhiyun 	    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3671*4882a593Smuzhiyun 	    (unsigned long long)buffer.phy_info[0].identify.sas_address);
3672*4882a593Smuzhiyun 	mptsas_expander_refresh(ioc, port_info);
3673*4882a593Smuzhiyun 	return port_info;
3674*4882a593Smuzhiyun }
3675*4882a593Smuzhiyun 
3676*4882a593Smuzhiyun static void
mptsas_send_link_status_event(struct fw_event_work * fw_event)3677*4882a593Smuzhiyun mptsas_send_link_status_event(struct fw_event_work *fw_event)
3678*4882a593Smuzhiyun {
3679*4882a593Smuzhiyun 	MPT_ADAPTER *ioc;
3680*4882a593Smuzhiyun 	MpiEventDataSasPhyLinkStatus_t *link_data;
3681*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
3682*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info = NULL;
3683*4882a593Smuzhiyun 	__le64 sas_address;
3684*4882a593Smuzhiyun 	u8 phy_num;
3685*4882a593Smuzhiyun 	u8 link_rate;
3686*4882a593Smuzhiyun 
3687*4882a593Smuzhiyun 	ioc = fw_event->ioc;
3688*4882a593Smuzhiyun 	link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3689*4882a593Smuzhiyun 
3690*4882a593Smuzhiyun 	memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3691*4882a593Smuzhiyun 	sas_address = le64_to_cpu(sas_address);
3692*4882a593Smuzhiyun 	link_rate = link_data->LinkRates >> 4;
3693*4882a593Smuzhiyun 	phy_num = link_data->PhyNum;
3694*4882a593Smuzhiyun 
3695*4882a593Smuzhiyun 	port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3696*4882a593Smuzhiyun 	if (port_info) {
3697*4882a593Smuzhiyun 		phy_info = &port_info->phy_info[phy_num];
3698*4882a593Smuzhiyun 		if (phy_info)
3699*4882a593Smuzhiyun 			phy_info->negotiated_link_rate = link_rate;
3700*4882a593Smuzhiyun 	}
3701*4882a593Smuzhiyun 
3702*4882a593Smuzhiyun 	if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3703*4882a593Smuzhiyun 	    link_rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
3704*4882a593Smuzhiyun 	    link_rate == MPI_SAS_IOUNIT0_RATE_6_0) {
3705*4882a593Smuzhiyun 
3706*4882a593Smuzhiyun 		if (!port_info) {
3707*4882a593Smuzhiyun 			if (ioc->old_sas_discovery_protocal) {
3708*4882a593Smuzhiyun 				port_info = mptsas_expander_add(ioc,
3709*4882a593Smuzhiyun 					le16_to_cpu(link_data->DevHandle));
3710*4882a593Smuzhiyun 				if (port_info)
3711*4882a593Smuzhiyun 					goto out;
3712*4882a593Smuzhiyun 			}
3713*4882a593Smuzhiyun 			goto out;
3714*4882a593Smuzhiyun 		}
3715*4882a593Smuzhiyun 
3716*4882a593Smuzhiyun 		if (port_info == ioc->hba_port_info)
3717*4882a593Smuzhiyun 			mptsas_probe_hba_phys(ioc);
3718*4882a593Smuzhiyun 		else
3719*4882a593Smuzhiyun 			mptsas_expander_refresh(ioc, port_info);
3720*4882a593Smuzhiyun 	} else if (phy_info && phy_info->phy) {
3721*4882a593Smuzhiyun 		if (link_rate ==  MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3722*4882a593Smuzhiyun 			phy_info->phy->negotiated_linkrate =
3723*4882a593Smuzhiyun 			    SAS_PHY_DISABLED;
3724*4882a593Smuzhiyun 		else if (link_rate ==
3725*4882a593Smuzhiyun 		    MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3726*4882a593Smuzhiyun 			phy_info->phy->negotiated_linkrate =
3727*4882a593Smuzhiyun 			    SAS_LINK_RATE_FAILED;
3728*4882a593Smuzhiyun 		else {
3729*4882a593Smuzhiyun 			phy_info->phy->negotiated_linkrate =
3730*4882a593Smuzhiyun 			    SAS_LINK_RATE_UNKNOWN;
3731*4882a593Smuzhiyun 			if (ioc->device_missing_delay &&
3732*4882a593Smuzhiyun 			    mptsas_is_end_device(&phy_info->attached)) {
3733*4882a593Smuzhiyun 				struct scsi_device		*sdev;
3734*4882a593Smuzhiyun 				VirtDevice			*vdevice;
3735*4882a593Smuzhiyun 				u8	channel, id;
3736*4882a593Smuzhiyun 				id = phy_info->attached.id;
3737*4882a593Smuzhiyun 				channel = phy_info->attached.channel;
3738*4882a593Smuzhiyun 				devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3739*4882a593Smuzhiyun 				"Link down for fw_id %d:fw_channel %d\n",
3740*4882a593Smuzhiyun 				    ioc->name, phy_info->attached.id,
3741*4882a593Smuzhiyun 				    phy_info->attached.channel));
3742*4882a593Smuzhiyun 
3743*4882a593Smuzhiyun 				shost_for_each_device(sdev, ioc->sh) {
3744*4882a593Smuzhiyun 					vdevice = sdev->hostdata;
3745*4882a593Smuzhiyun 					if ((vdevice == NULL) ||
3746*4882a593Smuzhiyun 						(vdevice->vtarget == NULL))
3747*4882a593Smuzhiyun 						continue;
3748*4882a593Smuzhiyun 					if ((vdevice->vtarget->tflags &
3749*4882a593Smuzhiyun 					    MPT_TARGET_FLAGS_RAID_COMPONENT ||
3750*4882a593Smuzhiyun 					    vdevice->vtarget->raidVolume))
3751*4882a593Smuzhiyun 						continue;
3752*4882a593Smuzhiyun 					if (vdevice->vtarget->id == id &&
3753*4882a593Smuzhiyun 						vdevice->vtarget->channel ==
3754*4882a593Smuzhiyun 						channel)
3755*4882a593Smuzhiyun 						devtprintk(ioc,
3756*4882a593Smuzhiyun 						printk(MYIOC_s_DEBUG_FMT
3757*4882a593Smuzhiyun 						"SDEV OUTSTANDING CMDS"
3758*4882a593Smuzhiyun 						"%d\n", ioc->name,
3759*4882a593Smuzhiyun 						atomic_read(&sdev->device_busy)));
3760*4882a593Smuzhiyun 				}
3761*4882a593Smuzhiyun 
3762*4882a593Smuzhiyun 			}
3763*4882a593Smuzhiyun 		}
3764*4882a593Smuzhiyun 	}
3765*4882a593Smuzhiyun  out:
3766*4882a593Smuzhiyun 	mptsas_free_fw_event(ioc, fw_event);
3767*4882a593Smuzhiyun }
3768*4882a593Smuzhiyun 
3769*4882a593Smuzhiyun static void
mptsas_not_responding_devices(MPT_ADAPTER * ioc)3770*4882a593Smuzhiyun mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3771*4882a593Smuzhiyun {
3772*4882a593Smuzhiyun 	struct mptsas_portinfo buffer, *port_info;
3773*4882a593Smuzhiyun 	struct mptsas_device_info	*sas_info;
3774*4882a593Smuzhiyun 	struct mptsas_devinfo sas_device;
3775*4882a593Smuzhiyun 	u32	handle;
3776*4882a593Smuzhiyun 	VirtTarget *vtarget = NULL;
3777*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
3778*4882a593Smuzhiyun 	u8 found_expander;
3779*4882a593Smuzhiyun 	int retval, retry_count;
3780*4882a593Smuzhiyun 	unsigned long flags;
3781*4882a593Smuzhiyun 
3782*4882a593Smuzhiyun 	mpt_findImVolumes(ioc);
3783*4882a593Smuzhiyun 
3784*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3785*4882a593Smuzhiyun 	if (ioc->ioc_reset_in_progress) {
3786*4882a593Smuzhiyun 		dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3787*4882a593Smuzhiyun 		   "%s: exiting due to a parallel reset \n", ioc->name,
3788*4882a593Smuzhiyun 		    __func__));
3789*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3790*4882a593Smuzhiyun 		return;
3791*4882a593Smuzhiyun 	}
3792*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3793*4882a593Smuzhiyun 
3794*4882a593Smuzhiyun 	/* devices, logical volumes */
3795*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_device_info_mutex);
3796*4882a593Smuzhiyun  redo_device_scan:
3797*4882a593Smuzhiyun 	list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
3798*4882a593Smuzhiyun 		if (sas_info->is_cached)
3799*4882a593Smuzhiyun 			continue;
3800*4882a593Smuzhiyun 		if (!sas_info->is_logical_volume) {
3801*4882a593Smuzhiyun 			sas_device.handle = 0;
3802*4882a593Smuzhiyun 			retry_count = 0;
3803*4882a593Smuzhiyun retry_page:
3804*4882a593Smuzhiyun 			retval = mptsas_sas_device_pg0(ioc, &sas_device,
3805*4882a593Smuzhiyun 				(MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3806*4882a593Smuzhiyun 				<< MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3807*4882a593Smuzhiyun 				(sas_info->fw.channel << 8) +
3808*4882a593Smuzhiyun 				sas_info->fw.id);
3809*4882a593Smuzhiyun 
3810*4882a593Smuzhiyun 			if (sas_device.handle)
3811*4882a593Smuzhiyun 				continue;
3812*4882a593Smuzhiyun 			if (retval == -EBUSY) {
3813*4882a593Smuzhiyun 				spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3814*4882a593Smuzhiyun 				if (ioc->ioc_reset_in_progress) {
3815*4882a593Smuzhiyun 					dfailprintk(ioc,
3816*4882a593Smuzhiyun 					printk(MYIOC_s_DEBUG_FMT
3817*4882a593Smuzhiyun 					"%s: exiting due to reset\n",
3818*4882a593Smuzhiyun 					ioc->name, __func__));
3819*4882a593Smuzhiyun 					spin_unlock_irqrestore
3820*4882a593Smuzhiyun 					(&ioc->taskmgmt_lock, flags);
3821*4882a593Smuzhiyun 					mutex_unlock(&ioc->
3822*4882a593Smuzhiyun 					sas_device_info_mutex);
3823*4882a593Smuzhiyun 					return;
3824*4882a593Smuzhiyun 				}
3825*4882a593Smuzhiyun 				spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3826*4882a593Smuzhiyun 				flags);
3827*4882a593Smuzhiyun 			}
3828*4882a593Smuzhiyun 
3829*4882a593Smuzhiyun 			if (retval && (retval != -ENODEV)) {
3830*4882a593Smuzhiyun 				if (retry_count < 10) {
3831*4882a593Smuzhiyun 					retry_count++;
3832*4882a593Smuzhiyun 					goto retry_page;
3833*4882a593Smuzhiyun 				} else {
3834*4882a593Smuzhiyun 					devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3835*4882a593Smuzhiyun 					"%s: Config page retry exceeded retry "
3836*4882a593Smuzhiyun 					"count deleting device 0x%llx\n",
3837*4882a593Smuzhiyun 					ioc->name, __func__,
3838*4882a593Smuzhiyun 					sas_info->sas_address));
3839*4882a593Smuzhiyun 				}
3840*4882a593Smuzhiyun 			}
3841*4882a593Smuzhiyun 
3842*4882a593Smuzhiyun 			/* delete device */
3843*4882a593Smuzhiyun 			vtarget = mptsas_find_vtarget(ioc,
3844*4882a593Smuzhiyun 				sas_info->fw.channel, sas_info->fw.id);
3845*4882a593Smuzhiyun 
3846*4882a593Smuzhiyun 			if (vtarget)
3847*4882a593Smuzhiyun 				vtarget->deleted = 1;
3848*4882a593Smuzhiyun 
3849*4882a593Smuzhiyun 			phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3850*4882a593Smuzhiyun 					sas_info->sas_address);
3851*4882a593Smuzhiyun 
3852*4882a593Smuzhiyun 			mptsas_del_end_device(ioc, phy_info);
3853*4882a593Smuzhiyun 			goto redo_device_scan;
3854*4882a593Smuzhiyun 		} else
3855*4882a593Smuzhiyun 			mptsas_volume_delete(ioc, sas_info->fw.id);
3856*4882a593Smuzhiyun 	}
3857*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_device_info_mutex);
3858*4882a593Smuzhiyun 
3859*4882a593Smuzhiyun 	/* expanders */
3860*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
3861*4882a593Smuzhiyun  redo_expander_scan:
3862*4882a593Smuzhiyun 	list_for_each_entry(port_info, &ioc->sas_topology, list) {
3863*4882a593Smuzhiyun 
3864*4882a593Smuzhiyun 		if (!(port_info->phy_info[0].identify.device_info &
3865*4882a593Smuzhiyun 		    MPI_SAS_DEVICE_INFO_SMP_TARGET))
3866*4882a593Smuzhiyun 			continue;
3867*4882a593Smuzhiyun 		found_expander = 0;
3868*4882a593Smuzhiyun 		handle = 0xFFFF;
3869*4882a593Smuzhiyun 		while (!mptsas_sas_expander_pg0(ioc, &buffer,
3870*4882a593Smuzhiyun 		    (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3871*4882a593Smuzhiyun 		     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3872*4882a593Smuzhiyun 		    !found_expander) {
3873*4882a593Smuzhiyun 
3874*4882a593Smuzhiyun 			handle = buffer.phy_info[0].handle;
3875*4882a593Smuzhiyun 			if (buffer.phy_info[0].identify.sas_address ==
3876*4882a593Smuzhiyun 			    port_info->phy_info[0].identify.sas_address) {
3877*4882a593Smuzhiyun 				found_expander = 1;
3878*4882a593Smuzhiyun 			}
3879*4882a593Smuzhiyun 			kfree(buffer.phy_info);
3880*4882a593Smuzhiyun 		}
3881*4882a593Smuzhiyun 
3882*4882a593Smuzhiyun 		if (!found_expander) {
3883*4882a593Smuzhiyun 			mptsas_expander_delete(ioc, port_info, 0);
3884*4882a593Smuzhiyun 			goto redo_expander_scan;
3885*4882a593Smuzhiyun 		}
3886*4882a593Smuzhiyun 	}
3887*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
3888*4882a593Smuzhiyun }
3889*4882a593Smuzhiyun 
3890*4882a593Smuzhiyun /**
3891*4882a593Smuzhiyun  *	mptsas_probe_expanders - adding expanders
3892*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
3893*4882a593Smuzhiyun  *
3894*4882a593Smuzhiyun  **/
3895*4882a593Smuzhiyun static void
mptsas_probe_expanders(MPT_ADAPTER * ioc)3896*4882a593Smuzhiyun mptsas_probe_expanders(MPT_ADAPTER *ioc)
3897*4882a593Smuzhiyun {
3898*4882a593Smuzhiyun 	struct mptsas_portinfo buffer, *port_info;
3899*4882a593Smuzhiyun 	u32 			handle;
3900*4882a593Smuzhiyun 	int i;
3901*4882a593Smuzhiyun 
3902*4882a593Smuzhiyun 	handle = 0xFFFF;
3903*4882a593Smuzhiyun 	while (!mptsas_sas_expander_pg0(ioc, &buffer,
3904*4882a593Smuzhiyun 	    (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3905*4882a593Smuzhiyun 	     MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3906*4882a593Smuzhiyun 
3907*4882a593Smuzhiyun 		handle = buffer.phy_info[0].handle;
3908*4882a593Smuzhiyun 		port_info = mptsas_find_portinfo_by_sas_address(ioc,
3909*4882a593Smuzhiyun 		    buffer.phy_info[0].identify.sas_address);
3910*4882a593Smuzhiyun 
3911*4882a593Smuzhiyun 		if (port_info) {
3912*4882a593Smuzhiyun 			/* refreshing handles */
3913*4882a593Smuzhiyun 			for (i = 0; i < buffer.num_phys; i++) {
3914*4882a593Smuzhiyun 				port_info->phy_info[i].handle = handle;
3915*4882a593Smuzhiyun 				port_info->phy_info[i].identify.handle_parent =
3916*4882a593Smuzhiyun 				    buffer.phy_info[0].identify.handle_parent;
3917*4882a593Smuzhiyun 			}
3918*4882a593Smuzhiyun 			mptsas_expander_refresh(ioc, port_info);
3919*4882a593Smuzhiyun 			kfree(buffer.phy_info);
3920*4882a593Smuzhiyun 			continue;
3921*4882a593Smuzhiyun 		}
3922*4882a593Smuzhiyun 
3923*4882a593Smuzhiyun 		port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3924*4882a593Smuzhiyun 		if (!port_info) {
3925*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3926*4882a593Smuzhiyun 			"%s: exit at line=%d\n", ioc->name,
3927*4882a593Smuzhiyun 			__func__, __LINE__));
3928*4882a593Smuzhiyun 			return;
3929*4882a593Smuzhiyun 		}
3930*4882a593Smuzhiyun 		port_info->num_phys = buffer.num_phys;
3931*4882a593Smuzhiyun 		port_info->phy_info = buffer.phy_info;
3932*4882a593Smuzhiyun 		for (i = 0; i < port_info->num_phys; i++)
3933*4882a593Smuzhiyun 			port_info->phy_info[i].portinfo = port_info;
3934*4882a593Smuzhiyun 		mutex_lock(&ioc->sas_topology_mutex);
3935*4882a593Smuzhiyun 		list_add_tail(&port_info->list, &ioc->sas_topology);
3936*4882a593Smuzhiyun 		mutex_unlock(&ioc->sas_topology_mutex);
3937*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3938*4882a593Smuzhiyun 		    "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3939*4882a593Smuzhiyun 	    (unsigned long long)buffer.phy_info[0].identify.sas_address);
3940*4882a593Smuzhiyun 		mptsas_expander_refresh(ioc, port_info);
3941*4882a593Smuzhiyun 	}
3942*4882a593Smuzhiyun }
3943*4882a593Smuzhiyun 
3944*4882a593Smuzhiyun static void
mptsas_probe_devices(MPT_ADAPTER * ioc)3945*4882a593Smuzhiyun mptsas_probe_devices(MPT_ADAPTER *ioc)
3946*4882a593Smuzhiyun {
3947*4882a593Smuzhiyun 	u16 handle;
3948*4882a593Smuzhiyun 	struct mptsas_devinfo sas_device;
3949*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
3950*4882a593Smuzhiyun 
3951*4882a593Smuzhiyun 	handle = 0xFFFF;
3952*4882a593Smuzhiyun 	while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3953*4882a593Smuzhiyun 	    MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3954*4882a593Smuzhiyun 
3955*4882a593Smuzhiyun 		handle = sas_device.handle;
3956*4882a593Smuzhiyun 
3957*4882a593Smuzhiyun 		if ((sas_device.device_info &
3958*4882a593Smuzhiyun 		     (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3959*4882a593Smuzhiyun 		      MPI_SAS_DEVICE_INFO_STP_TARGET |
3960*4882a593Smuzhiyun 		      MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3961*4882a593Smuzhiyun 			continue;
3962*4882a593Smuzhiyun 
3963*4882a593Smuzhiyun 		/* If there is no FW B_T mapping for this device then continue
3964*4882a593Smuzhiyun 		 * */
3965*4882a593Smuzhiyun 		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
3966*4882a593Smuzhiyun 			|| !(sas_device.flags &
3967*4882a593Smuzhiyun 			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
3968*4882a593Smuzhiyun 			continue;
3969*4882a593Smuzhiyun 
3970*4882a593Smuzhiyun 		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3971*4882a593Smuzhiyun 		if (!phy_info)
3972*4882a593Smuzhiyun 			continue;
3973*4882a593Smuzhiyun 
3974*4882a593Smuzhiyun 		if (mptsas_get_rphy(phy_info))
3975*4882a593Smuzhiyun 			continue;
3976*4882a593Smuzhiyun 
3977*4882a593Smuzhiyun 		mptsas_add_end_device(ioc, phy_info);
3978*4882a593Smuzhiyun 	}
3979*4882a593Smuzhiyun }
3980*4882a593Smuzhiyun 
3981*4882a593Smuzhiyun /**
3982*4882a593Smuzhiyun  *	mptsas_scan_sas_topology -
3983*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
3984*4882a593Smuzhiyun  *	@sas_address:
3985*4882a593Smuzhiyun  *
3986*4882a593Smuzhiyun  **/
3987*4882a593Smuzhiyun static void
mptsas_scan_sas_topology(MPT_ADAPTER * ioc)3988*4882a593Smuzhiyun mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3989*4882a593Smuzhiyun {
3990*4882a593Smuzhiyun 	struct scsi_device *sdev;
3991*4882a593Smuzhiyun 	int i;
3992*4882a593Smuzhiyun 
3993*4882a593Smuzhiyun 	mptsas_probe_hba_phys(ioc);
3994*4882a593Smuzhiyun 	mptsas_probe_expanders(ioc);
3995*4882a593Smuzhiyun 	mptsas_probe_devices(ioc);
3996*4882a593Smuzhiyun 
3997*4882a593Smuzhiyun 	/*
3998*4882a593Smuzhiyun 	  Reporting RAID volumes.
3999*4882a593Smuzhiyun 	*/
4000*4882a593Smuzhiyun 	if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
4001*4882a593Smuzhiyun 	    !ioc->raid_data.pIocPg2->NumActiveVolumes)
4002*4882a593Smuzhiyun 		return;
4003*4882a593Smuzhiyun 	for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4004*4882a593Smuzhiyun 		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4005*4882a593Smuzhiyun 		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4006*4882a593Smuzhiyun 		if (sdev) {
4007*4882a593Smuzhiyun 			scsi_device_put(sdev);
4008*4882a593Smuzhiyun 			continue;
4009*4882a593Smuzhiyun 		}
4010*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4011*4882a593Smuzhiyun 		    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4012*4882a593Smuzhiyun 		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
4013*4882a593Smuzhiyun 		scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4014*4882a593Smuzhiyun 		    ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4015*4882a593Smuzhiyun 	}
4016*4882a593Smuzhiyun }
4017*4882a593Smuzhiyun 
4018*4882a593Smuzhiyun 
4019*4882a593Smuzhiyun static void
mptsas_handle_queue_full_event(struct fw_event_work * fw_event)4020*4882a593Smuzhiyun mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
4021*4882a593Smuzhiyun {
4022*4882a593Smuzhiyun 	MPT_ADAPTER *ioc;
4023*4882a593Smuzhiyun 	EventDataQueueFull_t *qfull_data;
4024*4882a593Smuzhiyun 	struct mptsas_device_info *sas_info;
4025*4882a593Smuzhiyun 	struct scsi_device	*sdev;
4026*4882a593Smuzhiyun 	int depth;
4027*4882a593Smuzhiyun 	int id = -1;
4028*4882a593Smuzhiyun 	int channel = -1;
4029*4882a593Smuzhiyun 	int fw_id, fw_channel;
4030*4882a593Smuzhiyun 	u16 current_depth;
4031*4882a593Smuzhiyun 
4032*4882a593Smuzhiyun 
4033*4882a593Smuzhiyun 	ioc = fw_event->ioc;
4034*4882a593Smuzhiyun 	qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
4035*4882a593Smuzhiyun 	fw_id = qfull_data->TargetID;
4036*4882a593Smuzhiyun 	fw_channel = qfull_data->Bus;
4037*4882a593Smuzhiyun 	current_depth = le16_to_cpu(qfull_data->CurrentDepth);
4038*4882a593Smuzhiyun 
4039*4882a593Smuzhiyun 	/* if hidden raid component, look for the volume id */
4040*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_device_info_mutex);
4041*4882a593Smuzhiyun 	if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
4042*4882a593Smuzhiyun 		list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4043*4882a593Smuzhiyun 		    list) {
4044*4882a593Smuzhiyun 			if (sas_info->is_cached ||
4045*4882a593Smuzhiyun 			    sas_info->is_logical_volume)
4046*4882a593Smuzhiyun 				continue;
4047*4882a593Smuzhiyun 			if (sas_info->is_hidden_raid_component &&
4048*4882a593Smuzhiyun 			    (sas_info->fw.channel == fw_channel &&
4049*4882a593Smuzhiyun 			    sas_info->fw.id == fw_id)) {
4050*4882a593Smuzhiyun 				id = sas_info->volume_id;
4051*4882a593Smuzhiyun 				channel = MPTSAS_RAID_CHANNEL;
4052*4882a593Smuzhiyun 				goto out;
4053*4882a593Smuzhiyun 			}
4054*4882a593Smuzhiyun 		}
4055*4882a593Smuzhiyun 	} else {
4056*4882a593Smuzhiyun 		list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4057*4882a593Smuzhiyun 		    list) {
4058*4882a593Smuzhiyun 			if (sas_info->is_cached ||
4059*4882a593Smuzhiyun 			    sas_info->is_hidden_raid_component ||
4060*4882a593Smuzhiyun 			    sas_info->is_logical_volume)
4061*4882a593Smuzhiyun 				continue;
4062*4882a593Smuzhiyun 			if (sas_info->fw.channel == fw_channel &&
4063*4882a593Smuzhiyun 			    sas_info->fw.id == fw_id) {
4064*4882a593Smuzhiyun 				id = sas_info->os.id;
4065*4882a593Smuzhiyun 				channel = sas_info->os.channel;
4066*4882a593Smuzhiyun 				goto out;
4067*4882a593Smuzhiyun 			}
4068*4882a593Smuzhiyun 		}
4069*4882a593Smuzhiyun 
4070*4882a593Smuzhiyun 	}
4071*4882a593Smuzhiyun 
4072*4882a593Smuzhiyun  out:
4073*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_device_info_mutex);
4074*4882a593Smuzhiyun 
4075*4882a593Smuzhiyun 	if (id != -1) {
4076*4882a593Smuzhiyun 		shost_for_each_device(sdev, ioc->sh) {
4077*4882a593Smuzhiyun 			if (sdev->id == id && sdev->channel == channel) {
4078*4882a593Smuzhiyun 				if (current_depth > sdev->queue_depth) {
4079*4882a593Smuzhiyun 					sdev_printk(KERN_INFO, sdev,
4080*4882a593Smuzhiyun 					    "strange observation, the queue "
4081*4882a593Smuzhiyun 					    "depth is (%d) meanwhile fw queue "
4082*4882a593Smuzhiyun 					    "depth (%d)\n", sdev->queue_depth,
4083*4882a593Smuzhiyun 					    current_depth);
4084*4882a593Smuzhiyun 					continue;
4085*4882a593Smuzhiyun 				}
4086*4882a593Smuzhiyun 				depth = scsi_track_queue_full(sdev,
4087*4882a593Smuzhiyun 					sdev->queue_depth - 1);
4088*4882a593Smuzhiyun 				if (depth > 0)
4089*4882a593Smuzhiyun 					sdev_printk(KERN_INFO, sdev,
4090*4882a593Smuzhiyun 					"Queue depth reduced to (%d)\n",
4091*4882a593Smuzhiyun 					   depth);
4092*4882a593Smuzhiyun 				else if (depth < 0)
4093*4882a593Smuzhiyun 					sdev_printk(KERN_INFO, sdev,
4094*4882a593Smuzhiyun 					"Tagged Command Queueing is being "
4095*4882a593Smuzhiyun 					"disabled\n");
4096*4882a593Smuzhiyun 				else if (depth == 0)
4097*4882a593Smuzhiyun 					sdev_printk(KERN_DEBUG, sdev,
4098*4882a593Smuzhiyun 					"Queue depth not changed yet\n");
4099*4882a593Smuzhiyun 			}
4100*4882a593Smuzhiyun 		}
4101*4882a593Smuzhiyun 	}
4102*4882a593Smuzhiyun 
4103*4882a593Smuzhiyun 	mptsas_free_fw_event(ioc, fw_event);
4104*4882a593Smuzhiyun }
4105*4882a593Smuzhiyun 
4106*4882a593Smuzhiyun 
4107*4882a593Smuzhiyun static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER * ioc,u64 sas_address)4108*4882a593Smuzhiyun mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
4109*4882a593Smuzhiyun {
4110*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
4111*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info = NULL;
4112*4882a593Smuzhiyun 	int i;
4113*4882a593Smuzhiyun 
4114*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
4115*4882a593Smuzhiyun 	list_for_each_entry(port_info, &ioc->sas_topology, list) {
4116*4882a593Smuzhiyun 		for (i = 0; i < port_info->num_phys; i++) {
4117*4882a593Smuzhiyun 			if (!mptsas_is_end_device(
4118*4882a593Smuzhiyun 				&port_info->phy_info[i].attached))
4119*4882a593Smuzhiyun 				continue;
4120*4882a593Smuzhiyun 			if (port_info->phy_info[i].attached.sas_address
4121*4882a593Smuzhiyun 			    != sas_address)
4122*4882a593Smuzhiyun 				continue;
4123*4882a593Smuzhiyun 			phy_info = &port_info->phy_info[i];
4124*4882a593Smuzhiyun 			break;
4125*4882a593Smuzhiyun 		}
4126*4882a593Smuzhiyun 	}
4127*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
4128*4882a593Smuzhiyun 	return phy_info;
4129*4882a593Smuzhiyun }
4130*4882a593Smuzhiyun 
4131*4882a593Smuzhiyun /**
4132*4882a593Smuzhiyun  *	mptsas_find_phyinfo_by_phys_disk_num -
4133*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
4134*4882a593Smuzhiyun  *	@phys_disk_num:
4135*4882a593Smuzhiyun  *	@channel:
4136*4882a593Smuzhiyun  *	@id:
4137*4882a593Smuzhiyun  *
4138*4882a593Smuzhiyun  **/
4139*4882a593Smuzhiyun static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER * ioc,u8 phys_disk_num,u8 channel,u8 id)4140*4882a593Smuzhiyun mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4141*4882a593Smuzhiyun 	u8 channel, u8 id)
4142*4882a593Smuzhiyun {
4143*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info = NULL;
4144*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
4145*4882a593Smuzhiyun 	RaidPhysDiskPage1_t *phys_disk = NULL;
4146*4882a593Smuzhiyun 	int num_paths;
4147*4882a593Smuzhiyun 	u64 sas_address = 0;
4148*4882a593Smuzhiyun 	int i;
4149*4882a593Smuzhiyun 
4150*4882a593Smuzhiyun 	phy_info = NULL;
4151*4882a593Smuzhiyun 	if (!ioc->raid_data.pIocPg3)
4152*4882a593Smuzhiyun 		return NULL;
4153*4882a593Smuzhiyun 	/* dual port support */
4154*4882a593Smuzhiyun 	num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4155*4882a593Smuzhiyun 	if (!num_paths)
4156*4882a593Smuzhiyun 		goto out;
4157*4882a593Smuzhiyun 	phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4158*4882a593Smuzhiyun 	   (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4159*4882a593Smuzhiyun 	if (!phys_disk)
4160*4882a593Smuzhiyun 		goto out;
4161*4882a593Smuzhiyun 	mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4162*4882a593Smuzhiyun 	for (i = 0; i < num_paths; i++) {
4163*4882a593Smuzhiyun 		if ((phys_disk->Path[i].Flags & 1) != 0)
4164*4882a593Smuzhiyun 			/* entry no longer valid */
4165*4882a593Smuzhiyun 			continue;
4166*4882a593Smuzhiyun 		if ((id == phys_disk->Path[i].PhysDiskID) &&
4167*4882a593Smuzhiyun 		    (channel == phys_disk->Path[i].PhysDiskBus)) {
4168*4882a593Smuzhiyun 			memcpy(&sas_address, &phys_disk->Path[i].WWID,
4169*4882a593Smuzhiyun 				sizeof(u64));
4170*4882a593Smuzhiyun 			phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4171*4882a593Smuzhiyun 					sas_address);
4172*4882a593Smuzhiyun 			goto out;
4173*4882a593Smuzhiyun 		}
4174*4882a593Smuzhiyun 	}
4175*4882a593Smuzhiyun 
4176*4882a593Smuzhiyun  out:
4177*4882a593Smuzhiyun 	kfree(phys_disk);
4178*4882a593Smuzhiyun 	if (phy_info)
4179*4882a593Smuzhiyun 		return phy_info;
4180*4882a593Smuzhiyun 
4181*4882a593Smuzhiyun 	/*
4182*4882a593Smuzhiyun 	 * Extra code to handle RAID0 case, where the sas_address is not updated
4183*4882a593Smuzhiyun 	 * in phys_disk_page_1 when hotswapped
4184*4882a593Smuzhiyun 	 */
4185*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
4186*4882a593Smuzhiyun 	list_for_each_entry(port_info, &ioc->sas_topology, list) {
4187*4882a593Smuzhiyun 		for (i = 0; i < port_info->num_phys && !phy_info; i++) {
4188*4882a593Smuzhiyun 			if (!mptsas_is_end_device(
4189*4882a593Smuzhiyun 				&port_info->phy_info[i].attached))
4190*4882a593Smuzhiyun 				continue;
4191*4882a593Smuzhiyun 			if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4192*4882a593Smuzhiyun 				continue;
4193*4882a593Smuzhiyun 			if ((port_info->phy_info[i].attached.phys_disk_num ==
4194*4882a593Smuzhiyun 			    phys_disk_num) &&
4195*4882a593Smuzhiyun 			    (port_info->phy_info[i].attached.id == id) &&
4196*4882a593Smuzhiyun 			    (port_info->phy_info[i].attached.channel ==
4197*4882a593Smuzhiyun 			     channel))
4198*4882a593Smuzhiyun 				phy_info = &port_info->phy_info[i];
4199*4882a593Smuzhiyun 		}
4200*4882a593Smuzhiyun 	}
4201*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
4202*4882a593Smuzhiyun 	return phy_info;
4203*4882a593Smuzhiyun }
4204*4882a593Smuzhiyun 
4205*4882a593Smuzhiyun static void
mptsas_reprobe_lun(struct scsi_device * sdev,void * data)4206*4882a593Smuzhiyun mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4207*4882a593Smuzhiyun {
4208*4882a593Smuzhiyun 	int rc;
4209*4882a593Smuzhiyun 
4210*4882a593Smuzhiyun 	sdev->no_uld_attach = data ? 1 : 0;
4211*4882a593Smuzhiyun 	rc = scsi_device_reprobe(sdev);
4212*4882a593Smuzhiyun }
4213*4882a593Smuzhiyun 
4214*4882a593Smuzhiyun static void
mptsas_reprobe_target(struct scsi_target * starget,int uld_attach)4215*4882a593Smuzhiyun mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4216*4882a593Smuzhiyun {
4217*4882a593Smuzhiyun 	starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4218*4882a593Smuzhiyun 			mptsas_reprobe_lun);
4219*4882a593Smuzhiyun }
4220*4882a593Smuzhiyun 
4221*4882a593Smuzhiyun static void
mptsas_adding_inactive_raid_components(MPT_ADAPTER * ioc,u8 channel,u8 id)4222*4882a593Smuzhiyun mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4223*4882a593Smuzhiyun {
4224*4882a593Smuzhiyun 	CONFIGPARMS			cfg;
4225*4882a593Smuzhiyun 	ConfigPageHeader_t		hdr;
4226*4882a593Smuzhiyun 	dma_addr_t			dma_handle;
4227*4882a593Smuzhiyun 	pRaidVolumePage0_t		buffer = NULL;
4228*4882a593Smuzhiyun 	RaidPhysDiskPage0_t 		phys_disk;
4229*4882a593Smuzhiyun 	int				i;
4230*4882a593Smuzhiyun 	struct mptsas_phyinfo	*phy_info;
4231*4882a593Smuzhiyun 	struct mptsas_devinfo		sas_device;
4232*4882a593Smuzhiyun 
4233*4882a593Smuzhiyun 	memset(&cfg, 0 , sizeof(CONFIGPARMS));
4234*4882a593Smuzhiyun 	memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4235*4882a593Smuzhiyun 	hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4236*4882a593Smuzhiyun 	cfg.pageAddr = (channel << 8) + id;
4237*4882a593Smuzhiyun 	cfg.cfghdr.hdr = &hdr;
4238*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4239*4882a593Smuzhiyun 	cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
4240*4882a593Smuzhiyun 
4241*4882a593Smuzhiyun 	if (mpt_config(ioc, &cfg) != 0)
4242*4882a593Smuzhiyun 		goto out;
4243*4882a593Smuzhiyun 
4244*4882a593Smuzhiyun 	if (!hdr.PageLength)
4245*4882a593Smuzhiyun 		goto out;
4246*4882a593Smuzhiyun 
4247*4882a593Smuzhiyun 	buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4248*4882a593Smuzhiyun 	    &dma_handle);
4249*4882a593Smuzhiyun 
4250*4882a593Smuzhiyun 	if (!buffer)
4251*4882a593Smuzhiyun 		goto out;
4252*4882a593Smuzhiyun 
4253*4882a593Smuzhiyun 	cfg.physAddr = dma_handle;
4254*4882a593Smuzhiyun 	cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4255*4882a593Smuzhiyun 
4256*4882a593Smuzhiyun 	if (mpt_config(ioc, &cfg) != 0)
4257*4882a593Smuzhiyun 		goto out;
4258*4882a593Smuzhiyun 
4259*4882a593Smuzhiyun 	if (!(buffer->VolumeStatus.Flags &
4260*4882a593Smuzhiyun 	    MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4261*4882a593Smuzhiyun 		goto out;
4262*4882a593Smuzhiyun 
4263*4882a593Smuzhiyun 	if (!buffer->NumPhysDisks)
4264*4882a593Smuzhiyun 		goto out;
4265*4882a593Smuzhiyun 
4266*4882a593Smuzhiyun 	for (i = 0; i < buffer->NumPhysDisks; i++) {
4267*4882a593Smuzhiyun 
4268*4882a593Smuzhiyun 		if (mpt_raid_phys_disk_pg0(ioc,
4269*4882a593Smuzhiyun 		    buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4270*4882a593Smuzhiyun 			continue;
4271*4882a593Smuzhiyun 
4272*4882a593Smuzhiyun 		if (mptsas_sas_device_pg0(ioc, &sas_device,
4273*4882a593Smuzhiyun 		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4274*4882a593Smuzhiyun 		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4275*4882a593Smuzhiyun 			(phys_disk.PhysDiskBus << 8) +
4276*4882a593Smuzhiyun 			phys_disk.PhysDiskID))
4277*4882a593Smuzhiyun 			continue;
4278*4882a593Smuzhiyun 
4279*4882a593Smuzhiyun 		/* If there is no FW B_T mapping for this device then continue
4280*4882a593Smuzhiyun 		 * */
4281*4882a593Smuzhiyun 		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4282*4882a593Smuzhiyun 			|| !(sas_device.flags &
4283*4882a593Smuzhiyun 			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4284*4882a593Smuzhiyun 			continue;
4285*4882a593Smuzhiyun 
4286*4882a593Smuzhiyun 
4287*4882a593Smuzhiyun 		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4288*4882a593Smuzhiyun 		    sas_device.sas_address);
4289*4882a593Smuzhiyun 		mptsas_add_end_device(ioc, phy_info);
4290*4882a593Smuzhiyun 	}
4291*4882a593Smuzhiyun 
4292*4882a593Smuzhiyun  out:
4293*4882a593Smuzhiyun 	if (buffer)
4294*4882a593Smuzhiyun 		pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4295*4882a593Smuzhiyun 		    dma_handle);
4296*4882a593Smuzhiyun }
4297*4882a593Smuzhiyun /*
4298*4882a593Smuzhiyun  * Work queue thread to handle SAS hotplug events
4299*4882a593Smuzhiyun  */
4300*4882a593Smuzhiyun static void
mptsas_hotplug_work(MPT_ADAPTER * ioc,struct fw_event_work * fw_event,struct mptsas_hotplug_event * hot_plug_info)4301*4882a593Smuzhiyun mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4302*4882a593Smuzhiyun     struct mptsas_hotplug_event *hot_plug_info)
4303*4882a593Smuzhiyun {
4304*4882a593Smuzhiyun 	struct mptsas_phyinfo *phy_info;
4305*4882a593Smuzhiyun 	struct scsi_target * starget;
4306*4882a593Smuzhiyun 	struct mptsas_devinfo sas_device;
4307*4882a593Smuzhiyun 	VirtTarget *vtarget;
4308*4882a593Smuzhiyun 	int i;
4309*4882a593Smuzhiyun 	struct mptsas_portinfo *port_info;
4310*4882a593Smuzhiyun 
4311*4882a593Smuzhiyun 	switch (hot_plug_info->event_type) {
4312*4882a593Smuzhiyun 
4313*4882a593Smuzhiyun 	case MPTSAS_ADD_PHYSDISK:
4314*4882a593Smuzhiyun 
4315*4882a593Smuzhiyun 		if (!ioc->raid_data.pIocPg2)
4316*4882a593Smuzhiyun 			break;
4317*4882a593Smuzhiyun 
4318*4882a593Smuzhiyun 		for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4319*4882a593Smuzhiyun 			if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4320*4882a593Smuzhiyun 			    hot_plug_info->id) {
4321*4882a593Smuzhiyun 				printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4322*4882a593Smuzhiyun 				    "to add hidden disk - target_id matches "
4323*4882a593Smuzhiyun 				    "volume_id\n", ioc->name);
4324*4882a593Smuzhiyun 				mptsas_free_fw_event(ioc, fw_event);
4325*4882a593Smuzhiyun 				return;
4326*4882a593Smuzhiyun 			}
4327*4882a593Smuzhiyun 		}
4328*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4329*4882a593Smuzhiyun 		fallthrough;
4330*4882a593Smuzhiyun 
4331*4882a593Smuzhiyun 	case MPTSAS_ADD_DEVICE:
4332*4882a593Smuzhiyun 		memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4333*4882a593Smuzhiyun 		mptsas_sas_device_pg0(ioc, &sas_device,
4334*4882a593Smuzhiyun 		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4335*4882a593Smuzhiyun 		    MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4336*4882a593Smuzhiyun 		    (hot_plug_info->channel << 8) +
4337*4882a593Smuzhiyun 		    hot_plug_info->id);
4338*4882a593Smuzhiyun 
4339*4882a593Smuzhiyun 		/* If there is no FW B_T mapping for this device then break
4340*4882a593Smuzhiyun 		 * */
4341*4882a593Smuzhiyun 		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4342*4882a593Smuzhiyun 			|| !(sas_device.flags &
4343*4882a593Smuzhiyun 			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4344*4882a593Smuzhiyun 			break;
4345*4882a593Smuzhiyun 
4346*4882a593Smuzhiyun 		if (!sas_device.handle)
4347*4882a593Smuzhiyun 			return;
4348*4882a593Smuzhiyun 
4349*4882a593Smuzhiyun 		phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4350*4882a593Smuzhiyun 		/* Device hot plug */
4351*4882a593Smuzhiyun 		if (!phy_info) {
4352*4882a593Smuzhiyun 			devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4353*4882a593Smuzhiyun 				"%s %d HOT PLUG: "
4354*4882a593Smuzhiyun 				"parent handle of device %x\n", ioc->name,
4355*4882a593Smuzhiyun 				__func__, __LINE__, sas_device.handle_parent));
4356*4882a593Smuzhiyun 			port_info = mptsas_find_portinfo_by_handle(ioc,
4357*4882a593Smuzhiyun 				sas_device.handle_parent);
4358*4882a593Smuzhiyun 
4359*4882a593Smuzhiyun 			if (port_info == ioc->hba_port_info)
4360*4882a593Smuzhiyun 				mptsas_probe_hba_phys(ioc);
4361*4882a593Smuzhiyun 			else if (port_info)
4362*4882a593Smuzhiyun 				mptsas_expander_refresh(ioc, port_info);
4363*4882a593Smuzhiyun 			else {
4364*4882a593Smuzhiyun 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4365*4882a593Smuzhiyun 					"%s %d port info is NULL\n",
4366*4882a593Smuzhiyun 					ioc->name, __func__, __LINE__));
4367*4882a593Smuzhiyun 				break;
4368*4882a593Smuzhiyun 			}
4369*4882a593Smuzhiyun 			phy_info = mptsas_refreshing_device_handles
4370*4882a593Smuzhiyun 				(ioc, &sas_device);
4371*4882a593Smuzhiyun 		}
4372*4882a593Smuzhiyun 
4373*4882a593Smuzhiyun 		if (!phy_info) {
4374*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4375*4882a593Smuzhiyun 				"%s %d phy info is NULL\n",
4376*4882a593Smuzhiyun 				ioc->name, __func__, __LINE__));
4377*4882a593Smuzhiyun 			break;
4378*4882a593Smuzhiyun 		}
4379*4882a593Smuzhiyun 
4380*4882a593Smuzhiyun 		if (mptsas_get_rphy(phy_info))
4381*4882a593Smuzhiyun 			break;
4382*4882a593Smuzhiyun 
4383*4882a593Smuzhiyun 		mptsas_add_end_device(ioc, phy_info);
4384*4882a593Smuzhiyun 		break;
4385*4882a593Smuzhiyun 
4386*4882a593Smuzhiyun 	case MPTSAS_DEL_DEVICE:
4387*4882a593Smuzhiyun 		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4388*4882a593Smuzhiyun 		    hot_plug_info->sas_address);
4389*4882a593Smuzhiyun 		mptsas_del_end_device(ioc, phy_info);
4390*4882a593Smuzhiyun 		break;
4391*4882a593Smuzhiyun 
4392*4882a593Smuzhiyun 	case MPTSAS_DEL_PHYSDISK:
4393*4882a593Smuzhiyun 
4394*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4395*4882a593Smuzhiyun 
4396*4882a593Smuzhiyun 		phy_info = mptsas_find_phyinfo_by_phys_disk_num(
4397*4882a593Smuzhiyun 				ioc, hot_plug_info->phys_disk_num,
4398*4882a593Smuzhiyun 				hot_plug_info->channel,
4399*4882a593Smuzhiyun 				hot_plug_info->id);
4400*4882a593Smuzhiyun 		mptsas_del_end_device(ioc, phy_info);
4401*4882a593Smuzhiyun 		break;
4402*4882a593Smuzhiyun 
4403*4882a593Smuzhiyun 	case MPTSAS_ADD_PHYSDISK_REPROBE:
4404*4882a593Smuzhiyun 
4405*4882a593Smuzhiyun 		if (mptsas_sas_device_pg0(ioc, &sas_device,
4406*4882a593Smuzhiyun 		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4407*4882a593Smuzhiyun 		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4408*4882a593Smuzhiyun 		    (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4409*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4410*4882a593Smuzhiyun 			"%s: fw_id=%d exit at line=%d\n", ioc->name,
4411*4882a593Smuzhiyun 				 __func__, hot_plug_info->id, __LINE__));
4412*4882a593Smuzhiyun 			break;
4413*4882a593Smuzhiyun 		}
4414*4882a593Smuzhiyun 
4415*4882a593Smuzhiyun 		/* If there is no FW B_T mapping for this device then break
4416*4882a593Smuzhiyun 		 * */
4417*4882a593Smuzhiyun 		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4418*4882a593Smuzhiyun 			|| !(sas_device.flags &
4419*4882a593Smuzhiyun 			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4420*4882a593Smuzhiyun 			break;
4421*4882a593Smuzhiyun 
4422*4882a593Smuzhiyun 		phy_info = mptsas_find_phyinfo_by_sas_address(
4423*4882a593Smuzhiyun 		    ioc, sas_device.sas_address);
4424*4882a593Smuzhiyun 
4425*4882a593Smuzhiyun 		if (!phy_info) {
4426*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4427*4882a593Smuzhiyun 				"%s: fw_id=%d exit at line=%d\n", ioc->name,
4428*4882a593Smuzhiyun 				 __func__, hot_plug_info->id, __LINE__));
4429*4882a593Smuzhiyun 			break;
4430*4882a593Smuzhiyun 		}
4431*4882a593Smuzhiyun 
4432*4882a593Smuzhiyun 		starget = mptsas_get_starget(phy_info);
4433*4882a593Smuzhiyun 		if (!starget) {
4434*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4435*4882a593Smuzhiyun 				"%s: fw_id=%d exit at line=%d\n", ioc->name,
4436*4882a593Smuzhiyun 				 __func__, hot_plug_info->id, __LINE__));
4437*4882a593Smuzhiyun 			break;
4438*4882a593Smuzhiyun 		}
4439*4882a593Smuzhiyun 
4440*4882a593Smuzhiyun 		vtarget = starget->hostdata;
4441*4882a593Smuzhiyun 		if (!vtarget) {
4442*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4443*4882a593Smuzhiyun 				"%s: fw_id=%d exit at line=%d\n", ioc->name,
4444*4882a593Smuzhiyun 				 __func__, hot_plug_info->id, __LINE__));
4445*4882a593Smuzhiyun 			break;
4446*4882a593Smuzhiyun 		}
4447*4882a593Smuzhiyun 
4448*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4449*4882a593Smuzhiyun 
4450*4882a593Smuzhiyun 		starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4451*4882a593Smuzhiyun 		    "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4452*4882a593Smuzhiyun 		    ioc->name, hot_plug_info->channel, hot_plug_info->id,
4453*4882a593Smuzhiyun 		    hot_plug_info->phys_disk_num, (unsigned long long)
4454*4882a593Smuzhiyun 		    sas_device.sas_address);
4455*4882a593Smuzhiyun 
4456*4882a593Smuzhiyun 		vtarget->id = hot_plug_info->phys_disk_num;
4457*4882a593Smuzhiyun 		vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4458*4882a593Smuzhiyun 		phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4459*4882a593Smuzhiyun 		mptsas_reprobe_target(starget, 1);
4460*4882a593Smuzhiyun 		break;
4461*4882a593Smuzhiyun 
4462*4882a593Smuzhiyun 	case MPTSAS_DEL_PHYSDISK_REPROBE:
4463*4882a593Smuzhiyun 
4464*4882a593Smuzhiyun 		if (mptsas_sas_device_pg0(ioc, &sas_device,
4465*4882a593Smuzhiyun 		    (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4466*4882a593Smuzhiyun 		     MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4467*4882a593Smuzhiyun 			(hot_plug_info->channel << 8) + hot_plug_info->id)) {
4468*4882a593Smuzhiyun 				dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4469*4882a593Smuzhiyun 				    "%s: fw_id=%d exit at line=%d\n",
4470*4882a593Smuzhiyun 				    ioc->name, __func__,
4471*4882a593Smuzhiyun 				    hot_plug_info->id, __LINE__));
4472*4882a593Smuzhiyun 			break;
4473*4882a593Smuzhiyun 		}
4474*4882a593Smuzhiyun 
4475*4882a593Smuzhiyun 		/* If there is no FW B_T mapping for this device then break
4476*4882a593Smuzhiyun 		 * */
4477*4882a593Smuzhiyun 		if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4478*4882a593Smuzhiyun 			|| !(sas_device.flags &
4479*4882a593Smuzhiyun 			MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4480*4882a593Smuzhiyun 			break;
4481*4882a593Smuzhiyun 
4482*4882a593Smuzhiyun 		phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4483*4882a593Smuzhiyun 				sas_device.sas_address);
4484*4882a593Smuzhiyun 		if (!phy_info) {
4485*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4486*4882a593Smuzhiyun 			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
4487*4882a593Smuzhiyun 			 __func__, hot_plug_info->id, __LINE__));
4488*4882a593Smuzhiyun 			break;
4489*4882a593Smuzhiyun 		}
4490*4882a593Smuzhiyun 
4491*4882a593Smuzhiyun 		starget = mptsas_get_starget(phy_info);
4492*4882a593Smuzhiyun 		if (!starget) {
4493*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4494*4882a593Smuzhiyun 			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
4495*4882a593Smuzhiyun 			 __func__, hot_plug_info->id, __LINE__));
4496*4882a593Smuzhiyun 			break;
4497*4882a593Smuzhiyun 		}
4498*4882a593Smuzhiyun 
4499*4882a593Smuzhiyun 		vtarget = starget->hostdata;
4500*4882a593Smuzhiyun 		if (!vtarget) {
4501*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4502*4882a593Smuzhiyun 			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
4503*4882a593Smuzhiyun 			 __func__, hot_plug_info->id, __LINE__));
4504*4882a593Smuzhiyun 			break;
4505*4882a593Smuzhiyun 		}
4506*4882a593Smuzhiyun 
4507*4882a593Smuzhiyun 		if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4508*4882a593Smuzhiyun 			dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4509*4882a593Smuzhiyun 			    "%s: fw_id=%d exit at line=%d\n", ioc->name,
4510*4882a593Smuzhiyun 			 __func__, hot_plug_info->id, __LINE__));
4511*4882a593Smuzhiyun 			break;
4512*4882a593Smuzhiyun 		}
4513*4882a593Smuzhiyun 
4514*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4515*4882a593Smuzhiyun 
4516*4882a593Smuzhiyun 		starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4517*4882a593Smuzhiyun 		    " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4518*4882a593Smuzhiyun 		    ioc->name, hot_plug_info->channel, hot_plug_info->id,
4519*4882a593Smuzhiyun 		    hot_plug_info->phys_disk_num, (unsigned long long)
4520*4882a593Smuzhiyun 		    sas_device.sas_address);
4521*4882a593Smuzhiyun 
4522*4882a593Smuzhiyun 		vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4523*4882a593Smuzhiyun 		vtarget->id = hot_plug_info->id;
4524*4882a593Smuzhiyun 		phy_info->attached.phys_disk_num = ~0;
4525*4882a593Smuzhiyun 		mptsas_reprobe_target(starget, 0);
4526*4882a593Smuzhiyun 		mptsas_add_device_component_by_fw(ioc,
4527*4882a593Smuzhiyun 		    hot_plug_info->channel, hot_plug_info->id);
4528*4882a593Smuzhiyun 		break;
4529*4882a593Smuzhiyun 
4530*4882a593Smuzhiyun 	case MPTSAS_ADD_RAID:
4531*4882a593Smuzhiyun 
4532*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4533*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4534*4882a593Smuzhiyun 		    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4535*4882a593Smuzhiyun 		    hot_plug_info->id);
4536*4882a593Smuzhiyun 		scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4537*4882a593Smuzhiyun 		    hot_plug_info->id, 0);
4538*4882a593Smuzhiyun 		break;
4539*4882a593Smuzhiyun 
4540*4882a593Smuzhiyun 	case MPTSAS_DEL_RAID:
4541*4882a593Smuzhiyun 
4542*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4543*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4544*4882a593Smuzhiyun 		    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4545*4882a593Smuzhiyun 		    hot_plug_info->id);
4546*4882a593Smuzhiyun 		scsi_remove_device(hot_plug_info->sdev);
4547*4882a593Smuzhiyun 		scsi_device_put(hot_plug_info->sdev);
4548*4882a593Smuzhiyun 		break;
4549*4882a593Smuzhiyun 
4550*4882a593Smuzhiyun 	case MPTSAS_ADD_INACTIVE_VOLUME:
4551*4882a593Smuzhiyun 
4552*4882a593Smuzhiyun 		mpt_findImVolumes(ioc);
4553*4882a593Smuzhiyun 		mptsas_adding_inactive_raid_components(ioc,
4554*4882a593Smuzhiyun 		    hot_plug_info->channel, hot_plug_info->id);
4555*4882a593Smuzhiyun 		break;
4556*4882a593Smuzhiyun 
4557*4882a593Smuzhiyun 	default:
4558*4882a593Smuzhiyun 		break;
4559*4882a593Smuzhiyun 	}
4560*4882a593Smuzhiyun 
4561*4882a593Smuzhiyun 	mptsas_free_fw_event(ioc, fw_event);
4562*4882a593Smuzhiyun }
4563*4882a593Smuzhiyun 
4564*4882a593Smuzhiyun static void
mptsas_send_sas_event(struct fw_event_work * fw_event)4565*4882a593Smuzhiyun mptsas_send_sas_event(struct fw_event_work *fw_event)
4566*4882a593Smuzhiyun {
4567*4882a593Smuzhiyun 	MPT_ADAPTER *ioc;
4568*4882a593Smuzhiyun 	struct mptsas_hotplug_event hot_plug_info;
4569*4882a593Smuzhiyun 	EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4570*4882a593Smuzhiyun 	u32 device_info;
4571*4882a593Smuzhiyun 	u64 sas_address;
4572*4882a593Smuzhiyun 
4573*4882a593Smuzhiyun 	ioc = fw_event->ioc;
4574*4882a593Smuzhiyun 	sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4575*4882a593Smuzhiyun 	    fw_event->event_data;
4576*4882a593Smuzhiyun 	device_info = le32_to_cpu(sas_event_data->DeviceInfo);
4577*4882a593Smuzhiyun 
4578*4882a593Smuzhiyun 	if ((device_info &
4579*4882a593Smuzhiyun 		(MPI_SAS_DEVICE_INFO_SSP_TARGET |
4580*4882a593Smuzhiyun 		MPI_SAS_DEVICE_INFO_STP_TARGET |
4581*4882a593Smuzhiyun 		MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4582*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
4583*4882a593Smuzhiyun 		return;
4584*4882a593Smuzhiyun 	}
4585*4882a593Smuzhiyun 
4586*4882a593Smuzhiyun 	if (sas_event_data->ReasonCode ==
4587*4882a593Smuzhiyun 		MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4588*4882a593Smuzhiyun 		mptbase_sas_persist_operation(ioc,
4589*4882a593Smuzhiyun 		MPI_SAS_OP_CLEAR_NOT_PRESENT);
4590*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
4591*4882a593Smuzhiyun 		return;
4592*4882a593Smuzhiyun 	}
4593*4882a593Smuzhiyun 
4594*4882a593Smuzhiyun 	switch (sas_event_data->ReasonCode) {
4595*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
4596*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
4597*4882a593Smuzhiyun 		memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4598*4882a593Smuzhiyun 		hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4599*4882a593Smuzhiyun 		hot_plug_info.channel = sas_event_data->Bus;
4600*4882a593Smuzhiyun 		hot_plug_info.id = sas_event_data->TargetID;
4601*4882a593Smuzhiyun 		hot_plug_info.phy_id = sas_event_data->PhyNum;
4602*4882a593Smuzhiyun 		memcpy(&sas_address, &sas_event_data->SASAddress,
4603*4882a593Smuzhiyun 		    sizeof(u64));
4604*4882a593Smuzhiyun 		hot_plug_info.sas_address = le64_to_cpu(sas_address);
4605*4882a593Smuzhiyun 		hot_plug_info.device_info = device_info;
4606*4882a593Smuzhiyun 		if (sas_event_data->ReasonCode &
4607*4882a593Smuzhiyun 		    MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
4608*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
4609*4882a593Smuzhiyun 		else
4610*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4611*4882a593Smuzhiyun 		mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4612*4882a593Smuzhiyun 		break;
4613*4882a593Smuzhiyun 
4614*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
4615*4882a593Smuzhiyun 		mptbase_sas_persist_operation(ioc,
4616*4882a593Smuzhiyun 		    MPI_SAS_OP_CLEAR_NOT_PRESENT);
4617*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
4618*4882a593Smuzhiyun 		break;
4619*4882a593Smuzhiyun 
4620*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
4621*4882a593Smuzhiyun 	/* TODO */
4622*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
4623*4882a593Smuzhiyun 	/* TODO */
4624*4882a593Smuzhiyun 	default:
4625*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
4626*4882a593Smuzhiyun 		break;
4627*4882a593Smuzhiyun 	}
4628*4882a593Smuzhiyun }
4629*4882a593Smuzhiyun 
4630*4882a593Smuzhiyun static void
mptsas_send_raid_event(struct fw_event_work * fw_event)4631*4882a593Smuzhiyun mptsas_send_raid_event(struct fw_event_work *fw_event)
4632*4882a593Smuzhiyun {
4633*4882a593Smuzhiyun 	MPT_ADAPTER *ioc;
4634*4882a593Smuzhiyun 	EVENT_DATA_RAID *raid_event_data;
4635*4882a593Smuzhiyun 	struct mptsas_hotplug_event hot_plug_info;
4636*4882a593Smuzhiyun 	int status;
4637*4882a593Smuzhiyun 	int state;
4638*4882a593Smuzhiyun 	struct scsi_device *sdev = NULL;
4639*4882a593Smuzhiyun 	VirtDevice *vdevice = NULL;
4640*4882a593Smuzhiyun 	RaidPhysDiskPage0_t phys_disk;
4641*4882a593Smuzhiyun 
4642*4882a593Smuzhiyun 	ioc = fw_event->ioc;
4643*4882a593Smuzhiyun 	raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4644*4882a593Smuzhiyun 	status = le32_to_cpu(raid_event_data->SettingsStatus);
4645*4882a593Smuzhiyun 	state = (status >> 8) & 0xff;
4646*4882a593Smuzhiyun 
4647*4882a593Smuzhiyun 	memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4648*4882a593Smuzhiyun 	hot_plug_info.id = raid_event_data->VolumeID;
4649*4882a593Smuzhiyun 	hot_plug_info.channel = raid_event_data->VolumeBus;
4650*4882a593Smuzhiyun 	hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4651*4882a593Smuzhiyun 
4652*4882a593Smuzhiyun 	if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4653*4882a593Smuzhiyun 	    raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4654*4882a593Smuzhiyun 	    raid_event_data->ReasonCode ==
4655*4882a593Smuzhiyun 	    MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4656*4882a593Smuzhiyun 		sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4657*4882a593Smuzhiyun 		    hot_plug_info.id, 0);
4658*4882a593Smuzhiyun 		hot_plug_info.sdev = sdev;
4659*4882a593Smuzhiyun 		if (sdev)
4660*4882a593Smuzhiyun 			vdevice = sdev->hostdata;
4661*4882a593Smuzhiyun 	}
4662*4882a593Smuzhiyun 
4663*4882a593Smuzhiyun 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4664*4882a593Smuzhiyun 	    "ReasonCode=%02x\n", ioc->name, __func__,
4665*4882a593Smuzhiyun 	    raid_event_data->ReasonCode));
4666*4882a593Smuzhiyun 
4667*4882a593Smuzhiyun 	switch (raid_event_data->ReasonCode) {
4668*4882a593Smuzhiyun 	case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
4669*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
4670*4882a593Smuzhiyun 		break;
4671*4882a593Smuzhiyun 	case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
4672*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
4673*4882a593Smuzhiyun 		break;
4674*4882a593Smuzhiyun 	case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4675*4882a593Smuzhiyun 		switch (state) {
4676*4882a593Smuzhiyun 		case MPI_PD_STATE_ONLINE:
4677*4882a593Smuzhiyun 		case MPI_PD_STATE_NOT_COMPATIBLE:
4678*4882a593Smuzhiyun 			mpt_raid_phys_disk_pg0(ioc,
4679*4882a593Smuzhiyun 			    raid_event_data->PhysDiskNum, &phys_disk);
4680*4882a593Smuzhiyun 			hot_plug_info.id = phys_disk.PhysDiskID;
4681*4882a593Smuzhiyun 			hot_plug_info.channel = phys_disk.PhysDiskBus;
4682*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4683*4882a593Smuzhiyun 			break;
4684*4882a593Smuzhiyun 		case MPI_PD_STATE_FAILED:
4685*4882a593Smuzhiyun 		case MPI_PD_STATE_MISSING:
4686*4882a593Smuzhiyun 		case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4687*4882a593Smuzhiyun 		case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4688*4882a593Smuzhiyun 		case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
4689*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4690*4882a593Smuzhiyun 			break;
4691*4882a593Smuzhiyun 		default:
4692*4882a593Smuzhiyun 			break;
4693*4882a593Smuzhiyun 		}
4694*4882a593Smuzhiyun 		break;
4695*4882a593Smuzhiyun 	case MPI_EVENT_RAID_RC_VOLUME_DELETED:
4696*4882a593Smuzhiyun 		if (!sdev)
4697*4882a593Smuzhiyun 			break;
4698*4882a593Smuzhiyun 		vdevice->vtarget->deleted = 1; /* block IO */
4699*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_DEL_RAID;
4700*4882a593Smuzhiyun 		break;
4701*4882a593Smuzhiyun 	case MPI_EVENT_RAID_RC_VOLUME_CREATED:
4702*4882a593Smuzhiyun 		if (sdev) {
4703*4882a593Smuzhiyun 			scsi_device_put(sdev);
4704*4882a593Smuzhiyun 			break;
4705*4882a593Smuzhiyun 		}
4706*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_ADD_RAID;
4707*4882a593Smuzhiyun 		break;
4708*4882a593Smuzhiyun 	case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
4709*4882a593Smuzhiyun 		if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4710*4882a593Smuzhiyun 			if (!sdev)
4711*4882a593Smuzhiyun 				break;
4712*4882a593Smuzhiyun 			vdevice->vtarget->deleted = 1; /* block IO */
4713*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_DEL_RAID;
4714*4882a593Smuzhiyun 			break;
4715*4882a593Smuzhiyun 		}
4716*4882a593Smuzhiyun 		switch (state) {
4717*4882a593Smuzhiyun 		case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4718*4882a593Smuzhiyun 		case MPI_RAIDVOL0_STATUS_STATE_MISSING:
4719*4882a593Smuzhiyun 			if (!sdev)
4720*4882a593Smuzhiyun 				break;
4721*4882a593Smuzhiyun 			vdevice->vtarget->deleted = 1; /* block IO */
4722*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_DEL_RAID;
4723*4882a593Smuzhiyun 			break;
4724*4882a593Smuzhiyun 		case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4725*4882a593Smuzhiyun 		case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
4726*4882a593Smuzhiyun 			if (sdev) {
4727*4882a593Smuzhiyun 				scsi_device_put(sdev);
4728*4882a593Smuzhiyun 				break;
4729*4882a593Smuzhiyun 			}
4730*4882a593Smuzhiyun 			hot_plug_info.event_type = MPTSAS_ADD_RAID;
4731*4882a593Smuzhiyun 			break;
4732*4882a593Smuzhiyun 		default:
4733*4882a593Smuzhiyun 			break;
4734*4882a593Smuzhiyun 		}
4735*4882a593Smuzhiyun 		break;
4736*4882a593Smuzhiyun 	default:
4737*4882a593Smuzhiyun 		break;
4738*4882a593Smuzhiyun 	}
4739*4882a593Smuzhiyun 
4740*4882a593Smuzhiyun 	if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4741*4882a593Smuzhiyun 		mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4742*4882a593Smuzhiyun 	else
4743*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
4744*4882a593Smuzhiyun }
4745*4882a593Smuzhiyun 
4746*4882a593Smuzhiyun /**
4747*4882a593Smuzhiyun  *	mptsas_issue_tm - send mptsas internal tm request
4748*4882a593Smuzhiyun  *	@ioc: Pointer to MPT_ADAPTER structure
4749*4882a593Smuzhiyun  *	@type: Task Management type
4750*4882a593Smuzhiyun  *	@channel: channel number for task management
4751*4882a593Smuzhiyun  *	@id: Logical Target ID for reset (if appropriate)
4752*4882a593Smuzhiyun  *	@lun: Logical unit for reset (if appropriate)
4753*4882a593Smuzhiyun  *	@task_context: Context for the task to be aborted
4754*4882a593Smuzhiyun  *	@timeout: timeout for task management control
4755*4882a593Smuzhiyun  *
4756*4882a593Smuzhiyun  *	return 0 on success and -1 on failure:
4757*4882a593Smuzhiyun  *
4758*4882a593Smuzhiyun  */
4759*4882a593Smuzhiyun static int
mptsas_issue_tm(MPT_ADAPTER * ioc,u8 type,u8 channel,u8 id,u64 lun,int task_context,ulong timeout,u8 * issue_reset)4760*4882a593Smuzhiyun mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4761*4882a593Smuzhiyun 	int task_context, ulong timeout, u8 *issue_reset)
4762*4882a593Smuzhiyun {
4763*4882a593Smuzhiyun 	MPT_FRAME_HDR	*mf;
4764*4882a593Smuzhiyun 	SCSITaskMgmt_t	*pScsiTm;
4765*4882a593Smuzhiyun 	int		 retval;
4766*4882a593Smuzhiyun 	unsigned long	 timeleft;
4767*4882a593Smuzhiyun 
4768*4882a593Smuzhiyun 	*issue_reset = 0;
4769*4882a593Smuzhiyun 	mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4770*4882a593Smuzhiyun 	if (mf == NULL) {
4771*4882a593Smuzhiyun 		retval = -1; /* return failure */
4772*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4773*4882a593Smuzhiyun 		    "msg frames!!\n", ioc->name));
4774*4882a593Smuzhiyun 		goto out;
4775*4882a593Smuzhiyun 	}
4776*4882a593Smuzhiyun 
4777*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4778*4882a593Smuzhiyun 	    "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4779*4882a593Smuzhiyun 	    "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4780*4882a593Smuzhiyun 	     type, timeout, channel, id, (unsigned long long)lun,
4781*4882a593Smuzhiyun 	     task_context));
4782*4882a593Smuzhiyun 
4783*4882a593Smuzhiyun 	pScsiTm = (SCSITaskMgmt_t *) mf;
4784*4882a593Smuzhiyun 	memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4785*4882a593Smuzhiyun 	pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4786*4882a593Smuzhiyun 	pScsiTm->TaskType = type;
4787*4882a593Smuzhiyun 	pScsiTm->MsgFlags = 0;
4788*4882a593Smuzhiyun 	pScsiTm->TargetID = id;
4789*4882a593Smuzhiyun 	pScsiTm->Bus = channel;
4790*4882a593Smuzhiyun 	pScsiTm->ChainOffset = 0;
4791*4882a593Smuzhiyun 	pScsiTm->Reserved = 0;
4792*4882a593Smuzhiyun 	pScsiTm->Reserved1 = 0;
4793*4882a593Smuzhiyun 	pScsiTm->TaskMsgContext = task_context;
4794*4882a593Smuzhiyun 	int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4795*4882a593Smuzhiyun 
4796*4882a593Smuzhiyun 	INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4797*4882a593Smuzhiyun 	CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4798*4882a593Smuzhiyun 	retval = 0;
4799*4882a593Smuzhiyun 	mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4800*4882a593Smuzhiyun 
4801*4882a593Smuzhiyun 	/* Now wait for the command to complete */
4802*4882a593Smuzhiyun 	timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4803*4882a593Smuzhiyun 	    timeout*HZ);
4804*4882a593Smuzhiyun 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4805*4882a593Smuzhiyun 		retval = -1; /* return failure */
4806*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4807*4882a593Smuzhiyun 		    "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4808*4882a593Smuzhiyun 		mpt_free_msg_frame(ioc, mf);
4809*4882a593Smuzhiyun 		if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4810*4882a593Smuzhiyun 			goto out;
4811*4882a593Smuzhiyun 		*issue_reset = 1;
4812*4882a593Smuzhiyun 		goto out;
4813*4882a593Smuzhiyun 	}
4814*4882a593Smuzhiyun 
4815*4882a593Smuzhiyun 	if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4816*4882a593Smuzhiyun 		retval = -1; /* return failure */
4817*4882a593Smuzhiyun 		dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4818*4882a593Smuzhiyun 		    "TaskMgmt request: failed with no reply\n", ioc->name));
4819*4882a593Smuzhiyun 		goto out;
4820*4882a593Smuzhiyun 	}
4821*4882a593Smuzhiyun 
4822*4882a593Smuzhiyun  out:
4823*4882a593Smuzhiyun 	CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4824*4882a593Smuzhiyun 	return retval;
4825*4882a593Smuzhiyun }
4826*4882a593Smuzhiyun 
4827*4882a593Smuzhiyun /**
4828*4882a593Smuzhiyun  *	mptsas_broadcast_primitive_work - Handle broadcast primitives
4829*4882a593Smuzhiyun  *	@work: work queue payload containing info describing the event
4830*4882a593Smuzhiyun  *
4831*4882a593Smuzhiyun  *	this will be handled in workqueue context.
4832*4882a593Smuzhiyun  */
4833*4882a593Smuzhiyun static void
mptsas_broadcast_primitive_work(struct fw_event_work * fw_event)4834*4882a593Smuzhiyun mptsas_broadcast_primitive_work(struct fw_event_work *fw_event)
4835*4882a593Smuzhiyun {
4836*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = fw_event->ioc;
4837*4882a593Smuzhiyun 	MPT_FRAME_HDR	*mf;
4838*4882a593Smuzhiyun 	VirtDevice	*vdevice;
4839*4882a593Smuzhiyun 	int			ii;
4840*4882a593Smuzhiyun 	struct scsi_cmnd	*sc;
4841*4882a593Smuzhiyun 	SCSITaskMgmtReply_t	*pScsiTmReply;
4842*4882a593Smuzhiyun 	u8			issue_reset;
4843*4882a593Smuzhiyun 	int			task_context;
4844*4882a593Smuzhiyun 	u8			channel, id;
4845*4882a593Smuzhiyun 	int			 lun;
4846*4882a593Smuzhiyun 	u32			 termination_count;
4847*4882a593Smuzhiyun 	u32			 query_count;
4848*4882a593Smuzhiyun 
4849*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4850*4882a593Smuzhiyun 	    "%s - enter\n", ioc->name, __func__));
4851*4882a593Smuzhiyun 
4852*4882a593Smuzhiyun 	mutex_lock(&ioc->taskmgmt_cmds.mutex);
4853*4882a593Smuzhiyun 	if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4854*4882a593Smuzhiyun 		mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4855*4882a593Smuzhiyun 		mptsas_requeue_fw_event(ioc, fw_event, 1000);
4856*4882a593Smuzhiyun 		return;
4857*4882a593Smuzhiyun 	}
4858*4882a593Smuzhiyun 
4859*4882a593Smuzhiyun 	issue_reset = 0;
4860*4882a593Smuzhiyun 	termination_count = 0;
4861*4882a593Smuzhiyun 	query_count = 0;
4862*4882a593Smuzhiyun 	mpt_findImVolumes(ioc);
4863*4882a593Smuzhiyun 	pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4864*4882a593Smuzhiyun 
4865*4882a593Smuzhiyun 	for (ii = 0; ii < ioc->req_depth; ii++) {
4866*4882a593Smuzhiyun 		if (ioc->fw_events_off)
4867*4882a593Smuzhiyun 			goto out;
4868*4882a593Smuzhiyun 		sc = mptscsih_get_scsi_lookup(ioc, ii);
4869*4882a593Smuzhiyun 		if (!sc)
4870*4882a593Smuzhiyun 			continue;
4871*4882a593Smuzhiyun 		mf = MPT_INDEX_2_MFPTR(ioc, ii);
4872*4882a593Smuzhiyun 		if (!mf)
4873*4882a593Smuzhiyun 			continue;
4874*4882a593Smuzhiyun 		task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4875*4882a593Smuzhiyun 		vdevice = sc->device->hostdata;
4876*4882a593Smuzhiyun 		if (!vdevice || !vdevice->vtarget)
4877*4882a593Smuzhiyun 			continue;
4878*4882a593Smuzhiyun 		if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4879*4882a593Smuzhiyun 			continue; /* skip hidden raid components */
4880*4882a593Smuzhiyun 		if (vdevice->vtarget->raidVolume)
4881*4882a593Smuzhiyun 			continue; /* skip hidden raid components */
4882*4882a593Smuzhiyun 		channel = vdevice->vtarget->channel;
4883*4882a593Smuzhiyun 		id = vdevice->vtarget->id;
4884*4882a593Smuzhiyun 		lun = vdevice->lun;
4885*4882a593Smuzhiyun 		if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4886*4882a593Smuzhiyun 		    channel, id, (u64)lun, task_context, 30, &issue_reset))
4887*4882a593Smuzhiyun 			goto out;
4888*4882a593Smuzhiyun 		query_count++;
4889*4882a593Smuzhiyun 		termination_count +=
4890*4882a593Smuzhiyun 		    le32_to_cpu(pScsiTmReply->TerminationCount);
4891*4882a593Smuzhiyun 		if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4892*4882a593Smuzhiyun 		    (pScsiTmReply->ResponseCode ==
4893*4882a593Smuzhiyun 		    MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4894*4882a593Smuzhiyun 		    pScsiTmReply->ResponseCode ==
4895*4882a593Smuzhiyun 		    MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4896*4882a593Smuzhiyun 			continue;
4897*4882a593Smuzhiyun 		if (mptsas_issue_tm(ioc,
4898*4882a593Smuzhiyun 		    MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4899*4882a593Smuzhiyun 		    channel, id, (u64)lun, 0, 30, &issue_reset))
4900*4882a593Smuzhiyun 			goto out;
4901*4882a593Smuzhiyun 		termination_count +=
4902*4882a593Smuzhiyun 		    le32_to_cpu(pScsiTmReply->TerminationCount);
4903*4882a593Smuzhiyun 	}
4904*4882a593Smuzhiyun 
4905*4882a593Smuzhiyun  out:
4906*4882a593Smuzhiyun 	dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4907*4882a593Smuzhiyun 	    "%s - exit, query_count = %d termination_count = %d\n",
4908*4882a593Smuzhiyun 	    ioc->name, __func__, query_count, termination_count));
4909*4882a593Smuzhiyun 
4910*4882a593Smuzhiyun 	ioc->broadcast_aen_busy = 0;
4911*4882a593Smuzhiyun 	mpt_clear_taskmgmt_in_progress_flag(ioc);
4912*4882a593Smuzhiyun 	mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4913*4882a593Smuzhiyun 
4914*4882a593Smuzhiyun 	if (issue_reset) {
4915*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT
4916*4882a593Smuzhiyun 		       "Issuing Reset from %s!! doorbell=0x%08x\n",
4917*4882a593Smuzhiyun 		       ioc->name, __func__, mpt_GetIocState(ioc, 0));
4918*4882a593Smuzhiyun 		mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
4919*4882a593Smuzhiyun 	}
4920*4882a593Smuzhiyun 	mptsas_free_fw_event(ioc, fw_event);
4921*4882a593Smuzhiyun }
4922*4882a593Smuzhiyun 
4923*4882a593Smuzhiyun /*
4924*4882a593Smuzhiyun  * mptsas_send_ir2_event - handle exposing hidden disk when
4925*4882a593Smuzhiyun  * an inactive raid volume is added
4926*4882a593Smuzhiyun  *
4927*4882a593Smuzhiyun  * @ioc: Pointer to MPT_ADAPTER structure
4928*4882a593Smuzhiyun  * @ir2_data
4929*4882a593Smuzhiyun  *
4930*4882a593Smuzhiyun  */
4931*4882a593Smuzhiyun static void
mptsas_send_ir2_event(struct fw_event_work * fw_event)4932*4882a593Smuzhiyun mptsas_send_ir2_event(struct fw_event_work *fw_event)
4933*4882a593Smuzhiyun {
4934*4882a593Smuzhiyun 	MPT_ADAPTER	*ioc;
4935*4882a593Smuzhiyun 	struct mptsas_hotplug_event hot_plug_info;
4936*4882a593Smuzhiyun 	MPI_EVENT_DATA_IR2	*ir2_data;
4937*4882a593Smuzhiyun 	u8 reasonCode;
4938*4882a593Smuzhiyun 	RaidPhysDiskPage0_t phys_disk;
4939*4882a593Smuzhiyun 
4940*4882a593Smuzhiyun 	ioc = fw_event->ioc;
4941*4882a593Smuzhiyun 	ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4942*4882a593Smuzhiyun 	reasonCode = ir2_data->ReasonCode;
4943*4882a593Smuzhiyun 
4944*4882a593Smuzhiyun 	devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4945*4882a593Smuzhiyun 	    "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4946*4882a593Smuzhiyun 
4947*4882a593Smuzhiyun 	memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4948*4882a593Smuzhiyun 	hot_plug_info.id = ir2_data->TargetID;
4949*4882a593Smuzhiyun 	hot_plug_info.channel = ir2_data->Bus;
4950*4882a593Smuzhiyun 	switch (reasonCode) {
4951*4882a593Smuzhiyun 	case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4952*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4953*4882a593Smuzhiyun 		break;
4954*4882a593Smuzhiyun 	case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4955*4882a593Smuzhiyun 		hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4956*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4957*4882a593Smuzhiyun 		break;
4958*4882a593Smuzhiyun 	case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4959*4882a593Smuzhiyun 		hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4960*4882a593Smuzhiyun 		mpt_raid_phys_disk_pg0(ioc,
4961*4882a593Smuzhiyun 		    ir2_data->PhysDiskNum, &phys_disk);
4962*4882a593Smuzhiyun 		hot_plug_info.id = phys_disk.PhysDiskID;
4963*4882a593Smuzhiyun 		hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4964*4882a593Smuzhiyun 		break;
4965*4882a593Smuzhiyun 	default:
4966*4882a593Smuzhiyun 		mptsas_free_fw_event(ioc, fw_event);
4967*4882a593Smuzhiyun 		return;
4968*4882a593Smuzhiyun 	}
4969*4882a593Smuzhiyun 	mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4970*4882a593Smuzhiyun }
4971*4882a593Smuzhiyun 
4972*4882a593Smuzhiyun static int
mptsas_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * reply)4973*4882a593Smuzhiyun mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4974*4882a593Smuzhiyun {
4975*4882a593Smuzhiyun 	u32 event = le32_to_cpu(reply->Event);
4976*4882a593Smuzhiyun 	int event_data_sz;
4977*4882a593Smuzhiyun 	struct fw_event_work *fw_event;
4978*4882a593Smuzhiyun 	unsigned long delay;
4979*4882a593Smuzhiyun 
4980*4882a593Smuzhiyun 	if (ioc->bus_type != SAS)
4981*4882a593Smuzhiyun 		return 0;
4982*4882a593Smuzhiyun 
4983*4882a593Smuzhiyun 	/* events turned off due to host reset or driver unloading */
4984*4882a593Smuzhiyun 	if (ioc->fw_events_off)
4985*4882a593Smuzhiyun 		return 0;
4986*4882a593Smuzhiyun 
4987*4882a593Smuzhiyun 	delay = msecs_to_jiffies(1);
4988*4882a593Smuzhiyun 	switch (event) {
4989*4882a593Smuzhiyun 	case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4990*4882a593Smuzhiyun 	{
4991*4882a593Smuzhiyun 		EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4992*4882a593Smuzhiyun 		    (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4993*4882a593Smuzhiyun 		if (broadcast_event_data->Primitive !=
4994*4882a593Smuzhiyun 		    MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4995*4882a593Smuzhiyun 			return 0;
4996*4882a593Smuzhiyun 		if (ioc->broadcast_aen_busy)
4997*4882a593Smuzhiyun 			return 0;
4998*4882a593Smuzhiyun 		ioc->broadcast_aen_busy = 1;
4999*4882a593Smuzhiyun 		break;
5000*4882a593Smuzhiyun 	}
5001*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
5002*4882a593Smuzhiyun 	{
5003*4882a593Smuzhiyun 		EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
5004*4882a593Smuzhiyun 		    (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
5005*4882a593Smuzhiyun 		u16	ioc_stat;
5006*4882a593Smuzhiyun 		ioc_stat = le16_to_cpu(reply->IOCStatus);
5007*4882a593Smuzhiyun 
5008*4882a593Smuzhiyun 		if (sas_event_data->ReasonCode ==
5009*4882a593Smuzhiyun 		    MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
5010*4882a593Smuzhiyun 			mptsas_target_reset_queue(ioc, sas_event_data);
5011*4882a593Smuzhiyun 			return 0;
5012*4882a593Smuzhiyun 		}
5013*4882a593Smuzhiyun 		if (sas_event_data->ReasonCode ==
5014*4882a593Smuzhiyun 			MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
5015*4882a593Smuzhiyun 			ioc->device_missing_delay &&
5016*4882a593Smuzhiyun 			(ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
5017*4882a593Smuzhiyun 			VirtTarget *vtarget = NULL;
5018*4882a593Smuzhiyun 			u8		id, channel;
5019*4882a593Smuzhiyun 
5020*4882a593Smuzhiyun 			id = sas_event_data->TargetID;
5021*4882a593Smuzhiyun 			channel = sas_event_data->Bus;
5022*4882a593Smuzhiyun 
5023*4882a593Smuzhiyun 			vtarget = mptsas_find_vtarget(ioc, channel, id);
5024*4882a593Smuzhiyun 			if (vtarget) {
5025*4882a593Smuzhiyun 				devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5026*4882a593Smuzhiyun 				    "LogInfo (0x%x) available for "
5027*4882a593Smuzhiyun 				   "INTERNAL_DEVICE_RESET"
5028*4882a593Smuzhiyun 				   "fw_id %d fw_channel %d\n", ioc->name,
5029*4882a593Smuzhiyun 				   le32_to_cpu(reply->IOCLogInfo),
5030*4882a593Smuzhiyun 				   id, channel));
5031*4882a593Smuzhiyun 				if (vtarget->raidVolume) {
5032*4882a593Smuzhiyun 					devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5033*4882a593Smuzhiyun 					"Skipping Raid Volume for inDMD\n",
5034*4882a593Smuzhiyun 					ioc->name));
5035*4882a593Smuzhiyun 				} else {
5036*4882a593Smuzhiyun 					devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5037*4882a593Smuzhiyun 					"Setting device flag inDMD\n",
5038*4882a593Smuzhiyun 					ioc->name));
5039*4882a593Smuzhiyun 					vtarget->inDMD = 1;
5040*4882a593Smuzhiyun 				}
5041*4882a593Smuzhiyun 
5042*4882a593Smuzhiyun 			}
5043*4882a593Smuzhiyun 
5044*4882a593Smuzhiyun 		}
5045*4882a593Smuzhiyun 
5046*4882a593Smuzhiyun 		break;
5047*4882a593Smuzhiyun 	}
5048*4882a593Smuzhiyun 	case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
5049*4882a593Smuzhiyun 	{
5050*4882a593Smuzhiyun 		MpiEventDataSasExpanderStatusChange_t *expander_data =
5051*4882a593Smuzhiyun 		    (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
5052*4882a593Smuzhiyun 
5053*4882a593Smuzhiyun 		if (ioc->old_sas_discovery_protocal)
5054*4882a593Smuzhiyun 			return 0;
5055*4882a593Smuzhiyun 
5056*4882a593Smuzhiyun 		if (expander_data->ReasonCode ==
5057*4882a593Smuzhiyun 		    MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
5058*4882a593Smuzhiyun 		    ioc->device_missing_delay)
5059*4882a593Smuzhiyun 			delay = HZ * ioc->device_missing_delay;
5060*4882a593Smuzhiyun 		break;
5061*4882a593Smuzhiyun 	}
5062*4882a593Smuzhiyun 	case MPI_EVENT_SAS_DISCOVERY:
5063*4882a593Smuzhiyun 	{
5064*4882a593Smuzhiyun 		u32 discovery_status;
5065*4882a593Smuzhiyun 		EventDataSasDiscovery_t *discovery_data =
5066*4882a593Smuzhiyun 		    (EventDataSasDiscovery_t *)reply->Data;
5067*4882a593Smuzhiyun 
5068*4882a593Smuzhiyun 		discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
5069*4882a593Smuzhiyun 		ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
5070*4882a593Smuzhiyun 		if (ioc->old_sas_discovery_protocal && !discovery_status)
5071*4882a593Smuzhiyun 			mptsas_queue_rescan(ioc);
5072*4882a593Smuzhiyun 		return 0;
5073*4882a593Smuzhiyun 	}
5074*4882a593Smuzhiyun 	case MPI_EVENT_INTEGRATED_RAID:
5075*4882a593Smuzhiyun 	case MPI_EVENT_PERSISTENT_TABLE_FULL:
5076*4882a593Smuzhiyun 	case MPI_EVENT_IR2:
5077*4882a593Smuzhiyun 	case MPI_EVENT_SAS_PHY_LINK_STATUS:
5078*4882a593Smuzhiyun 	case MPI_EVENT_QUEUE_FULL:
5079*4882a593Smuzhiyun 		break;
5080*4882a593Smuzhiyun 	default:
5081*4882a593Smuzhiyun 		return 0;
5082*4882a593Smuzhiyun 	}
5083*4882a593Smuzhiyun 
5084*4882a593Smuzhiyun 	event_data_sz = ((reply->MsgLength * 4) -
5085*4882a593Smuzhiyun 	    offsetof(EventNotificationReply_t, Data));
5086*4882a593Smuzhiyun 	fw_event = kzalloc(sizeof(*fw_event) + event_data_sz, GFP_ATOMIC);
5087*4882a593Smuzhiyun 	if (!fw_event) {
5088*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
5089*4882a593Smuzhiyun 		 __func__, __LINE__);
5090*4882a593Smuzhiyun 		return 0;
5091*4882a593Smuzhiyun 	}
5092*4882a593Smuzhiyun 	memcpy(fw_event->event_data, reply->Data, event_data_sz);
5093*4882a593Smuzhiyun 	fw_event->event = event;
5094*4882a593Smuzhiyun 	fw_event->ioc = ioc;
5095*4882a593Smuzhiyun 	mptsas_add_fw_event(ioc, fw_event, delay);
5096*4882a593Smuzhiyun 	return 0;
5097*4882a593Smuzhiyun }
5098*4882a593Smuzhiyun 
5099*4882a593Smuzhiyun /* Delete a volume when no longer listed in ioc pg2
5100*4882a593Smuzhiyun  */
mptsas_volume_delete(MPT_ADAPTER * ioc,u8 id)5101*4882a593Smuzhiyun static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
5102*4882a593Smuzhiyun {
5103*4882a593Smuzhiyun 	struct scsi_device *sdev;
5104*4882a593Smuzhiyun 	int i;
5105*4882a593Smuzhiyun 
5106*4882a593Smuzhiyun 	sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
5107*4882a593Smuzhiyun 	if (!sdev)
5108*4882a593Smuzhiyun 		return;
5109*4882a593Smuzhiyun 	if (!ioc->raid_data.pIocPg2)
5110*4882a593Smuzhiyun 		goto out;
5111*4882a593Smuzhiyun 	if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
5112*4882a593Smuzhiyun 		goto out;
5113*4882a593Smuzhiyun 	for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
5114*4882a593Smuzhiyun 		if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
5115*4882a593Smuzhiyun 			goto release_sdev;
5116*4882a593Smuzhiyun  out:
5117*4882a593Smuzhiyun 	printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
5118*4882a593Smuzhiyun 	    "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
5119*4882a593Smuzhiyun 	scsi_remove_device(sdev);
5120*4882a593Smuzhiyun  release_sdev:
5121*4882a593Smuzhiyun 	scsi_device_put(sdev);
5122*4882a593Smuzhiyun }
5123*4882a593Smuzhiyun 
5124*4882a593Smuzhiyun static int
mptsas_probe(struct pci_dev * pdev,const struct pci_device_id * id)5125*4882a593Smuzhiyun mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5126*4882a593Smuzhiyun {
5127*4882a593Smuzhiyun 	struct Scsi_Host	*sh;
5128*4882a593Smuzhiyun 	MPT_SCSI_HOST		*hd;
5129*4882a593Smuzhiyun 	MPT_ADAPTER 		*ioc;
5130*4882a593Smuzhiyun 	unsigned long		 flags;
5131*4882a593Smuzhiyun 	int			 ii;
5132*4882a593Smuzhiyun 	int			 numSGE = 0;
5133*4882a593Smuzhiyun 	int			 scale;
5134*4882a593Smuzhiyun 	int			 ioc_cap;
5135*4882a593Smuzhiyun 	int			error=0;
5136*4882a593Smuzhiyun 	int			r;
5137*4882a593Smuzhiyun 
5138*4882a593Smuzhiyun 	r = mpt_attach(pdev,id);
5139*4882a593Smuzhiyun 	if (r)
5140*4882a593Smuzhiyun 		return r;
5141*4882a593Smuzhiyun 
5142*4882a593Smuzhiyun 	ioc = pci_get_drvdata(pdev);
5143*4882a593Smuzhiyun 	mptsas_fw_event_off(ioc);
5144*4882a593Smuzhiyun 	ioc->DoneCtx = mptsasDoneCtx;
5145*4882a593Smuzhiyun 	ioc->TaskCtx = mptsasTaskCtx;
5146*4882a593Smuzhiyun 	ioc->InternalCtx = mptsasInternalCtx;
5147*4882a593Smuzhiyun 	ioc->schedule_target_reset = &mptsas_schedule_target_reset;
5148*4882a593Smuzhiyun 	ioc->schedule_dead_ioc_flush_running_cmds =
5149*4882a593Smuzhiyun 				&mptscsih_flush_running_cmds;
5150*4882a593Smuzhiyun 	/*  Added sanity check on readiness of the MPT adapter.
5151*4882a593Smuzhiyun 	 */
5152*4882a593Smuzhiyun 	if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
5153*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT
5154*4882a593Smuzhiyun 		  "Skipping because it's not operational!\n",
5155*4882a593Smuzhiyun 		  ioc->name);
5156*4882a593Smuzhiyun 		error = -ENODEV;
5157*4882a593Smuzhiyun 		goto out_mptsas_probe;
5158*4882a593Smuzhiyun 	}
5159*4882a593Smuzhiyun 
5160*4882a593Smuzhiyun 	if (!ioc->active) {
5161*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
5162*4882a593Smuzhiyun 		  ioc->name);
5163*4882a593Smuzhiyun 		error = -ENODEV;
5164*4882a593Smuzhiyun 		goto out_mptsas_probe;
5165*4882a593Smuzhiyun 	}
5166*4882a593Smuzhiyun 
5167*4882a593Smuzhiyun 	/*  Sanity check - ensure at least 1 port is INITIATOR capable
5168*4882a593Smuzhiyun 	 */
5169*4882a593Smuzhiyun 	ioc_cap = 0;
5170*4882a593Smuzhiyun 	for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
5171*4882a593Smuzhiyun 		if (ioc->pfacts[ii].ProtocolFlags &
5172*4882a593Smuzhiyun 				MPI_PORTFACTS_PROTOCOL_INITIATOR)
5173*4882a593Smuzhiyun 			ioc_cap++;
5174*4882a593Smuzhiyun 	}
5175*4882a593Smuzhiyun 
5176*4882a593Smuzhiyun 	if (!ioc_cap) {
5177*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT
5178*4882a593Smuzhiyun 			"Skipping ioc=%p because SCSI Initiator mode "
5179*4882a593Smuzhiyun 			"is NOT enabled!\n", ioc->name, ioc);
5180*4882a593Smuzhiyun 		return 0;
5181*4882a593Smuzhiyun 	}
5182*4882a593Smuzhiyun 
5183*4882a593Smuzhiyun 	sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
5184*4882a593Smuzhiyun 	if (!sh) {
5185*4882a593Smuzhiyun 		printk(MYIOC_s_WARN_FMT
5186*4882a593Smuzhiyun 			"Unable to register controller with SCSI subsystem\n",
5187*4882a593Smuzhiyun 			ioc->name);
5188*4882a593Smuzhiyun 		error = -1;
5189*4882a593Smuzhiyun 		goto out_mptsas_probe;
5190*4882a593Smuzhiyun         }
5191*4882a593Smuzhiyun 
5192*4882a593Smuzhiyun 	spin_lock_irqsave(&ioc->FreeQlock, flags);
5193*4882a593Smuzhiyun 
5194*4882a593Smuzhiyun 	/* Attach the SCSI Host to the IOC structure
5195*4882a593Smuzhiyun 	 */
5196*4882a593Smuzhiyun 	ioc->sh = sh;
5197*4882a593Smuzhiyun 
5198*4882a593Smuzhiyun 	sh->io_port = 0;
5199*4882a593Smuzhiyun 	sh->n_io_port = 0;
5200*4882a593Smuzhiyun 	sh->irq = 0;
5201*4882a593Smuzhiyun 
5202*4882a593Smuzhiyun 	/* set 16 byte cdb's */
5203*4882a593Smuzhiyun 	sh->max_cmd_len = 16;
5204*4882a593Smuzhiyun 	sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5205*4882a593Smuzhiyun 	sh->max_id = -1;
5206*4882a593Smuzhiyun 	sh->max_lun = max_lun;
5207*4882a593Smuzhiyun 	sh->transportt = mptsas_transport_template;
5208*4882a593Smuzhiyun 
5209*4882a593Smuzhiyun 	/* Required entry.
5210*4882a593Smuzhiyun 	 */
5211*4882a593Smuzhiyun 	sh->unique_id = ioc->id;
5212*4882a593Smuzhiyun 
5213*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ioc->sas_topology);
5214*4882a593Smuzhiyun 	mutex_init(&ioc->sas_topology_mutex);
5215*4882a593Smuzhiyun 	mutex_init(&ioc->sas_discovery_mutex);
5216*4882a593Smuzhiyun 	mutex_init(&ioc->sas_mgmt.mutex);
5217*4882a593Smuzhiyun 	init_completion(&ioc->sas_mgmt.done);
5218*4882a593Smuzhiyun 
5219*4882a593Smuzhiyun 	/* Verify that we won't exceed the maximum
5220*4882a593Smuzhiyun 	 * number of chain buffers
5221*4882a593Smuzhiyun 	 * We can optimize:  ZZ = req_sz/sizeof(SGE)
5222*4882a593Smuzhiyun 	 * For 32bit SGE's:
5223*4882a593Smuzhiyun 	 *  numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5224*4882a593Smuzhiyun 	 *               + (req_sz - 64)/sizeof(SGE)
5225*4882a593Smuzhiyun 	 * A slightly different algorithm is required for
5226*4882a593Smuzhiyun 	 * 64bit SGEs.
5227*4882a593Smuzhiyun 	 */
5228*4882a593Smuzhiyun 	scale = ioc->req_sz/ioc->SGE_size;
5229*4882a593Smuzhiyun 	if (ioc->sg_addr_size == sizeof(u64)) {
5230*4882a593Smuzhiyun 		numSGE = (scale - 1) *
5231*4882a593Smuzhiyun 		  (ioc->facts.MaxChainDepth-1) + scale +
5232*4882a593Smuzhiyun 		  (ioc->req_sz - 60) / ioc->SGE_size;
5233*4882a593Smuzhiyun 	} else {
5234*4882a593Smuzhiyun 		numSGE = 1 + (scale - 1) *
5235*4882a593Smuzhiyun 		  (ioc->facts.MaxChainDepth-1) + scale +
5236*4882a593Smuzhiyun 		  (ioc->req_sz - 64) / ioc->SGE_size;
5237*4882a593Smuzhiyun 	}
5238*4882a593Smuzhiyun 
5239*4882a593Smuzhiyun 	if (numSGE < sh->sg_tablesize) {
5240*4882a593Smuzhiyun 		/* Reset this value */
5241*4882a593Smuzhiyun 		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5242*4882a593Smuzhiyun 		  "Resetting sg_tablesize to %d from %d\n",
5243*4882a593Smuzhiyun 		  ioc->name, numSGE, sh->sg_tablesize));
5244*4882a593Smuzhiyun 		sh->sg_tablesize = numSGE;
5245*4882a593Smuzhiyun 	}
5246*4882a593Smuzhiyun 
5247*4882a593Smuzhiyun 	if (mpt_loadtime_max_sectors) {
5248*4882a593Smuzhiyun 		if (mpt_loadtime_max_sectors < 64 ||
5249*4882a593Smuzhiyun 			mpt_loadtime_max_sectors > 8192) {
5250*4882a593Smuzhiyun 			printk(MYIOC_s_INFO_FMT "Invalid value passed for"
5251*4882a593Smuzhiyun 				"mpt_loadtime_max_sectors %d."
5252*4882a593Smuzhiyun 				"Range from 64 to 8192\n", ioc->name,
5253*4882a593Smuzhiyun 				mpt_loadtime_max_sectors);
5254*4882a593Smuzhiyun 		}
5255*4882a593Smuzhiyun 		mpt_loadtime_max_sectors &=  0xFFFFFFFE;
5256*4882a593Smuzhiyun 		dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5257*4882a593Smuzhiyun 			"Resetting max sector to %d from %d\n",
5258*4882a593Smuzhiyun 		  ioc->name, mpt_loadtime_max_sectors, sh->max_sectors));
5259*4882a593Smuzhiyun 		sh->max_sectors = mpt_loadtime_max_sectors;
5260*4882a593Smuzhiyun 	}
5261*4882a593Smuzhiyun 
5262*4882a593Smuzhiyun 	hd = shost_priv(sh);
5263*4882a593Smuzhiyun 	hd->ioc = ioc;
5264*4882a593Smuzhiyun 
5265*4882a593Smuzhiyun 	/* SCSI needs scsi_cmnd lookup table!
5266*4882a593Smuzhiyun 	 * (with size equal to req_depth*PtrSz!)
5267*4882a593Smuzhiyun 	 */
5268*4882a593Smuzhiyun 	ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5269*4882a593Smuzhiyun 	if (!ioc->ScsiLookup) {
5270*4882a593Smuzhiyun 		error = -ENOMEM;
5271*4882a593Smuzhiyun 		spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5272*4882a593Smuzhiyun 		goto out_mptsas_probe;
5273*4882a593Smuzhiyun 	}
5274*4882a593Smuzhiyun 	spin_lock_init(&ioc->scsi_lookup_lock);
5275*4882a593Smuzhiyun 
5276*4882a593Smuzhiyun 	dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
5277*4882a593Smuzhiyun 		 ioc->name, ioc->ScsiLookup));
5278*4882a593Smuzhiyun 
5279*4882a593Smuzhiyun 	ioc->sas_data.ptClear = mpt_pt_clear;
5280*4882a593Smuzhiyun 
5281*4882a593Smuzhiyun 	hd->last_queue_full = 0;
5282*4882a593Smuzhiyun 	INIT_LIST_HEAD(&hd->target_reset_list);
5283*4882a593Smuzhiyun 	INIT_LIST_HEAD(&ioc->sas_device_info_list);
5284*4882a593Smuzhiyun 	mutex_init(&ioc->sas_device_info_mutex);
5285*4882a593Smuzhiyun 
5286*4882a593Smuzhiyun 	spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5287*4882a593Smuzhiyun 
5288*4882a593Smuzhiyun 	if (ioc->sas_data.ptClear==1) {
5289*4882a593Smuzhiyun 		mptbase_sas_persist_operation(
5290*4882a593Smuzhiyun 		    ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5291*4882a593Smuzhiyun 	}
5292*4882a593Smuzhiyun 
5293*4882a593Smuzhiyun 	error = scsi_add_host(sh, &ioc->pcidev->dev);
5294*4882a593Smuzhiyun 	if (error) {
5295*4882a593Smuzhiyun 		dprintk(ioc, printk(MYIOC_s_ERR_FMT
5296*4882a593Smuzhiyun 		  "scsi_add_host failed\n", ioc->name));
5297*4882a593Smuzhiyun 		goto out_mptsas_probe;
5298*4882a593Smuzhiyun 	}
5299*4882a593Smuzhiyun 
5300*4882a593Smuzhiyun 	/* older firmware doesn't support expander events */
5301*4882a593Smuzhiyun 	if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5302*4882a593Smuzhiyun 		ioc->old_sas_discovery_protocal = 1;
5303*4882a593Smuzhiyun 	mptsas_scan_sas_topology(ioc);
5304*4882a593Smuzhiyun 	mptsas_fw_event_on(ioc);
5305*4882a593Smuzhiyun 	return 0;
5306*4882a593Smuzhiyun 
5307*4882a593Smuzhiyun  out_mptsas_probe:
5308*4882a593Smuzhiyun 
5309*4882a593Smuzhiyun 	mptscsih_remove(pdev);
5310*4882a593Smuzhiyun 	return error;
5311*4882a593Smuzhiyun }
5312*4882a593Smuzhiyun 
5313*4882a593Smuzhiyun static void
mptsas_shutdown(struct pci_dev * pdev)5314*4882a593Smuzhiyun mptsas_shutdown(struct pci_dev *pdev)
5315*4882a593Smuzhiyun {
5316*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5317*4882a593Smuzhiyun 
5318*4882a593Smuzhiyun 	mptsas_fw_event_off(ioc);
5319*4882a593Smuzhiyun 	mptsas_cleanup_fw_event_q(ioc);
5320*4882a593Smuzhiyun }
5321*4882a593Smuzhiyun 
mptsas_remove(struct pci_dev * pdev)5322*4882a593Smuzhiyun static void mptsas_remove(struct pci_dev *pdev)
5323*4882a593Smuzhiyun {
5324*4882a593Smuzhiyun 	MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5325*4882a593Smuzhiyun 	struct mptsas_portinfo *p, *n;
5326*4882a593Smuzhiyun 	int i;
5327*4882a593Smuzhiyun 
5328*4882a593Smuzhiyun 	if (!ioc->sh) {
5329*4882a593Smuzhiyun 		printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5330*4882a593Smuzhiyun 		mpt_detach(pdev);
5331*4882a593Smuzhiyun 		return;
5332*4882a593Smuzhiyun 	}
5333*4882a593Smuzhiyun 
5334*4882a593Smuzhiyun 	mptsas_shutdown(pdev);
5335*4882a593Smuzhiyun 
5336*4882a593Smuzhiyun 	mptsas_del_device_components(ioc);
5337*4882a593Smuzhiyun 
5338*4882a593Smuzhiyun 	ioc->sas_discovery_ignore_events = 1;
5339*4882a593Smuzhiyun 	sas_remove_host(ioc->sh);
5340*4882a593Smuzhiyun 
5341*4882a593Smuzhiyun 	mutex_lock(&ioc->sas_topology_mutex);
5342*4882a593Smuzhiyun 	list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5343*4882a593Smuzhiyun 		list_del(&p->list);
5344*4882a593Smuzhiyun 		for (i = 0 ; i < p->num_phys ; i++)
5345*4882a593Smuzhiyun 			mptsas_port_delete(ioc, p->phy_info[i].port_details);
5346*4882a593Smuzhiyun 
5347*4882a593Smuzhiyun 		kfree(p->phy_info);
5348*4882a593Smuzhiyun 		kfree(p);
5349*4882a593Smuzhiyun 	}
5350*4882a593Smuzhiyun 	mutex_unlock(&ioc->sas_topology_mutex);
5351*4882a593Smuzhiyun 	ioc->hba_port_info = NULL;
5352*4882a593Smuzhiyun 	mptscsih_remove(pdev);
5353*4882a593Smuzhiyun }
5354*4882a593Smuzhiyun 
5355*4882a593Smuzhiyun static struct pci_device_id mptsas_pci_table[] = {
5356*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
5357*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID },
5358*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
5359*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID },
5360*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
5361*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID },
5362*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
5363*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID },
5364*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
5365*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID },
5366*4882a593Smuzhiyun 	{ PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP,
5367*4882a593Smuzhiyun 		PCI_ANY_ID, PCI_ANY_ID },
5368*4882a593Smuzhiyun 	{0}	/* Terminating entry */
5369*4882a593Smuzhiyun };
5370*4882a593Smuzhiyun MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5371*4882a593Smuzhiyun 
5372*4882a593Smuzhiyun 
5373*4882a593Smuzhiyun static struct pci_driver mptsas_driver = {
5374*4882a593Smuzhiyun 	.name		= "mptsas",
5375*4882a593Smuzhiyun 	.id_table	= mptsas_pci_table,
5376*4882a593Smuzhiyun 	.probe		= mptsas_probe,
5377*4882a593Smuzhiyun 	.remove		= mptsas_remove,
5378*4882a593Smuzhiyun 	.shutdown	= mptsas_shutdown,
5379*4882a593Smuzhiyun #ifdef CONFIG_PM
5380*4882a593Smuzhiyun 	.suspend	= mptscsih_suspend,
5381*4882a593Smuzhiyun 	.resume		= mptscsih_resume,
5382*4882a593Smuzhiyun #endif
5383*4882a593Smuzhiyun };
5384*4882a593Smuzhiyun 
5385*4882a593Smuzhiyun static int __init
mptsas_init(void)5386*4882a593Smuzhiyun mptsas_init(void)
5387*4882a593Smuzhiyun {
5388*4882a593Smuzhiyun 	int error;
5389*4882a593Smuzhiyun 
5390*4882a593Smuzhiyun 	show_mptmod_ver(my_NAME, my_VERSION);
5391*4882a593Smuzhiyun 
5392*4882a593Smuzhiyun 	mptsas_transport_template =
5393*4882a593Smuzhiyun 	    sas_attach_transport(&mptsas_transport_functions);
5394*4882a593Smuzhiyun 	if (!mptsas_transport_template)
5395*4882a593Smuzhiyun 		return -ENODEV;
5396*4882a593Smuzhiyun 
5397*4882a593Smuzhiyun 	mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
5398*4882a593Smuzhiyun 	    "mptscsih_io_done");
5399*4882a593Smuzhiyun 	mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
5400*4882a593Smuzhiyun 	    "mptscsih_taskmgmt_complete");
5401*4882a593Smuzhiyun 	mptsasInternalCtx =
5402*4882a593Smuzhiyun 		mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
5403*4882a593Smuzhiyun 		    "mptscsih_scandv_complete");
5404*4882a593Smuzhiyun 	mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
5405*4882a593Smuzhiyun 	    "mptsas_mgmt_done");
5406*4882a593Smuzhiyun 	mptsasDeviceResetCtx =
5407*4882a593Smuzhiyun 		mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
5408*4882a593Smuzhiyun 		    "mptsas_taskmgmt_complete");
5409*4882a593Smuzhiyun 
5410*4882a593Smuzhiyun 	mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5411*4882a593Smuzhiyun 	mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
5412*4882a593Smuzhiyun 
5413*4882a593Smuzhiyun 	error = pci_register_driver(&mptsas_driver);
5414*4882a593Smuzhiyun 	if (error)
5415*4882a593Smuzhiyun 		sas_release_transport(mptsas_transport_template);
5416*4882a593Smuzhiyun 
5417*4882a593Smuzhiyun 	return error;
5418*4882a593Smuzhiyun }
5419*4882a593Smuzhiyun 
5420*4882a593Smuzhiyun static void __exit
mptsas_exit(void)5421*4882a593Smuzhiyun mptsas_exit(void)
5422*4882a593Smuzhiyun {
5423*4882a593Smuzhiyun 	pci_unregister_driver(&mptsas_driver);
5424*4882a593Smuzhiyun 	sas_release_transport(mptsas_transport_template);
5425*4882a593Smuzhiyun 
5426*4882a593Smuzhiyun 	mpt_reset_deregister(mptsasDoneCtx);
5427*4882a593Smuzhiyun 	mpt_event_deregister(mptsasDoneCtx);
5428*4882a593Smuzhiyun 
5429*4882a593Smuzhiyun 	mpt_deregister(mptsasMgmtCtx);
5430*4882a593Smuzhiyun 	mpt_deregister(mptsasInternalCtx);
5431*4882a593Smuzhiyun 	mpt_deregister(mptsasTaskCtx);
5432*4882a593Smuzhiyun 	mpt_deregister(mptsasDoneCtx);
5433*4882a593Smuzhiyun 	mpt_deregister(mptsasDeviceResetCtx);
5434*4882a593Smuzhiyun }
5435*4882a593Smuzhiyun 
5436*4882a593Smuzhiyun module_init(mptsas_init);
5437*4882a593Smuzhiyun module_exit(mptsas_exit);
5438