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