10c33b27dSChristoph Hellwig /*
20c33b27dSChristoph Hellwig * linux/drivers/message/fusion/mptsas.c
3f36789e2SPrakash, Sathya * For use with LSI PCI chip/adapter(s)
4f36789e2SPrakash, Sathya * running LSI Fusion MPT (Message Passing Technology) firmware.
50c33b27dSChristoph Hellwig *
6cddc0ab7SPrakash, Sathya * Copyright (c) 1999-2008 LSI Corporation
716d20101SEric Moore * (mailto:DL-MPTFusionLinux@lsi.com)
80c33b27dSChristoph Hellwig */
90c33b27dSChristoph Hellwig /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
100c33b27dSChristoph Hellwig /*
110c33b27dSChristoph Hellwig This program is free software; you can redistribute it and/or modify
120c33b27dSChristoph Hellwig it under the terms of the GNU General Public License as published by
130c33b27dSChristoph Hellwig the Free Software Foundation; version 2 of the License.
140c33b27dSChristoph Hellwig
150c33b27dSChristoph Hellwig This program is distributed in the hope that it will be useful,
160c33b27dSChristoph Hellwig but WITHOUT ANY WARRANTY; without even the implied warranty of
170c33b27dSChristoph Hellwig MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
180c33b27dSChristoph Hellwig GNU General Public License for more details.
190c33b27dSChristoph Hellwig
200c33b27dSChristoph Hellwig NO WARRANTY
210c33b27dSChristoph Hellwig THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
220c33b27dSChristoph Hellwig CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
230c33b27dSChristoph Hellwig LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
240c33b27dSChristoph Hellwig MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
250c33b27dSChristoph Hellwig solely responsible for determining the appropriateness of using and
260c33b27dSChristoph Hellwig distributing the Program and assumes all risks associated with its
270c33b27dSChristoph Hellwig exercise of rights under this Agreement, including but not limited to
280c33b27dSChristoph Hellwig the risks and costs of program errors, damage to or loss of data,
290c33b27dSChristoph Hellwig programs or equipment, and unavailability or interruption of operations.
300c33b27dSChristoph Hellwig
310c33b27dSChristoph Hellwig DISCLAIMER OF LIABILITY
320c33b27dSChristoph Hellwig NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
330c33b27dSChristoph Hellwig DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
340c33b27dSChristoph Hellwig DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
350c33b27dSChristoph Hellwig ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
360c33b27dSChristoph Hellwig TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
370c33b27dSChristoph Hellwig USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
380c33b27dSChristoph Hellwig HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
390c33b27dSChristoph Hellwig
400c33b27dSChristoph Hellwig You should have received a copy of the GNU General Public License
410c33b27dSChristoph Hellwig along with this program; if not, write to the Free Software
420c33b27dSChristoph Hellwig Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
430c33b27dSChristoph Hellwig */
440c33b27dSChristoph Hellwig /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
450c33b27dSChristoph Hellwig
460c33b27dSChristoph Hellwig #include <linux/module.h>
470c33b27dSChristoph Hellwig #include <linux/kernel.h>
485a0e3ad6STejun Heo #include <linux/slab.h>
490c33b27dSChristoph Hellwig #include <linux/init.h>
500c33b27dSChristoph Hellwig #include <linux/errno.h>
51cd354f1aSTim Schmielau #include <linux/jiffies.h>
520c33b27dSChristoph Hellwig #include <linux/workqueue.h>
53547f9a21SEric Moore #include <linux/delay.h> /* for mdelay */
540c33b27dSChristoph Hellwig
55547f9a21SEric Moore #include <scsi/scsi.h>
560c33b27dSChristoph Hellwig #include <scsi/scsi_cmnd.h>
570c33b27dSChristoph Hellwig #include <scsi/scsi_device.h>
580c33b27dSChristoph Hellwig #include <scsi/scsi_host.h>
590c33b27dSChristoph Hellwig #include <scsi/scsi_transport_sas.h>
60c9de7dc4SKashyap, Desai #include <scsi/scsi_transport.h>
61547f9a21SEric Moore #include <scsi/scsi_dbg.h>
620c33b27dSChristoph Hellwig
630c33b27dSChristoph Hellwig #include "mptbase.h"
640c33b27dSChristoph Hellwig #include "mptscsih.h"
6556af97aeSPrakash, Sathya #include "mptsas.h"
660c33b27dSChristoph Hellwig
670c33b27dSChristoph Hellwig
680c33b27dSChristoph Hellwig #define my_NAME "Fusion MPT SAS Host driver"
690c33b27dSChristoph Hellwig #define my_VERSION MPT_LINUX_VERSION_COMMON
700c33b27dSChristoph Hellwig #define MYNAM "mptsas"
710c33b27dSChristoph Hellwig
72e8bf3941SJames Bottomley /*
73e8bf3941SJames Bottomley * Reserved channel for integrated raid
74e8bf3941SJames Bottomley */
75e8bf3941SJames Bottomley #define MPTSAS_RAID_CHANNEL 1
76e8bf3941SJames Bottomley
774b97650bSKashyap, Desai #define SAS_CONFIG_PAGE_TIMEOUT 30
780c33b27dSChristoph Hellwig MODULE_AUTHOR(MODULEAUTHOR);
790c33b27dSChristoph Hellwig MODULE_DESCRIPTION(my_NAME);
800c33b27dSChristoph Hellwig MODULE_LICENSE("GPL");
819f4203b3SEric Moore MODULE_VERSION(my_VERSION);
820c33b27dSChristoph Hellwig
830c33b27dSChristoph Hellwig static int mpt_pt_clear;
840c33b27dSChristoph Hellwig module_param(mpt_pt_clear, int, 0);
850c33b27dSChristoph Hellwig MODULE_PARM_DESC(mpt_pt_clear,
860c33b27dSChristoph Hellwig " Clear persistency table: enable=1 "
870c33b27dSChristoph Hellwig "(default=MPTSCSIH_PT_CLEAR=0)");
880c33b27dSChristoph Hellwig
89cdcda465SRandy Dunlap /* scsi-mid layer global parameter is max_report_luns, which is 511 */
90793955f5SEric Moore #define MPTSAS_MAX_LUN (16895)
91793955f5SEric Moore static int max_lun = MPTSAS_MAX_LUN;
92793955f5SEric Moore module_param(max_lun, int, 0);
93793955f5SEric Moore MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
94793955f5SEric Moore
953850b14eSkashyap.desai@lsi.com static int mpt_loadtime_max_sectors = 8192;
963850b14eSkashyap.desai@lsi.com module_param(mpt_loadtime_max_sectors, int, 0);
973850b14eSkashyap.desai@lsi.com MODULE_PARM_DESC(mpt_loadtime_max_sectors,
983850b14eSkashyap.desai@lsi.com " Maximum sector define for Host Bus Adaptor.Range 64 to 8192 default=8192");
993850b14eSkashyap.desai@lsi.com
100f606f571SPrakash, Sathya static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
101f606f571SPrakash, Sathya static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
102f606f571SPrakash, Sathya static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
103f606f571SPrakash, Sathya static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
104e7deff33SKashyap, Desai static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
1050c33b27dSChristoph Hellwig
1063eb0822cSKashyap, Desai static void mptsas_firmware_event_work(struct work_struct *work);
1073eb0822cSKashyap, Desai static void mptsas_send_sas_event(struct fw_event_work *fw_event);
1083eb0822cSKashyap, Desai static void mptsas_send_raid_event(struct fw_event_work *fw_event);
1093eb0822cSKashyap, Desai static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
1103eb0822cSKashyap, Desai static void mptsas_parse_device_info(struct sas_identify *identify,
1113eb0822cSKashyap, Desai struct mptsas_devinfo *device_info);
1123eb0822cSKashyap, Desai static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
1133eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
1143eb0822cSKashyap, Desai static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
1153eb0822cSKashyap, Desai (MPT_ADAPTER *ioc, u64 sas_address);
1163eb0822cSKashyap, Desai static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
1173eb0822cSKashyap, Desai struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
1183eb0822cSKashyap, Desai static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
1193eb0822cSKashyap, Desai struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
1203eb0822cSKashyap, Desai static int mptsas_add_end_device(MPT_ADAPTER *ioc,
1213eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info);
1223eb0822cSKashyap, Desai static void mptsas_del_end_device(MPT_ADAPTER *ioc,
1233eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info);
124f9c34022SKashyap, Desai static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
125f9c34022SKashyap, Desai static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
126f9c34022SKashyap, Desai (MPT_ADAPTER *ioc, u64 sas_address);
127f9c34022SKashyap, Desai static void mptsas_expander_delete(MPT_ADAPTER *ioc,
128f9c34022SKashyap, Desai struct mptsas_portinfo *port_info, u8 force);
129f9c34022SKashyap, Desai static void mptsas_send_expander_event(struct fw_event_work *fw_event);
130eedf92b9SKashyap, Desai static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
131eedf92b9SKashyap, Desai static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
13294e989deSColin Ian King static void mptsas_broadcast_primitive_work(struct fw_event_work *fw_event);
13357e98513SKashyap, Desai static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
134a7938b0bSKashyap, Desai static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
135b68bf096SKashyap, Desai void mptsas_schedule_target_reset(void *ioc);
1360c33b27dSChristoph Hellwig
mptsas_print_phy_data(MPT_ADAPTER * ioc,MPI_SAS_IO_UNIT0_PHY_DATA * phy_data)137d6ecdd63SPrakash, Sathya static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
138d6ecdd63SPrakash, Sathya MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
139b5141128SChristoph Hellwig {
14029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
14129dd3609SEric Moore "---- IO UNIT PAGE 0 ------------\n", ioc->name));
14229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
14329dd3609SEric Moore ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
14429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
14529dd3609SEric Moore ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
14629dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
14729dd3609SEric Moore ioc->name, phy_data->Port));
14829dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
14929dd3609SEric Moore ioc->name, phy_data->PortFlags));
15029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
15129dd3609SEric Moore ioc->name, phy_data->PhyFlags));
15229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
15329dd3609SEric Moore ioc->name, phy_data->NegotiatedLinkRate));
15429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
15529dd3609SEric Moore "Controller PHY Device Info=0x%X\n", ioc->name,
156d6ecdd63SPrakash, Sathya le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
15729dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
15829dd3609SEric Moore ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
159b5141128SChristoph Hellwig }
160b5141128SChristoph Hellwig
mptsas_print_phy_pg0(MPT_ADAPTER * ioc,SasPhyPage0_t * pg0)161d6ecdd63SPrakash, Sathya static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
162b5141128SChristoph Hellwig {
163b5141128SChristoph Hellwig __le64 sas_address;
164b5141128SChristoph Hellwig
165b5141128SChristoph Hellwig memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
166b5141128SChristoph Hellwig
16729dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
16829dd3609SEric Moore "---- SAS PHY PAGE 0 ------------\n", ioc->name));
16929dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
17029dd3609SEric Moore "Attached Device Handle=0x%X\n", ioc->name,
171d6ecdd63SPrakash, Sathya le16_to_cpu(pg0->AttachedDevHandle)));
17229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
17329dd3609SEric Moore ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
17429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
17529dd3609SEric Moore "Attached PHY Identifier=0x%X\n", ioc->name,
17629dd3609SEric Moore pg0->AttachedPhyIdentifier));
17729dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
17829dd3609SEric Moore ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
17929dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
18029dd3609SEric Moore ioc->name, pg0->ProgrammedLinkRate));
18129dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
18229dd3609SEric Moore ioc->name, pg0->ChangeCount));
18329dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
18429dd3609SEric Moore ioc->name, le32_to_cpu(pg0->PhyInfo)));
185b5141128SChristoph Hellwig }
186b5141128SChristoph Hellwig
mptsas_print_phy_pg1(MPT_ADAPTER * ioc,SasPhyPage1_t * pg1)187d6ecdd63SPrakash, Sathya static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
188b5141128SChristoph Hellwig {
18929dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
19029dd3609SEric Moore "---- SAS PHY PAGE 1 ------------\n", ioc->name));
19129dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
19229dd3609SEric Moore ioc->name, pg1->InvalidDwordCount));
19329dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
19429dd3609SEric Moore "Running Disparity Error Count=0x%x\n", ioc->name,
195d6ecdd63SPrakash, Sathya pg1->RunningDisparityErrorCount));
19629dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
19729dd3609SEric Moore "Loss Dword Synch Count=0x%x\n", ioc->name,
19829dd3609SEric Moore pg1->LossDwordSynchCount));
19929dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
20029dd3609SEric Moore "PHY Reset Problem Count=0x%x\n\n", ioc->name,
20129dd3609SEric Moore pg1->PhyResetProblemCount));
202b5141128SChristoph Hellwig }
203b5141128SChristoph Hellwig
mptsas_print_device_pg0(MPT_ADAPTER * ioc,SasDevicePage0_t * pg0)204d6ecdd63SPrakash, Sathya static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
205b5141128SChristoph Hellwig {
206b5141128SChristoph Hellwig __le64 sas_address;
207b5141128SChristoph Hellwig
208b5141128SChristoph Hellwig memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
209b5141128SChristoph Hellwig
21029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
21129dd3609SEric Moore "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
21229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
21329dd3609SEric Moore ioc->name, le16_to_cpu(pg0->DevHandle)));
21429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
21529dd3609SEric Moore ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
21629dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
21729dd3609SEric Moore ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
21829dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
21929dd3609SEric Moore ioc->name, le16_to_cpu(pg0->Slot)));
22029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
22129dd3609SEric Moore ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
22229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
22329dd3609SEric Moore ioc->name, pg0->TargetID));
22429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
22529dd3609SEric Moore ioc->name, pg0->Bus));
22629dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
22729dd3609SEric Moore ioc->name, pg0->PhyNum));
22829dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
22929dd3609SEric Moore ioc->name, le16_to_cpu(pg0->AccessStatus)));
23029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
23129dd3609SEric Moore ioc->name, le32_to_cpu(pg0->DeviceInfo)));
23229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
23329dd3609SEric Moore ioc->name, le16_to_cpu(pg0->Flags)));
23429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
23529dd3609SEric Moore ioc->name, pg0->PhysicalPort));
236b5141128SChristoph Hellwig }
237b5141128SChristoph Hellwig
mptsas_print_expander_pg1(MPT_ADAPTER * ioc,SasExpanderPage1_t * pg1)238d6ecdd63SPrakash, Sathya static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
239b5141128SChristoph Hellwig {
24029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
24129dd3609SEric Moore "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
24229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
24329dd3609SEric Moore ioc->name, pg1->PhysicalPort));
24429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
24529dd3609SEric Moore ioc->name, pg1->PhyIdentifier));
24629dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
24729dd3609SEric Moore ioc->name, pg1->NegotiatedLinkRate));
24829dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
24929dd3609SEric Moore ioc->name, pg1->ProgrammedLinkRate));
25029dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
25129dd3609SEric Moore ioc->name, pg1->HwLinkRate));
25229dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
25329dd3609SEric Moore ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
25429dd3609SEric Moore dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
25529dd3609SEric Moore "Attached Device Handle=0x%X\n\n", ioc->name,
256d6ecdd63SPrakash, Sathya le16_to_cpu(pg1->AttachedDevHandle)));
257b5141128SChristoph Hellwig }
258b5141128SChristoph Hellwig
2593eb0822cSKashyap, Desai /* inhibit sas firmware event handling */
2603eb0822cSKashyap, Desai static void
mptsas_fw_event_off(MPT_ADAPTER * ioc)2613eb0822cSKashyap, Desai mptsas_fw_event_off(MPT_ADAPTER *ioc)
2623eb0822cSKashyap, Desai {
2633eb0822cSKashyap, Desai unsigned long flags;
2643eb0822cSKashyap, Desai
2653eb0822cSKashyap, Desai spin_lock_irqsave(&ioc->fw_event_lock, flags);
2663eb0822cSKashyap, Desai ioc->fw_events_off = 1;
2673eb0822cSKashyap, Desai ioc->sas_discovery_quiesce_io = 0;
2683eb0822cSKashyap, Desai spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2693eb0822cSKashyap, Desai
2703eb0822cSKashyap, Desai }
2713eb0822cSKashyap, Desai
2723eb0822cSKashyap, Desai /* enable sas firmware event handling */
2733eb0822cSKashyap, Desai static void
mptsas_fw_event_on(MPT_ADAPTER * ioc)2743eb0822cSKashyap, Desai mptsas_fw_event_on(MPT_ADAPTER *ioc)
2753eb0822cSKashyap, Desai {
2763eb0822cSKashyap, Desai unsigned long flags;
2773eb0822cSKashyap, Desai
2783eb0822cSKashyap, Desai spin_lock_irqsave(&ioc->fw_event_lock, flags);
2793eb0822cSKashyap, Desai ioc->fw_events_off = 0;
2803eb0822cSKashyap, Desai spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
2813eb0822cSKashyap, Desai }
2823eb0822cSKashyap, Desai
2833eb0822cSKashyap, Desai /* queue a sas firmware event */
2843eb0822cSKashyap, Desai static void
mptsas_add_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event,unsigned long delay)2853eb0822cSKashyap, Desai mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
2863eb0822cSKashyap, Desai unsigned long delay)
2873eb0822cSKashyap, Desai {
2883eb0822cSKashyap, Desai unsigned long flags;
2893eb0822cSKashyap, Desai
2903eb0822cSKashyap, Desai spin_lock_irqsave(&ioc->fw_event_lock, flags);
2913eb0822cSKashyap, Desai list_add_tail(&fw_event->list, &ioc->fw_event_list);
292817a7c99SSebastian Andrzej Siewior fw_event->users = 1;
2933eb0822cSKashyap, Desai INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
294a38ae37fSkashyap.desai@lsi.com devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)"
295a38ae37fSkashyap.desai@lsi.com "on cpuid %d\n", ioc->name, __func__,
296a38ae37fSkashyap.desai@lsi.com fw_event, smp_processor_id()));
297a38ae37fSkashyap.desai@lsi.com queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q,
298a38ae37fSkashyap.desai@lsi.com &fw_event->work, delay);
2993eb0822cSKashyap, Desai spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
3003eb0822cSKashyap, Desai }
3013eb0822cSKashyap, Desai
302db7051b2SKashyap, Desai /* requeue a sas firmware event */
303db7051b2SKashyap, Desai static void
mptsas_requeue_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event,unsigned long delay)304db7051b2SKashyap, Desai mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
305db7051b2SKashyap, Desai unsigned long delay)
306db7051b2SKashyap, Desai {
307db7051b2SKashyap, Desai unsigned long flags;
308db7051b2SKashyap, Desai spin_lock_irqsave(&ioc->fw_event_lock, flags);
309db7051b2SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
310a38ae37fSkashyap.desai@lsi.com "(fw_event=0x%p)on cpuid %d\n", ioc->name, __func__,
311a38ae37fSkashyap.desai@lsi.com fw_event, smp_processor_id()));
312db7051b2SKashyap, Desai fw_event->retries++;
313a38ae37fSkashyap.desai@lsi.com queue_delayed_work_on(smp_processor_id(), ioc->fw_event_q,
314a38ae37fSkashyap.desai@lsi.com &fw_event->work, msecs_to_jiffies(delay));
315db7051b2SKashyap, Desai spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
316db7051b2SKashyap, Desai }
317db7051b2SKashyap, Desai
__mptsas_free_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event)318817a7c99SSebastian Andrzej Siewior static void __mptsas_free_fw_event(MPT_ADAPTER *ioc,
319817a7c99SSebastian Andrzej Siewior struct fw_event_work *fw_event)
320817a7c99SSebastian Andrzej Siewior {
321817a7c99SSebastian Andrzej Siewior devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
322817a7c99SSebastian Andrzej Siewior ioc->name, __func__, fw_event));
323817a7c99SSebastian Andrzej Siewior list_del(&fw_event->list);
324817a7c99SSebastian Andrzej Siewior kfree(fw_event);
325817a7c99SSebastian Andrzej Siewior }
326817a7c99SSebastian Andrzej Siewior
32725985edcSLucas De Marchi /* free memory associated to a sas firmware event */
3283eb0822cSKashyap, Desai static void
mptsas_free_fw_event(MPT_ADAPTER * ioc,struct fw_event_work * fw_event)3293eb0822cSKashyap, Desai mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
3303eb0822cSKashyap, Desai {
3313eb0822cSKashyap, Desai unsigned long flags;
3323eb0822cSKashyap, Desai
3333eb0822cSKashyap, Desai spin_lock_irqsave(&ioc->fw_event_lock, flags);
334817a7c99SSebastian Andrzej Siewior fw_event->users--;
335817a7c99SSebastian Andrzej Siewior if (!fw_event->users)
336817a7c99SSebastian Andrzej Siewior __mptsas_free_fw_event(ioc, fw_event);
3373eb0822cSKashyap, Desai spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
3383eb0822cSKashyap, Desai }
3393eb0822cSKashyap, Desai
3403eb0822cSKashyap, Desai /* walk the firmware event queue, and either stop or wait for
3413eb0822cSKashyap, Desai * outstanding events to complete */
3423eb0822cSKashyap, Desai static void
mptsas_cleanup_fw_event_q(MPT_ADAPTER * ioc)3433eb0822cSKashyap, Desai mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
3443eb0822cSKashyap, Desai {
345817a7c99SSebastian Andrzej Siewior struct fw_event_work *fw_event;
3463eb0822cSKashyap, Desai struct mptsas_target_reset_event *target_reset_list, *n;
3473eb0822cSKashyap, Desai MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
348817a7c99SSebastian Andrzej Siewior unsigned long flags;
3493eb0822cSKashyap, Desai
3503eb0822cSKashyap, Desai /* flush the target_reset_list */
3513eb0822cSKashyap, Desai if (!list_empty(&hd->target_reset_list)) {
3523eb0822cSKashyap, Desai list_for_each_entry_safe(target_reset_list, n,
3533eb0822cSKashyap, Desai &hd->target_reset_list, list) {
3543eb0822cSKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3553eb0822cSKashyap, Desai "%s: removing target reset for id=%d\n",
3563eb0822cSKashyap, Desai ioc->name, __func__,
3573eb0822cSKashyap, Desai target_reset_list->sas_event_data.TargetID));
3583eb0822cSKashyap, Desai list_del(&target_reset_list->list);
3593eb0822cSKashyap, Desai kfree(target_reset_list);
3603eb0822cSKashyap, Desai }
3613eb0822cSKashyap, Desai }
3623eb0822cSKashyap, Desai
363817a7c99SSebastian Andrzej Siewior if (list_empty(&ioc->fw_event_list) || !ioc->fw_event_q)
3643eb0822cSKashyap, Desai return;
3653eb0822cSKashyap, Desai
366817a7c99SSebastian Andrzej Siewior spin_lock_irqsave(&ioc->fw_event_lock, flags);
367817a7c99SSebastian Andrzej Siewior
368817a7c99SSebastian Andrzej Siewior while (!list_empty(&ioc->fw_event_list)) {
369817a7c99SSebastian Andrzej Siewior bool canceled = false;
370817a7c99SSebastian Andrzej Siewior
371817a7c99SSebastian Andrzej Siewior fw_event = list_first_entry(&ioc->fw_event_list,
372817a7c99SSebastian Andrzej Siewior struct fw_event_work, list);
373817a7c99SSebastian Andrzej Siewior fw_event->users++;
374817a7c99SSebastian Andrzej Siewior spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
375817a7c99SSebastian Andrzej Siewior if (cancel_delayed_work_sync(&fw_event->work))
376817a7c99SSebastian Andrzej Siewior canceled = true;
377817a7c99SSebastian Andrzej Siewior
378817a7c99SSebastian Andrzej Siewior spin_lock_irqsave(&ioc->fw_event_lock, flags);
379817a7c99SSebastian Andrzej Siewior if (canceled)
380817a7c99SSebastian Andrzej Siewior fw_event->users--;
381817a7c99SSebastian Andrzej Siewior fw_event->users--;
382817a7c99SSebastian Andrzej Siewior WARN_ON_ONCE(fw_event->users);
383817a7c99SSebastian Andrzej Siewior __mptsas_free_fw_event(ioc, fw_event);
3843eb0822cSKashyap, Desai }
385817a7c99SSebastian Andrzej Siewior spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
3863eb0822cSKashyap, Desai }
3873eb0822cSKashyap, Desai
3883eb0822cSKashyap, Desai
phy_to_ioc(struct sas_phy * phy)389e3094447SChristoph Hellwig static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
390e3094447SChristoph Hellwig {
391e3094447SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
392e3094447SChristoph Hellwig return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
393e3094447SChristoph Hellwig }
394e3094447SChristoph Hellwig
rphy_to_ioc(struct sas_rphy * rphy)395e3094447SChristoph Hellwig static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
396e3094447SChristoph Hellwig {
397e3094447SChristoph Hellwig struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
398e3094447SChristoph Hellwig return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
399e3094447SChristoph Hellwig }
400e3094447SChristoph Hellwig
401e6b2d76aSMoore, Eric /*
402e6b2d76aSMoore, Eric * mptsas_find_portinfo_by_handle
403e6b2d76aSMoore, Eric *
404e6b2d76aSMoore, Eric * This function should be called with the sas_topology_mutex already held
405e6b2d76aSMoore, Eric */
406e6b2d76aSMoore, Eric static struct mptsas_portinfo *
mptsas_find_portinfo_by_handle(MPT_ADAPTER * ioc,u16 handle)407e6b2d76aSMoore, Eric mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
408e6b2d76aSMoore, Eric {
409e6b2d76aSMoore, Eric struct mptsas_portinfo *port_info, *rc=NULL;
410e6b2d76aSMoore, Eric int i;
411e6b2d76aSMoore, Eric
412e6b2d76aSMoore, Eric list_for_each_entry(port_info, &ioc->sas_topology, list)
413e6b2d76aSMoore, Eric for (i = 0; i < port_info->num_phys; i++)
414e6b2d76aSMoore, Eric if (port_info->phy_info[i].identify.handle == handle) {
415e6b2d76aSMoore, Eric rc = port_info;
416e6b2d76aSMoore, Eric goto out;
417e6b2d76aSMoore, Eric }
418e6b2d76aSMoore, Eric out:
419e6b2d76aSMoore, Eric return rc;
420e6b2d76aSMoore, Eric }
421e6b2d76aSMoore, Eric
422f9c34022SKashyap, Desai /**
423cdcda465SRandy Dunlap * mptsas_find_portinfo_by_sas_address - find and return portinfo for
424cdcda465SRandy Dunlap * this sas_address
425f9c34022SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
426cdcda465SRandy Dunlap * @sas_address: expander sas address
427f9c34022SKashyap, Desai *
428cdcda465SRandy Dunlap * This function should be called with the sas_topology_mutex already held.
429f9c34022SKashyap, Desai *
430cdcda465SRandy Dunlap * Return: %NULL if not found.
431f9c34022SKashyap, Desai **/
432f9c34022SKashyap, Desai static struct mptsas_portinfo *
mptsas_find_portinfo_by_sas_address(MPT_ADAPTER * ioc,u64 sas_address)433f9c34022SKashyap, Desai mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
434f9c34022SKashyap, Desai {
435f9c34022SKashyap, Desai struct mptsas_portinfo *port_info, *rc = NULL;
436f9c34022SKashyap, Desai int i;
437f9c34022SKashyap, Desai
438f9c34022SKashyap, Desai if (sas_address >= ioc->hba_port_sas_addr &&
439f9c34022SKashyap, Desai sas_address < (ioc->hba_port_sas_addr +
440f9c34022SKashyap, Desai ioc->hba_port_num_phy))
441f9c34022SKashyap, Desai return ioc->hba_port_info;
442f9c34022SKashyap, Desai
443f9c34022SKashyap, Desai mutex_lock(&ioc->sas_topology_mutex);
444f9c34022SKashyap, Desai list_for_each_entry(port_info, &ioc->sas_topology, list)
445f9c34022SKashyap, Desai for (i = 0; i < port_info->num_phys; i++)
446f9c34022SKashyap, Desai if (port_info->phy_info[i].identify.sas_address ==
447f9c34022SKashyap, Desai sas_address) {
448f9c34022SKashyap, Desai rc = port_info;
449f9c34022SKashyap, Desai goto out;
450f9c34022SKashyap, Desai }
451f9c34022SKashyap, Desai out:
452f9c34022SKashyap, Desai mutex_unlock(&ioc->sas_topology_mutex);
453f9c34022SKashyap, Desai return rc;
454f9c34022SKashyap, Desai }
455f9c34022SKashyap, Desai
456bd23e94cSMoore, Eric /*
457bd23e94cSMoore, Eric * Returns true if there is a scsi end device
458bd23e94cSMoore, Eric */
459bd23e94cSMoore, Eric static inline int
mptsas_is_end_device(struct mptsas_devinfo * attached)460bd23e94cSMoore, Eric mptsas_is_end_device(struct mptsas_devinfo * attached)
461bd23e94cSMoore, Eric {
462547f9a21SEric Moore if ((attached->sas_address) &&
463bd23e94cSMoore, Eric (attached->device_info &
464bd23e94cSMoore, Eric MPI_SAS_DEVICE_INFO_END_DEVICE) &&
465bd23e94cSMoore, Eric ((attached->device_info &
466bd23e94cSMoore, Eric MPI_SAS_DEVICE_INFO_SSP_TARGET) |
467bd23e94cSMoore, Eric (attached->device_info &
468bd23e94cSMoore, Eric MPI_SAS_DEVICE_INFO_STP_TARGET) |
469bd23e94cSMoore, Eric (attached->device_info &
470bd23e94cSMoore, Eric MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
471bd23e94cSMoore, Eric return 1;
472bd23e94cSMoore, Eric else
473bd23e94cSMoore, Eric return 0;
474bd23e94cSMoore, Eric }
475bd23e94cSMoore, Eric
476547f9a21SEric Moore /* no mutex */
477376ac830SEric Moore static void
mptsas_port_delete(MPT_ADAPTER * ioc,struct mptsas_portinfo_details * port_details)478d6ecdd63SPrakash, Sathya mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
479547f9a21SEric Moore {
480547f9a21SEric Moore struct mptsas_portinfo *port_info;
481547f9a21SEric Moore struct mptsas_phyinfo *phy_info;
482547f9a21SEric Moore u8 i;
483547f9a21SEric Moore
484547f9a21SEric Moore if (!port_details)
485547f9a21SEric Moore return;
486547f9a21SEric Moore
487547f9a21SEric Moore port_info = port_details->port_info;
488547f9a21SEric Moore phy_info = port_info->phy_info;
489547f9a21SEric Moore
49029dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
491cadbd4a5SHarvey Harrison "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
492f99be43bSEric Moore port_details->num_phys, (unsigned long long)
493dc22f16dSEric Moore port_details->phy_bitmask));
494547f9a21SEric Moore
495547f9a21SEric Moore for (i = 0; i < port_info->num_phys; i++, phy_info++) {
496547f9a21SEric Moore if(phy_info->port_details != port_details)
497547f9a21SEric Moore continue;
498547f9a21SEric Moore memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
4993eb0822cSKashyap, Desai mptsas_set_rphy(ioc, phy_info, NULL);
500547f9a21SEric Moore phy_info->port_details = NULL;
501547f9a21SEric Moore }
502547f9a21SEric Moore kfree(port_details);
503547f9a21SEric Moore }
504547f9a21SEric Moore
505547f9a21SEric Moore static inline struct sas_rphy *
mptsas_get_rphy(struct mptsas_phyinfo * phy_info)506547f9a21SEric Moore mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
507547f9a21SEric Moore {
508547f9a21SEric Moore if (phy_info->port_details)
509547f9a21SEric Moore return phy_info->port_details->rphy;
510547f9a21SEric Moore else
511547f9a21SEric Moore return NULL;
512547f9a21SEric Moore }
513547f9a21SEric Moore
514547f9a21SEric Moore static inline void
mptsas_set_rphy(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,struct sas_rphy * rphy)515d6ecdd63SPrakash, Sathya mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
516547f9a21SEric Moore {
517547f9a21SEric Moore if (phy_info->port_details) {
518547f9a21SEric Moore phy_info->port_details->rphy = rphy;
51929dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
52029dd3609SEric Moore ioc->name, rphy));
521547f9a21SEric Moore }
522547f9a21SEric Moore
523547f9a21SEric Moore if (rphy) {
524c51d0beaSEric Moore dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
525c51d0beaSEric Moore &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
52629dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
52729dd3609SEric Moore ioc->name, rphy, rphy->dev.release));
528547f9a21SEric Moore }
529547f9a21SEric Moore }
530547f9a21SEric Moore
531547f9a21SEric Moore static inline struct sas_port *
mptsas_get_port(struct mptsas_phyinfo * phy_info)532547f9a21SEric Moore mptsas_get_port(struct mptsas_phyinfo *phy_info)
533547f9a21SEric Moore {
534547f9a21SEric Moore if (phy_info->port_details)
535547f9a21SEric Moore return phy_info->port_details->port;
536547f9a21SEric Moore else
537547f9a21SEric Moore return NULL;
538547f9a21SEric Moore }
539547f9a21SEric Moore
540547f9a21SEric Moore static inline void
mptsas_set_port(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,struct sas_port * port)541d6ecdd63SPrakash, Sathya mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
542547f9a21SEric Moore {
543547f9a21SEric Moore if (phy_info->port_details)
544547f9a21SEric Moore phy_info->port_details->port = port;
545547f9a21SEric Moore
546547f9a21SEric Moore if (port) {
547c51d0beaSEric Moore dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
548c51d0beaSEric Moore &port->dev, MYIOC_s_FMT "add:", ioc->name));
54929dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
55029dd3609SEric Moore ioc->name, port, port->dev.release));
551547f9a21SEric Moore }
552547f9a21SEric Moore }
553547f9a21SEric Moore
554547f9a21SEric Moore static inline struct scsi_target *
mptsas_get_starget(struct mptsas_phyinfo * phy_info)555547f9a21SEric Moore mptsas_get_starget(struct mptsas_phyinfo *phy_info)
556547f9a21SEric Moore {
557547f9a21SEric Moore if (phy_info->port_details)
558547f9a21SEric Moore return phy_info->port_details->starget;
559547f9a21SEric Moore else
560547f9a21SEric Moore return NULL;
561547f9a21SEric Moore }
562547f9a21SEric Moore
563547f9a21SEric Moore static inline void
mptsas_set_starget(struct mptsas_phyinfo * phy_info,struct scsi_target * starget)564547f9a21SEric Moore mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
565547f9a21SEric Moore starget)
566547f9a21SEric Moore {
567547f9a21SEric Moore if (phy_info->port_details)
568547f9a21SEric Moore phy_info->port_details->starget = starget;
569547f9a21SEric Moore }
570547f9a21SEric Moore
5713eb0822cSKashyap, Desai /**
572cdcda465SRandy Dunlap * mptsas_add_device_component - adds a new device component to our lists
5733eb0822cSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
574cdcda465SRandy Dunlap * @channel: channel number
575cdcda465SRandy Dunlap * @id: Logical Target ID for reset (if appropriate)
576cdcda465SRandy Dunlap * @sas_address: expander sas address
577cdcda465SRandy Dunlap * @device_info: specific bits (flags) for devices
578cdcda465SRandy Dunlap * @slot: enclosure slot ID
579cdcda465SRandy Dunlap * @enclosure_logical_id: enclosure WWN
5803eb0822cSKashyap, Desai *
5813eb0822cSKashyap, Desai **/
5823eb0822cSKashyap, Desai 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)5833eb0822cSKashyap, Desai mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
5843eb0822cSKashyap, Desai u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
5853eb0822cSKashyap, Desai {
5863eb0822cSKashyap, Desai struct mptsas_device_info *sas_info, *next;
5873eb0822cSKashyap, Desai struct scsi_device *sdev;
5883eb0822cSKashyap, Desai struct scsi_target *starget;
5893eb0822cSKashyap, Desai struct sas_rphy *rphy;
5903eb0822cSKashyap, Desai
5913eb0822cSKashyap, Desai /*
5923eb0822cSKashyap, Desai * Delete all matching devices out of the list
5933eb0822cSKashyap, Desai */
5943eb0822cSKashyap, Desai mutex_lock(&ioc->sas_device_info_mutex);
5953eb0822cSKashyap, Desai list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
5963eb0822cSKashyap, Desai list) {
597a7938b0bSKashyap, Desai if (!sas_info->is_logical_volume &&
598a7938b0bSKashyap, Desai (sas_info->sas_address == sas_address ||
5993eb0822cSKashyap, Desai (sas_info->fw.channel == channel &&
6003eb0822cSKashyap, Desai sas_info->fw.id == id))) {
6013eb0822cSKashyap, Desai list_del(&sas_info->list);
6023eb0822cSKashyap, Desai kfree(sas_info);
6033eb0822cSKashyap, Desai }
6043eb0822cSKashyap, Desai }
6053eb0822cSKashyap, Desai
6063eb0822cSKashyap, Desai sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
6073eb0822cSKashyap, Desai if (!sas_info)
6083eb0822cSKashyap, Desai goto out;
6093eb0822cSKashyap, Desai
6103eb0822cSKashyap, Desai /*
6113eb0822cSKashyap, Desai * Set Firmware mapping
6123eb0822cSKashyap, Desai */
6133eb0822cSKashyap, Desai sas_info->fw.id = id;
6143eb0822cSKashyap, Desai sas_info->fw.channel = channel;
6153eb0822cSKashyap, Desai
6163eb0822cSKashyap, Desai sas_info->sas_address = sas_address;
6173eb0822cSKashyap, Desai sas_info->device_info = device_info;
6183eb0822cSKashyap, Desai sas_info->slot = slot;
6193eb0822cSKashyap, Desai sas_info->enclosure_logical_id = enclosure_logical_id;
6203eb0822cSKashyap, Desai INIT_LIST_HEAD(&sas_info->list);
6213eb0822cSKashyap, Desai list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
6223eb0822cSKashyap, Desai
6233eb0822cSKashyap, Desai /*
6243eb0822cSKashyap, Desai * Set OS mapping
6253eb0822cSKashyap, Desai */
6263eb0822cSKashyap, Desai shost_for_each_device(sdev, ioc->sh) {
6273eb0822cSKashyap, Desai starget = scsi_target(sdev);
6283eb0822cSKashyap, Desai rphy = dev_to_rphy(starget->dev.parent);
6293eb0822cSKashyap, Desai if (rphy->identify.sas_address == sas_address) {
6303eb0822cSKashyap, Desai sas_info->os.id = starget->id;
6313eb0822cSKashyap, Desai sas_info->os.channel = starget->channel;
6323eb0822cSKashyap, Desai }
6333eb0822cSKashyap, Desai }
6343eb0822cSKashyap, Desai
6353eb0822cSKashyap, Desai out:
6363eb0822cSKashyap, Desai mutex_unlock(&ioc->sas_device_info_mutex);
6373eb0822cSKashyap, Desai return;
6383eb0822cSKashyap, Desai }
6393eb0822cSKashyap, Desai
6403eb0822cSKashyap, Desai /**
641cdcda465SRandy Dunlap * mptsas_add_device_component_by_fw - adds a new device component by FW ID
6423eb0822cSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
643cdcda465SRandy Dunlap * @channel: channel number
644cdcda465SRandy Dunlap * @id: Logical Target ID
6453eb0822cSKashyap, Desai *
6463eb0822cSKashyap, Desai **/
6473eb0822cSKashyap, Desai static void
mptsas_add_device_component_by_fw(MPT_ADAPTER * ioc,u8 channel,u8 id)6483eb0822cSKashyap, Desai mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
6493eb0822cSKashyap, Desai {
6503eb0822cSKashyap, Desai struct mptsas_devinfo sas_device;
6513eb0822cSKashyap, Desai struct mptsas_enclosure enclosure_info;
6523eb0822cSKashyap, Desai int rc;
6533eb0822cSKashyap, Desai
6543eb0822cSKashyap, Desai rc = mptsas_sas_device_pg0(ioc, &sas_device,
6553eb0822cSKashyap, Desai (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
6563eb0822cSKashyap, Desai MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
6573eb0822cSKashyap, Desai (channel << 8) + id);
6583eb0822cSKashyap, Desai if (rc)
6593eb0822cSKashyap, Desai return;
6603eb0822cSKashyap, Desai
6613eb0822cSKashyap, Desai memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
6623eb0822cSKashyap, Desai mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
6633eb0822cSKashyap, Desai (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
6643eb0822cSKashyap, Desai MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
6653eb0822cSKashyap, Desai sas_device.handle_enclosure);
6663eb0822cSKashyap, Desai
6673eb0822cSKashyap, Desai mptsas_add_device_component(ioc, sas_device.channel,
6683eb0822cSKashyap, Desai sas_device.id, sas_device.sas_address, sas_device.device_info,
6693eb0822cSKashyap, Desai sas_device.slot, enclosure_info.enclosure_logical_id);
6703eb0822cSKashyap, Desai }
6713eb0822cSKashyap, Desai
6723eb0822cSKashyap, Desai /**
673fc847ab4SJames Bottomley * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
674a7938b0bSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
675cdcda465SRandy Dunlap * @starget: SCSI target for this SCSI device
676a7938b0bSKashyap, Desai *
677a7938b0bSKashyap, Desai **/
678a7938b0bSKashyap, Desai static void
mptsas_add_device_component_starget_ir(MPT_ADAPTER * ioc,struct scsi_target * starget)679a7938b0bSKashyap, Desai mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
680a7938b0bSKashyap, Desai struct scsi_target *starget)
681a7938b0bSKashyap, Desai {
682a7938b0bSKashyap, Desai CONFIGPARMS cfg;
683a7938b0bSKashyap, Desai ConfigPageHeader_t hdr;
684a7938b0bSKashyap, Desai dma_addr_t dma_handle;
685a7938b0bSKashyap, Desai pRaidVolumePage0_t buffer = NULL;
686a7938b0bSKashyap, Desai int i;
687a7938b0bSKashyap, Desai RaidPhysDiskPage0_t phys_disk;
688a7938b0bSKashyap, Desai struct mptsas_device_info *sas_info, *next;
689a7938b0bSKashyap, Desai
690a7938b0bSKashyap, Desai memset(&cfg, 0 , sizeof(CONFIGPARMS));
691a7938b0bSKashyap, Desai memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
692a7938b0bSKashyap, Desai hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
693a7938b0bSKashyap, Desai /* assumption that all volumes on channel = 0 */
694a7938b0bSKashyap, Desai cfg.pageAddr = starget->id;
695a7938b0bSKashyap, Desai cfg.cfghdr.hdr = &hdr;
696a7938b0bSKashyap, Desai cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
6974b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
698a7938b0bSKashyap, Desai
699a7938b0bSKashyap, Desai if (mpt_config(ioc, &cfg) != 0)
700a7938b0bSKashyap, Desai goto out;
701a7938b0bSKashyap, Desai
702a7938b0bSKashyap, Desai if (!hdr.PageLength)
703a7938b0bSKashyap, Desai goto out;
704a7938b0bSKashyap, Desai
70576a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4,
70676a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
707a7938b0bSKashyap, Desai
708a7938b0bSKashyap, Desai if (!buffer)
709a7938b0bSKashyap, Desai goto out;
710a7938b0bSKashyap, Desai
711a7938b0bSKashyap, Desai cfg.physAddr = dma_handle;
712a7938b0bSKashyap, Desai cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
713a7938b0bSKashyap, Desai
714a7938b0bSKashyap, Desai if (mpt_config(ioc, &cfg) != 0)
715a7938b0bSKashyap, Desai goto out;
716a7938b0bSKashyap, Desai
717a7938b0bSKashyap, Desai if (!buffer->NumPhysDisks)
718a7938b0bSKashyap, Desai goto out;
719a7938b0bSKashyap, Desai
720a7938b0bSKashyap, Desai /*
721a7938b0bSKashyap, Desai * Adding entry for hidden components
722a7938b0bSKashyap, Desai */
723a7938b0bSKashyap, Desai for (i = 0; i < buffer->NumPhysDisks; i++) {
724a7938b0bSKashyap, Desai
725a7938b0bSKashyap, Desai if (mpt_raid_phys_disk_pg0(ioc,
726a7938b0bSKashyap, Desai buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
727a7938b0bSKashyap, Desai continue;
728a7938b0bSKashyap, Desai
729a7938b0bSKashyap, Desai mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
730a7938b0bSKashyap, Desai phys_disk.PhysDiskID);
731a7938b0bSKashyap, Desai
73257e98513SKashyap, Desai mutex_lock(&ioc->sas_device_info_mutex);
73357e98513SKashyap, Desai list_for_each_entry(sas_info, &ioc->sas_device_info_list,
73457e98513SKashyap, Desai list) {
73557e98513SKashyap, Desai if (!sas_info->is_logical_volume &&
73657e98513SKashyap, Desai (sas_info->fw.channel == phys_disk.PhysDiskBus &&
73757e98513SKashyap, Desai sas_info->fw.id == phys_disk.PhysDiskID)) {
73857e98513SKashyap, Desai sas_info->is_hidden_raid_component = 1;
73957e98513SKashyap, Desai sas_info->volume_id = starget->id;
74057e98513SKashyap, Desai }
74157e98513SKashyap, Desai }
74257e98513SKashyap, Desai mutex_unlock(&ioc->sas_device_info_mutex);
74357e98513SKashyap, Desai
744a7938b0bSKashyap, Desai }
745a7938b0bSKashyap, Desai
746a7938b0bSKashyap, Desai /*
747a7938b0bSKashyap, Desai * Delete all matching devices out of the list
748a7938b0bSKashyap, Desai */
749a7938b0bSKashyap, Desai mutex_lock(&ioc->sas_device_info_mutex);
750a7938b0bSKashyap, Desai list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
751a7938b0bSKashyap, Desai list) {
752a7938b0bSKashyap, Desai if (sas_info->is_logical_volume && sas_info->fw.id ==
753a7938b0bSKashyap, Desai starget->id) {
754a7938b0bSKashyap, Desai list_del(&sas_info->list);
755a7938b0bSKashyap, Desai kfree(sas_info);
756a7938b0bSKashyap, Desai }
757a7938b0bSKashyap, Desai }
758a7938b0bSKashyap, Desai
759a7938b0bSKashyap, Desai sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
760a7938b0bSKashyap, Desai if (sas_info) {
761a7938b0bSKashyap, Desai sas_info->fw.id = starget->id;
762a7938b0bSKashyap, Desai sas_info->os.id = starget->id;
763a7938b0bSKashyap, Desai sas_info->os.channel = starget->channel;
764a7938b0bSKashyap, Desai sas_info->is_logical_volume = 1;
765a7938b0bSKashyap, Desai INIT_LIST_HEAD(&sas_info->list);
766a7938b0bSKashyap, Desai list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
767a7938b0bSKashyap, Desai }
768a7938b0bSKashyap, Desai mutex_unlock(&ioc->sas_device_info_mutex);
769a7938b0bSKashyap, Desai
770a7938b0bSKashyap, Desai out:
771a7938b0bSKashyap, Desai if (buffer)
772b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4,
773b114dda6SChristophe JAILLET buffer, dma_handle);
774a7938b0bSKashyap, Desai }
775a7938b0bSKashyap, Desai
776a7938b0bSKashyap, Desai /**
777cdcda465SRandy Dunlap * mptsas_add_device_component_starget - adds a SCSI target device component
7783eb0822cSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
779cdcda465SRandy Dunlap * @starget: SCSI target for this SCSI device
7803eb0822cSKashyap, Desai *
7813eb0822cSKashyap, Desai **/
7823eb0822cSKashyap, Desai static void
mptsas_add_device_component_starget(MPT_ADAPTER * ioc,struct scsi_target * starget)7833eb0822cSKashyap, Desai mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
7843eb0822cSKashyap, Desai struct scsi_target *starget)
7853eb0822cSKashyap, Desai {
7863eb0822cSKashyap, Desai struct sas_rphy *rphy;
7873eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info = NULL;
7883eb0822cSKashyap, Desai struct mptsas_enclosure enclosure_info;
7893eb0822cSKashyap, Desai
7903eb0822cSKashyap, Desai rphy = dev_to_rphy(starget->dev.parent);
7913eb0822cSKashyap, Desai phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
7923eb0822cSKashyap, Desai rphy->identify.sas_address);
7933eb0822cSKashyap, Desai if (!phy_info)
7943eb0822cSKashyap, Desai return;
7953eb0822cSKashyap, Desai
7963eb0822cSKashyap, Desai memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
7973eb0822cSKashyap, Desai mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
7983eb0822cSKashyap, Desai (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
7993eb0822cSKashyap, Desai MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
8003eb0822cSKashyap, Desai phy_info->attached.handle_enclosure);
8013eb0822cSKashyap, Desai
8023eb0822cSKashyap, Desai mptsas_add_device_component(ioc, phy_info->attached.channel,
8033eb0822cSKashyap, Desai phy_info->attached.id, phy_info->attached.sas_address,
8043eb0822cSKashyap, Desai phy_info->attached.device_info,
8053eb0822cSKashyap, Desai phy_info->attached.slot, enclosure_info.enclosure_logical_id);
8063eb0822cSKashyap, Desai }
8073eb0822cSKashyap, Desai
8083eb0822cSKashyap, Desai /**
809fc847ab4SJames Bottomley * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
81057e98513SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
81157e98513SKashyap, Desai * @channel: os mapped id's
812cdcda465SRandy Dunlap * @id: Logical Target ID
81357e98513SKashyap, Desai *
81457e98513SKashyap, Desai **/
81557e98513SKashyap, Desai static void
mptsas_del_device_component_by_os(MPT_ADAPTER * ioc,u8 channel,u8 id)81657e98513SKashyap, Desai mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
81757e98513SKashyap, Desai {
81857e98513SKashyap, Desai struct mptsas_device_info *sas_info, *next;
81957e98513SKashyap, Desai
82057e98513SKashyap, Desai /*
82157e98513SKashyap, Desai * Set is_cached flag
82257e98513SKashyap, Desai */
82357e98513SKashyap, Desai list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
82457e98513SKashyap, Desai list) {
82557e98513SKashyap, Desai if (sas_info->os.channel == channel && sas_info->os.id == id)
82657e98513SKashyap, Desai sas_info->is_cached = 1;
82757e98513SKashyap, Desai }
82857e98513SKashyap, Desai }
82957e98513SKashyap, Desai
83057e98513SKashyap, Desai /**
8313eb0822cSKashyap, Desai * mptsas_del_device_components - Cleaning the list
8323eb0822cSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
8333eb0822cSKashyap, Desai *
8343eb0822cSKashyap, Desai **/
8353eb0822cSKashyap, Desai static void
mptsas_del_device_components(MPT_ADAPTER * ioc)8363eb0822cSKashyap, Desai mptsas_del_device_components(MPT_ADAPTER *ioc)
8373eb0822cSKashyap, Desai {
8383eb0822cSKashyap, Desai struct mptsas_device_info *sas_info, *next;
8393eb0822cSKashyap, Desai
8403eb0822cSKashyap, Desai mutex_lock(&ioc->sas_device_info_mutex);
8413eb0822cSKashyap, Desai list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
8423eb0822cSKashyap, Desai list) {
8433eb0822cSKashyap, Desai list_del(&sas_info->list);
8443eb0822cSKashyap, Desai kfree(sas_info);
8453eb0822cSKashyap, Desai }
8463eb0822cSKashyap, Desai mutex_unlock(&ioc->sas_device_info_mutex);
8473eb0822cSKashyap, Desai }
8483eb0822cSKashyap, Desai
849547f9a21SEric Moore
850547f9a21SEric Moore /*
851547f9a21SEric Moore * mptsas_setup_wide_ports
852547f9a21SEric Moore *
853547f9a21SEric Moore * Updates for new and existing narrow/wide port configuration
854547f9a21SEric Moore * in the sas_topology
855547f9a21SEric Moore */
856376ac830SEric Moore static void
mptsas_setup_wide_ports(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info)857547f9a21SEric Moore mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
858547f9a21SEric Moore {
859547f9a21SEric Moore struct mptsas_portinfo_details * port_details;
860547f9a21SEric Moore struct mptsas_phyinfo *phy_info, *phy_info_cmp;
861547f9a21SEric Moore u64 sas_address;
862547f9a21SEric Moore int i, j;
863547f9a21SEric Moore
864547f9a21SEric Moore mutex_lock(&ioc->sas_topology_mutex);
865547f9a21SEric Moore
866547f9a21SEric Moore phy_info = port_info->phy_info;
867547f9a21SEric Moore for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
868547f9a21SEric Moore if (phy_info->attached.handle)
869547f9a21SEric Moore continue;
870547f9a21SEric Moore port_details = phy_info->port_details;
871547f9a21SEric Moore if (!port_details)
872547f9a21SEric Moore continue;
873547f9a21SEric Moore if (port_details->num_phys < 2)
874547f9a21SEric Moore continue;
875547f9a21SEric Moore /*
876547f9a21SEric Moore * Removing a phy from a port, letting the last
877547f9a21SEric Moore * phy be removed by firmware events.
878547f9a21SEric Moore */
87929dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
880dc22f16dSEric Moore "%s: [%p]: deleting phy = %d\n",
881cadbd4a5SHarvey Harrison ioc->name, __func__, port_details, i));
882547f9a21SEric Moore port_details->num_phys--;
883547f9a21SEric Moore port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
884547f9a21SEric Moore memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
8859e39089bSKashyap, Desai if (phy_info->phy) {
8869e39089bSKashyap, Desai devtprintk(ioc, dev_printk(KERN_DEBUG,
8879e39089bSKashyap, Desai &phy_info->phy->dev, MYIOC_s_FMT
8889e39089bSKashyap, Desai "delete phy %d, phy-obj (0x%p)\n", ioc->name,
8899e39089bSKashyap, Desai phy_info->phy_id, phy_info->phy));
890547f9a21SEric Moore sas_port_delete_phy(port_details->port, phy_info->phy);
8919e39089bSKashyap, Desai }
892547f9a21SEric Moore phy_info->port_details = NULL;
893547f9a21SEric Moore }
894547f9a21SEric Moore
895547f9a21SEric Moore /*
896547f9a21SEric Moore * Populate and refresh the tree
897547f9a21SEric Moore */
898547f9a21SEric Moore phy_info = port_info->phy_info;
899547f9a21SEric Moore for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
900547f9a21SEric Moore sas_address = phy_info->attached.sas_address;
90129dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
90229dd3609SEric Moore ioc->name, i, (unsigned long long)sas_address));
903547f9a21SEric Moore if (!sas_address)
904547f9a21SEric Moore continue;
905547f9a21SEric Moore port_details = phy_info->port_details;
906547f9a21SEric Moore /*
907547f9a21SEric Moore * Forming a port
908547f9a21SEric Moore */
909547f9a21SEric Moore if (!port_details) {
9102f187862SKashyap, Desai port_details = kzalloc(sizeof(struct
9112f187862SKashyap, Desai mptsas_portinfo_details), GFP_KERNEL);
912547f9a21SEric Moore if (!port_details)
913547f9a21SEric Moore goto out;
914547f9a21SEric Moore port_details->num_phys = 1;
915547f9a21SEric Moore port_details->port_info = port_info;
916547f9a21SEric Moore if (phy_info->phy_id < 64 )
917547f9a21SEric Moore port_details->phy_bitmask |=
918547f9a21SEric Moore (1 << phy_info->phy_id);
919547f9a21SEric Moore phy_info->sas_port_add_phy=1;
92029dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
921547f9a21SEric Moore "phy_id=%d sas_address=0x%018llX\n",
92229dd3609SEric Moore ioc->name, i, (unsigned long long)sas_address));
923547f9a21SEric Moore phy_info->port_details = port_details;
924547f9a21SEric Moore }
925547f9a21SEric Moore
926547f9a21SEric Moore if (i == port_info->num_phys - 1)
927547f9a21SEric Moore continue;
928547f9a21SEric Moore phy_info_cmp = &port_info->phy_info[i + 1];
929547f9a21SEric Moore for (j = i + 1 ; j < port_info->num_phys ; j++,
930547f9a21SEric Moore phy_info_cmp++) {
931547f9a21SEric Moore if (!phy_info_cmp->attached.sas_address)
932547f9a21SEric Moore continue;
933547f9a21SEric Moore if (sas_address != phy_info_cmp->attached.sas_address)
934547f9a21SEric Moore continue;
935547f9a21SEric Moore if (phy_info_cmp->port_details == port_details )
936547f9a21SEric Moore continue;
93729dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
938547f9a21SEric Moore "\t\tphy_id=%d sas_address=0x%018llX\n",
93929dd3609SEric Moore ioc->name, j, (unsigned long long)
940f99be43bSEric Moore phy_info_cmp->attached.sas_address));
941547f9a21SEric Moore if (phy_info_cmp->port_details) {
942547f9a21SEric Moore port_details->rphy =
943547f9a21SEric Moore mptsas_get_rphy(phy_info_cmp);
944547f9a21SEric Moore port_details->port =
945547f9a21SEric Moore mptsas_get_port(phy_info_cmp);
946547f9a21SEric Moore port_details->starget =
947547f9a21SEric Moore mptsas_get_starget(phy_info_cmp);
948547f9a21SEric Moore port_details->num_phys =
949547f9a21SEric Moore phy_info_cmp->port_details->num_phys;
950547f9a21SEric Moore if (!phy_info_cmp->port_details->num_phys)
951547f9a21SEric Moore kfree(phy_info_cmp->port_details);
952547f9a21SEric Moore } else
953547f9a21SEric Moore phy_info_cmp->sas_port_add_phy=1;
954547f9a21SEric Moore /*
955547f9a21SEric Moore * Adding a phy to a port
956547f9a21SEric Moore */
957547f9a21SEric Moore phy_info_cmp->port_details = port_details;
958547f9a21SEric Moore if (phy_info_cmp->phy_id < 64 )
959547f9a21SEric Moore port_details->phy_bitmask |=
960547f9a21SEric Moore (1 << phy_info_cmp->phy_id);
961547f9a21SEric Moore port_details->num_phys++;
962547f9a21SEric Moore }
963547f9a21SEric Moore }
964547f9a21SEric Moore
965547f9a21SEric Moore out:
966547f9a21SEric Moore
967547f9a21SEric Moore for (i = 0; i < port_info->num_phys; i++) {
968547f9a21SEric Moore port_details = port_info->phy_info[i].port_details;
969547f9a21SEric Moore if (!port_details)
970547f9a21SEric Moore continue;
97129dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
972dc22f16dSEric Moore "%s: [%p]: phy_id=%02d num_phys=%02d "
973cadbd4a5SHarvey Harrison "bitmask=0x%016llX\n", ioc->name, __func__,
974dc22f16dSEric Moore port_details, i, port_details->num_phys,
975f99be43bSEric Moore (unsigned long long)port_details->phy_bitmask));
97629dd3609SEric Moore dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
97729dd3609SEric Moore ioc->name, port_details->port, port_details->rphy));
978547f9a21SEric Moore }
97929dd3609SEric Moore dsaswideprintk(ioc, printk("\n"));
980547f9a21SEric Moore mutex_unlock(&ioc->sas_topology_mutex);
981547f9a21SEric Moore }
982547f9a21SEric Moore
983df9e062aSEric Moore /**
984cdcda465SRandy Dunlap * mptsas_find_vtarget - find a virtual target device (FC LUN device or
985cdcda465SRandy Dunlap * SCSI target device)
986df9e062aSEric Moore *
987cdcda465SRandy Dunlap * @ioc: Pointer to MPT_ADAPTER structure
988cdcda465SRandy Dunlap * @channel: channel number
989cdcda465SRandy Dunlap * @id: Logical Target ID
990df9e062aSEric Moore *
991df9e062aSEric Moore **/
992df9e062aSEric Moore static VirtTarget *
mptsas_find_vtarget(MPT_ADAPTER * ioc,u8 channel,u8 id)993df9e062aSEric Moore mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
994df9e062aSEric Moore {
995df9e062aSEric Moore struct scsi_device *sdev;
996a69de507SEric Moore VirtDevice *vdevice;
997df9e062aSEric Moore VirtTarget *vtarget = NULL;
998df9e062aSEric Moore
999df9e062aSEric Moore shost_for_each_device(sdev, ioc->sh) {
1000e7deff33SKashyap, Desai vdevice = sdev->hostdata;
1001e7deff33SKashyap, Desai if ((vdevice == NULL) ||
1002e7deff33SKashyap, Desai (vdevice->vtarget == NULL))
1003df9e062aSEric Moore continue;
1004a7938b0bSKashyap, Desai if ((vdevice->vtarget->tflags &
1005a7938b0bSKashyap, Desai MPT_TARGET_FLAGS_RAID_COMPONENT ||
1006a7938b0bSKashyap, Desai vdevice->vtarget->raidVolume))
1007a7938b0bSKashyap, Desai continue;
1008a69de507SEric Moore if (vdevice->vtarget->id == id &&
1009a69de507SEric Moore vdevice->vtarget->channel == channel)
1010a69de507SEric Moore vtarget = vdevice->vtarget;
1011df9e062aSEric Moore }
1012df9e062aSEric Moore return vtarget;
1013df9e062aSEric Moore }
1014df9e062aSEric Moore
10153eb0822cSKashyap, Desai static void
mptsas_queue_device_delete(MPT_ADAPTER * ioc,MpiEventDataSasDeviceStatusChange_t * sas_event_data)10163eb0822cSKashyap, Desai mptsas_queue_device_delete(MPT_ADAPTER *ioc,
10173eb0822cSKashyap, Desai MpiEventDataSasDeviceStatusChange_t *sas_event_data)
10183eb0822cSKashyap, Desai {
10193eb0822cSKashyap, Desai struct fw_event_work *fw_event;
10203eb0822cSKashyap, Desai
102132696198SJoe Lawrence fw_event = kzalloc(sizeof(*fw_event) +
102232696198SJoe Lawrence sizeof(MpiEventDataSasDeviceStatusChange_t),
102332696198SJoe Lawrence GFP_ATOMIC);
10243eb0822cSKashyap, Desai if (!fw_event) {
10253eb0822cSKashyap, Desai printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
10263eb0822cSKashyap, Desai ioc->name, __func__, __LINE__);
10273eb0822cSKashyap, Desai return;
10283eb0822cSKashyap, Desai }
10293eb0822cSKashyap, Desai memcpy(fw_event->event_data, sas_event_data,
10303eb0822cSKashyap, Desai sizeof(MpiEventDataSasDeviceStatusChange_t));
10313eb0822cSKashyap, Desai fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
10323eb0822cSKashyap, Desai fw_event->ioc = ioc;
10333eb0822cSKashyap, Desai mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
10343eb0822cSKashyap, Desai }
10353eb0822cSKashyap, Desai
1036eedf92b9SKashyap, Desai static void
mptsas_queue_rescan(MPT_ADAPTER * ioc)1037eedf92b9SKashyap, Desai mptsas_queue_rescan(MPT_ADAPTER *ioc)
1038eedf92b9SKashyap, Desai {
1039eedf92b9SKashyap, Desai struct fw_event_work *fw_event;
1040eedf92b9SKashyap, Desai
104132696198SJoe Lawrence fw_event = kzalloc(sizeof(*fw_event), GFP_ATOMIC);
1042eedf92b9SKashyap, Desai if (!fw_event) {
1043eedf92b9SKashyap, Desai printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1044eedf92b9SKashyap, Desai ioc->name, __func__, __LINE__);
1045eedf92b9SKashyap, Desai return;
1046eedf92b9SKashyap, Desai }
1047eedf92b9SKashyap, Desai fw_event->event = -1;
1048eedf92b9SKashyap, Desai fw_event->ioc = ioc;
1049eedf92b9SKashyap, Desai mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1050eedf92b9SKashyap, Desai }
1051eedf92b9SKashyap, Desai
10523eb0822cSKashyap, Desai
1053df9e062aSEric Moore /**
1054cdcda465SRandy Dunlap * mptsas_target_reset - Issues TARGET_RESET to end device using
1055cdcda465SRandy Dunlap * handshaking method
1056df9e062aSEric Moore *
1057cdcda465SRandy Dunlap * @ioc: Pointer to MPT_ADAPTER structure
1058cdcda465SRandy Dunlap * @channel: channel number
1059cdcda465SRandy Dunlap * @id: Logical Target ID for reset
1060df9e062aSEric Moore *
1061cdcda465SRandy Dunlap * Return: (1) success
1062df9e062aSEric Moore * (0) failure
1063df9e062aSEric Moore *
1064df9e062aSEric Moore **/
1065df9e062aSEric Moore static int
mptsas_target_reset(MPT_ADAPTER * ioc,u8 channel,u8 id)1066df9e062aSEric Moore mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1067df9e062aSEric Moore {
1068df9e062aSEric Moore MPT_FRAME_HDR *mf;
1069df9e062aSEric Moore SCSITaskMgmt_t *pScsiTm;
1070ea2a788dSKashyap, Desai if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1071ea2a788dSKashyap, Desai return 0;
1072ea2a788dSKashyap, Desai
1073df9e062aSEric Moore
1074e7deff33SKashyap, Desai mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1075e7deff33SKashyap, Desai if (mf == NULL) {
1076e7deff33SKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1077ea2a788dSKashyap, Desai "%s, no msg frames @%d!!\n", ioc->name,
1078ea2a788dSKashyap, Desai __func__, __LINE__));
1079ea2a788dSKashyap, Desai goto out_fail;
1080df9e062aSEric Moore }
1081df9e062aSEric Moore
1082ea2a788dSKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1083ea2a788dSKashyap, Desai ioc->name, mf));
1084ea2a788dSKashyap, Desai
1085df9e062aSEric Moore /* Format the Request
1086df9e062aSEric Moore */
1087df9e062aSEric Moore pScsiTm = (SCSITaskMgmt_t *) mf;
1088df9e062aSEric Moore memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1089df9e062aSEric Moore pScsiTm->TargetID = id;
1090df9e062aSEric Moore pScsiTm->Bus = channel;
1091df9e062aSEric Moore pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1092df9e062aSEric Moore pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1093df9e062aSEric Moore pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1094df9e062aSEric Moore
1095d6ecdd63SPrakash, Sathya DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
1096df9e062aSEric Moore
1097ea2a788dSKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1098ea2a788dSKashyap, Desai "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1099ea2a788dSKashyap, Desai ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1100ea2a788dSKashyap, Desai
1101e7deff33SKashyap, Desai mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
1102df9e062aSEric Moore
1103df9e062aSEric Moore return 1;
1104ea2a788dSKashyap, Desai
1105ea2a788dSKashyap, Desai out_fail:
1106ea2a788dSKashyap, Desai
1107ea2a788dSKashyap, Desai mpt_clear_taskmgmt_in_progress_flag(ioc);
1108ea2a788dSKashyap, Desai return 0;
1109df9e062aSEric Moore }
1110df9e062aSEric Moore
111164e155adSKashyap, Desai static void
mptsas_block_io_sdev(struct scsi_device * sdev,void * data)111264e155adSKashyap, Desai mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
111364e155adSKashyap, Desai {
111464e155adSKashyap, Desai scsi_device_set_state(sdev, SDEV_BLOCK);
111564e155adSKashyap, Desai }
111664e155adSKashyap, Desai
111764e155adSKashyap, Desai static void
mptsas_block_io_starget(struct scsi_target * starget)111864e155adSKashyap, Desai mptsas_block_io_starget(struct scsi_target *starget)
111964e155adSKashyap, Desai {
112064e155adSKashyap, Desai if (starget)
112164e155adSKashyap, Desai starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
112264e155adSKashyap, Desai }
112364e155adSKashyap, Desai
1124df9e062aSEric Moore /**
1125cdcda465SRandy Dunlap * mptsas_target_reset_queue - queue a target reset
1126df9e062aSEric Moore *
1127cdcda465SRandy Dunlap * @ioc: Pointer to MPT_ADAPTER structure
1128cdcda465SRandy Dunlap * @sas_event_data: SAS Device Status Change Event data
1129cdcda465SRandy Dunlap *
1130cdcda465SRandy Dunlap * Receive request for TARGET_RESET after receiving a firmware
1131df9e062aSEric Moore * event NOT_RESPONDING_EVENT, then put command in link list
1132df9e062aSEric Moore * and queue if task_queue already in use.
1133df9e062aSEric Moore *
1134df9e062aSEric Moore **/
1135547f9a21SEric Moore static void
mptsas_target_reset_queue(MPT_ADAPTER * ioc,EVENT_DATA_SAS_DEVICE_STATUS_CHANGE * sas_event_data)1136df9e062aSEric Moore mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1137df9e062aSEric Moore EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1138547f9a21SEric Moore {
1139e7eae9f6SEric Moore MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1140df9e062aSEric Moore VirtTarget *vtarget = NULL;
1141df9e062aSEric Moore struct mptsas_target_reset_event *target_reset_list;
1142df9e062aSEric Moore u8 id, channel;
1143547f9a21SEric Moore
1144df9e062aSEric Moore id = sas_event_data->TargetID;
1145df9e062aSEric Moore channel = sas_event_data->Bus;
1146df9e062aSEric Moore
114764e155adSKashyap, Desai vtarget = mptsas_find_vtarget(ioc, channel, id);
114864e155adSKashyap, Desai if (vtarget) {
114964e155adSKashyap, Desai mptsas_block_io_starget(vtarget->starget);
1150df9e062aSEric Moore vtarget->deleted = 1; /* block IO */
115164e155adSKashyap, Desai }
1152df9e062aSEric Moore
11532f187862SKashyap, Desai target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
1154df9e062aSEric Moore GFP_ATOMIC);
1155df9e062aSEric Moore if (!target_reset_list) {
1156e7deff33SKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1157e7deff33SKashyap, Desai "%s, failed to allocate mem @%d..!!\n",
1158cadbd4a5SHarvey Harrison ioc->name, __func__, __LINE__));
1159df9e062aSEric Moore return;
1160547f9a21SEric Moore }
1161df9e062aSEric Moore
1162df9e062aSEric Moore memcpy(&target_reset_list->sas_event_data, sas_event_data,
1163df9e062aSEric Moore sizeof(*sas_event_data));
1164df9e062aSEric Moore list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1165df9e062aSEric Moore
1166e7deff33SKashyap, Desai target_reset_list->time_count = jiffies;
1167df9e062aSEric Moore
1168df9e062aSEric Moore if (mptsas_target_reset(ioc, channel, id)) {
1169df9e062aSEric Moore target_reset_list->target_reset_issued = 1;
1170df9e062aSEric Moore }
1171df9e062aSEric Moore }
1172df9e062aSEric Moore
1173df9e062aSEric Moore /**
1174b68bf096SKashyap, Desai * mptsas_schedule_target_reset- send pending target reset
1175b68bf096SKashyap, Desai * @iocp: per adapter object
1176b68bf096SKashyap, Desai *
1177b68bf096SKashyap, Desai * This function will delete scheduled target reset from the list and
1178b68bf096SKashyap, Desai * try to send next target reset. This will be called from completion
1179b595076aSUwe Kleine-König * context of any Task management command.
1180b68bf096SKashyap, Desai */
1181b68bf096SKashyap, Desai
1182b68bf096SKashyap, Desai void
mptsas_schedule_target_reset(void * iocp)1183b68bf096SKashyap, Desai mptsas_schedule_target_reset(void *iocp)
1184b68bf096SKashyap, Desai {
1185b68bf096SKashyap, Desai MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
1186b68bf096SKashyap, Desai MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1187b68bf096SKashyap, Desai struct list_head *head = &hd->target_reset_list;
1188b68bf096SKashyap, Desai struct mptsas_target_reset_event *target_reset_list;
1189b68bf096SKashyap, Desai u8 id, channel;
1190b68bf096SKashyap, Desai /*
1191b68bf096SKashyap, Desai * issue target reset to next device in the queue
1192b68bf096SKashyap, Desai */
1193b68bf096SKashyap, Desai
1194b68bf096SKashyap, Desai if (list_empty(head))
1195b68bf096SKashyap, Desai return;
1196b68bf096SKashyap, Desai
1197b68bf096SKashyap, Desai target_reset_list = list_entry(head->next,
1198b68bf096SKashyap, Desai struct mptsas_target_reset_event, list);
1199b68bf096SKashyap, Desai
1200b68bf096SKashyap, Desai id = target_reset_list->sas_event_data.TargetID;
1201b68bf096SKashyap, Desai channel = target_reset_list->sas_event_data.Bus;
1202b68bf096SKashyap, Desai target_reset_list->time_count = jiffies;
1203b68bf096SKashyap, Desai
1204b68bf096SKashyap, Desai if (mptsas_target_reset(ioc, channel, id))
1205b68bf096SKashyap, Desai target_reset_list->target_reset_issued = 1;
1206b68bf096SKashyap, Desai return;
1207b68bf096SKashyap, Desai }
1208b68bf096SKashyap, Desai
1209b68bf096SKashyap, Desai
1210b68bf096SKashyap, Desai /**
1211fc847ab4SJames Bottomley * mptsas_taskmgmt_complete - complete SAS task management function
1212e7deff33SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
1213cdcda465SRandy Dunlap * @mf: MPT message frame
1214cdcda465SRandy Dunlap * @mr: SCSI Task Management Reply structure ptr (may be %NULL)
1215df9e062aSEric Moore *
1216fc847ab4SJames Bottomley * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1217cdcda465SRandy Dunlap * queue to finish off removing device from upper layers, then send next
1218fc847ab4SJames Bottomley * TARGET_RESET in the queue.
1219df9e062aSEric Moore **/
1220e7deff33SKashyap, Desai static int
mptsas_taskmgmt_complete(MPT_ADAPTER * ioc,MPT_FRAME_HDR * mf,MPT_FRAME_HDR * mr)1221e7deff33SKashyap, Desai mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
1222df9e062aSEric Moore {
1223e7eae9f6SEric Moore MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1224df9e062aSEric Moore struct list_head *head = &hd->target_reset_list;
1225df9e062aSEric Moore u8 id, channel;
1226e7deff33SKashyap, Desai struct mptsas_target_reset_event *target_reset_list;
1227e7deff33SKashyap, Desai SCSITaskMgmtReply_t *pScsiTmReply;
1228e7deff33SKashyap, Desai
1229e7deff33SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1230e7deff33SKashyap, Desai "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1231e7deff33SKashyap, Desai
1232e7deff33SKashyap, Desai pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
12339f21316fSJoe Lawrence if (!pScsiTmReply)
12349f21316fSJoe Lawrence return 0;
12359f21316fSJoe Lawrence
1236e7deff33SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1237e7deff33SKashyap, Desai "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1238e7deff33SKashyap, Desai "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1239e7deff33SKashyap, Desai "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1240e7deff33SKashyap, Desai "term_cmnds = %d\n", ioc->name,
1241e7deff33SKashyap, Desai pScsiTmReply->Bus, pScsiTmReply->TargetID,
1242e7deff33SKashyap, Desai pScsiTmReply->TaskType,
1243e7deff33SKashyap, Desai le16_to_cpu(pScsiTmReply->IOCStatus),
1244e7deff33SKashyap, Desai le32_to_cpu(pScsiTmReply->IOCLogInfo),
1245e7deff33SKashyap, Desai pScsiTmReply->ResponseCode,
1246e7deff33SKashyap, Desai le32_to_cpu(pScsiTmReply->TerminationCount)));
1247e7deff33SKashyap, Desai
1248e7deff33SKashyap, Desai if (pScsiTmReply->ResponseCode)
1249e7deff33SKashyap, Desai mptscsih_taskmgmt_response_code(ioc,
1250e7deff33SKashyap, Desai pScsiTmReply->ResponseCode);
1251e7deff33SKashyap, Desai
12529f21316fSJoe Lawrence if (pScsiTmReply->TaskType ==
1253e7deff33SKashyap, Desai MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
12549f21316fSJoe Lawrence MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET) {
1255e7deff33SKashyap, Desai ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1256e7deff33SKashyap, Desai ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1257e7deff33SKashyap, Desai memcpy(ioc->taskmgmt_cmds.reply, mr,
1258e7deff33SKashyap, Desai min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1259e7deff33SKashyap, Desai if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1260e7deff33SKashyap, Desai ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1261e7deff33SKashyap, Desai complete(&ioc->taskmgmt_cmds.done);
1262e7deff33SKashyap, Desai return 1;
1263e7deff33SKashyap, Desai }
1264e7deff33SKashyap, Desai return 0;
1265e7deff33SKashyap, Desai }
1266e7deff33SKashyap, Desai
1267e7deff33SKashyap, Desai mpt_clear_taskmgmt_in_progress_flag(ioc);
1268df9e062aSEric Moore
1269df9e062aSEric Moore if (list_empty(head))
1270e7deff33SKashyap, Desai return 1;
1271df9e062aSEric Moore
1272e7deff33SKashyap, Desai target_reset_list = list_entry(head->next,
1273e7deff33SKashyap, Desai struct mptsas_target_reset_event, list);
1274e7deff33SKashyap, Desai
1275e7deff33SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1276e7deff33SKashyap, Desai "TaskMgmt: completed (%d seconds)\n",
1277e7deff33SKashyap, Desai ioc->name, jiffies_to_msecs(jiffies -
1278e7deff33SKashyap, Desai target_reset_list->time_count)/1000));
1279df9e062aSEric Moore
1280e7deff33SKashyap, Desai id = pScsiTmReply->TargetID;
1281e7deff33SKashyap, Desai channel = pScsiTmReply->Bus;
1282e7deff33SKashyap, Desai target_reset_list->time_count = jiffies;
1283df9e062aSEric Moore
1284df9e062aSEric Moore /*
1285df9e062aSEric Moore * retry target reset
1286df9e062aSEric Moore */
1287df9e062aSEric Moore if (!target_reset_list->target_reset_issued) {
1288e7deff33SKashyap, Desai if (mptsas_target_reset(ioc, channel, id))
1289df9e062aSEric Moore target_reset_list->target_reset_issued = 1;
1290e7deff33SKashyap, Desai return 1;
1291df9e062aSEric Moore }
1292df9e062aSEric Moore
1293df9e062aSEric Moore /*
1294df9e062aSEric Moore * enable work queue to remove device from upper layers
1295df9e062aSEric Moore */
1296df9e062aSEric Moore list_del(&target_reset_list->list);
12973e84bebaSKei Tokunaga if (!ioc->fw_events_off)
12983eb0822cSKashyap, Desai mptsas_queue_device_delete(ioc,
12993eb0822cSKashyap, Desai &target_reset_list->sas_event_data);
1300ea2a788dSKashyap, Desai
1301e7deff33SKashyap, Desai
1302b68bf096SKashyap, Desai ioc->schedule_target_reset(ioc);
1303df9e062aSEric Moore
1304e7deff33SKashyap, Desai return 1;
1305df9e062aSEric Moore }
1306df9e062aSEric Moore
1307df9e062aSEric Moore /**
1308cdcda465SRandy Dunlap * mptsas_ioc_reset - issue an IOC reset for this reset phase
1309df9e062aSEric Moore *
1310cdcda465SRandy Dunlap * @ioc: Pointer to MPT_ADAPTER structure
1311cdcda465SRandy Dunlap * @reset_phase: id of phase of reset
1312df9e062aSEric Moore *
1313df9e062aSEric Moore **/
1314df9e062aSEric Moore static int
mptsas_ioc_reset(MPT_ADAPTER * ioc,int reset_phase)1315df9e062aSEric Moore mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1316df9e062aSEric Moore {
1317ba76ef24SJudith Lebzelter MPT_SCSI_HOST *hd;
1318df9e062aSEric Moore int rc;
1319df9e062aSEric Moore
1320df9e062aSEric Moore rc = mptscsih_ioc_reset(ioc, reset_phase);
13213eb0822cSKashyap, Desai if ((ioc->bus_type != SAS) || (!rc))
13223eb0822cSKashyap, Desai return rc;
1323df9e062aSEric Moore
1324e7eae9f6SEric Moore hd = shost_priv(ioc->sh);
1325ba76ef24SJudith Lebzelter if (!hd->ioc)
1326df9e062aSEric Moore goto out;
1327df9e062aSEric Moore
13283eb0822cSKashyap, Desai switch (reset_phase) {
13293eb0822cSKashyap, Desai case MPT_IOC_SETUP_RESET:
13303eb0822cSKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
13313eb0822cSKashyap, Desai "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
13323eb0822cSKashyap, Desai mptsas_fw_event_off(ioc);
13333eb0822cSKashyap, Desai break;
13343eb0822cSKashyap, Desai case MPT_IOC_PRE_RESET:
13353eb0822cSKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
13363eb0822cSKashyap, Desai "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
13373eb0822cSKashyap, Desai break;
13383eb0822cSKashyap, Desai case MPT_IOC_POST_RESET:
13393eb0822cSKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
13403eb0822cSKashyap, Desai "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
13413eb0822cSKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
13423eb0822cSKashyap, Desai ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
13433eb0822cSKashyap, Desai complete(&ioc->sas_mgmt.done);
13443eb0822cSKashyap, Desai }
13453eb0822cSKashyap, Desai mptsas_cleanup_fw_event_q(ioc);
1346eedf92b9SKashyap, Desai mptsas_queue_rescan(ioc);
13473eb0822cSKashyap, Desai break;
13483eb0822cSKashyap, Desai default:
13493eb0822cSKashyap, Desai break;
1350df9e062aSEric Moore }
1351df9e062aSEric Moore
1352df9e062aSEric Moore out:
1353df9e062aSEric Moore return rc;
1354547f9a21SEric Moore }
1355547f9a21SEric Moore
13563eb0822cSKashyap, Desai
13573eb0822cSKashyap, Desai /**
1358cdcda465SRandy Dunlap * enum device_state - TUR device state
13593eb0822cSKashyap, Desai * @DEVICE_RETRY: need to retry the TUR
13603eb0822cSKashyap, Desai * @DEVICE_ERROR: TUR return error, don't add device
13613eb0822cSKashyap, Desai * @DEVICE_READY: device can be added
13623eb0822cSKashyap, Desai *
13633eb0822cSKashyap, Desai */
13643eb0822cSKashyap, Desai enum device_state{
13653eb0822cSKashyap, Desai DEVICE_RETRY,
13663eb0822cSKashyap, Desai DEVICE_ERROR,
13673eb0822cSKashyap, Desai DEVICE_READY,
13683eb0822cSKashyap, Desai };
13693eb0822cSKashyap, Desai
1370e3094447SChristoph Hellwig static int
mptsas_sas_enclosure_pg0(MPT_ADAPTER * ioc,struct mptsas_enclosure * enclosure,u32 form,u32 form_specific)137152435430SMoore, Eric mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
1372e3094447SChristoph Hellwig u32 form, u32 form_specific)
1373e3094447SChristoph Hellwig {
1374e3094447SChristoph Hellwig ConfigExtendedPageHeader_t hdr;
1375e3094447SChristoph Hellwig CONFIGPARMS cfg;
1376e3094447SChristoph Hellwig SasEnclosurePage0_t *buffer;
1377e3094447SChristoph Hellwig dma_addr_t dma_handle;
1378e3094447SChristoph Hellwig int error;
1379e3094447SChristoph Hellwig __le64 le_identifier;
1380e3094447SChristoph Hellwig
1381e3094447SChristoph Hellwig memset(&hdr, 0, sizeof(hdr));
1382e3094447SChristoph Hellwig hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1383e3094447SChristoph Hellwig hdr.PageNumber = 0;
1384e3094447SChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1385e3094447SChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1386e3094447SChristoph Hellwig
1387e3094447SChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
1388e3094447SChristoph Hellwig cfg.physAddr = -1;
1389e3094447SChristoph Hellwig cfg.pageAddr = form + form_specific;
1390e3094447SChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1391e3094447SChristoph Hellwig cfg.dir = 0; /* read */
13924b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
1393e3094447SChristoph Hellwig
1394e3094447SChristoph Hellwig error = mpt_config(ioc, &cfg);
1395e3094447SChristoph Hellwig if (error)
1396e3094447SChristoph Hellwig goto out;
1397e3094447SChristoph Hellwig if (!hdr.ExtPageLength) {
1398e3094447SChristoph Hellwig error = -ENXIO;
1399e3094447SChristoph Hellwig goto out;
1400e3094447SChristoph Hellwig }
1401e3094447SChristoph Hellwig
140276a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
140376a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
1404e3094447SChristoph Hellwig if (!buffer) {
1405e3094447SChristoph Hellwig error = -ENOMEM;
1406e3094447SChristoph Hellwig goto out;
1407e3094447SChristoph Hellwig }
1408e3094447SChristoph Hellwig
1409e3094447SChristoph Hellwig cfg.physAddr = dma_handle;
1410e3094447SChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1411e3094447SChristoph Hellwig
1412e3094447SChristoph Hellwig error = mpt_config(ioc, &cfg);
1413e3094447SChristoph Hellwig if (error)
1414e3094447SChristoph Hellwig goto out_free_consistent;
1415e3094447SChristoph Hellwig
1416e3094447SChristoph Hellwig /* save config data */
1417e3094447SChristoph Hellwig memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1418e3094447SChristoph Hellwig enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1419e3094447SChristoph Hellwig enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1420e3094447SChristoph Hellwig enclosure->flags = le16_to_cpu(buffer->Flags);
1421e3094447SChristoph Hellwig enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1422e3094447SChristoph Hellwig enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1423e3094447SChristoph Hellwig enclosure->start_id = buffer->StartTargetID;
1424e3094447SChristoph Hellwig enclosure->start_channel = buffer->StartBus;
1425e3094447SChristoph Hellwig enclosure->sep_id = buffer->SEPTargetID;
1426e3094447SChristoph Hellwig enclosure->sep_channel = buffer->SEPBus;
1427e3094447SChristoph Hellwig
1428e3094447SChristoph Hellwig out_free_consistent:
1429b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
1430b114dda6SChristophe JAILLET dma_handle);
1431e3094447SChristoph Hellwig out:
1432e3094447SChristoph Hellwig return error;
1433e3094447SChristoph Hellwig }
1434b5141128SChristoph Hellwig
14353eb0822cSKashyap, Desai /**
14363eb0822cSKashyap, Desai * mptsas_add_end_device - report a new end device to sas transport layer
14373eb0822cSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
143825985edcSLucas De Marchi * @phy_info: describes attached device
14393eb0822cSKashyap, Desai *
14403eb0822cSKashyap, Desai * return (0) success (1) failure
14413eb0822cSKashyap, Desai *
14423eb0822cSKashyap, Desai **/
14433eb0822cSKashyap, Desai static int
mptsas_add_end_device(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info)14443eb0822cSKashyap, Desai mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
14453eb0822cSKashyap, Desai {
14463eb0822cSKashyap, Desai struct sas_rphy *rphy;
14473eb0822cSKashyap, Desai struct sas_port *port;
14483eb0822cSKashyap, Desai struct sas_identify identify;
14493eb0822cSKashyap, Desai char *ds = NULL;
14503eb0822cSKashyap, Desai u8 fw_id;
14513eb0822cSKashyap, Desai
14523eb0822cSKashyap, Desai if (!phy_info) {
14533eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
14543eb0822cSKashyap, Desai "%s: exit at line=%d\n", ioc->name,
14553eb0822cSKashyap, Desai __func__, __LINE__));
14563eb0822cSKashyap, Desai return 1;
14573eb0822cSKashyap, Desai }
14583eb0822cSKashyap, Desai
14593eb0822cSKashyap, Desai fw_id = phy_info->attached.id;
14603eb0822cSKashyap, Desai
14613eb0822cSKashyap, Desai if (mptsas_get_rphy(phy_info)) {
14623eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
14633eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
14643eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
14653eb0822cSKashyap, Desai return 2;
14663eb0822cSKashyap, Desai }
14673eb0822cSKashyap, Desai
14683eb0822cSKashyap, Desai port = mptsas_get_port(phy_info);
14693eb0822cSKashyap, Desai if (!port) {
14703eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
14713eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
14723eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
14733eb0822cSKashyap, Desai return 3;
14743eb0822cSKashyap, Desai }
14753eb0822cSKashyap, Desai
14763eb0822cSKashyap, Desai if (phy_info->attached.device_info &
14773eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_SSP_TARGET)
14783eb0822cSKashyap, Desai ds = "ssp";
14793eb0822cSKashyap, Desai if (phy_info->attached.device_info &
14803eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_STP_TARGET)
14813eb0822cSKashyap, Desai ds = "stp";
14823eb0822cSKashyap, Desai if (phy_info->attached.device_info &
14833eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_SATA_DEVICE)
14843eb0822cSKashyap, Desai ds = "sata";
14853eb0822cSKashyap, Desai
14863eb0822cSKashyap, Desai printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
14873eb0822cSKashyap, Desai " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
14883eb0822cSKashyap, Desai phy_info->attached.channel, phy_info->attached.id,
14893eb0822cSKashyap, Desai phy_info->attached.phy_id, (unsigned long long)
14903eb0822cSKashyap, Desai phy_info->attached.sas_address);
14913eb0822cSKashyap, Desai
14923eb0822cSKashyap, Desai mptsas_parse_device_info(&identify, &phy_info->attached);
14933eb0822cSKashyap, Desai rphy = sas_end_device_alloc(port);
14943eb0822cSKashyap, Desai if (!rphy) {
14953eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
14963eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
14973eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
14983eb0822cSKashyap, Desai return 5; /* non-fatal: an rphy can be added later */
14993eb0822cSKashyap, Desai }
15003eb0822cSKashyap, Desai
15013eb0822cSKashyap, Desai rphy->identify = identify;
15023eb0822cSKashyap, Desai if (sas_rphy_add(rphy)) {
15033eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
15043eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
15053eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
15063eb0822cSKashyap, Desai sas_rphy_free(rphy);
15073eb0822cSKashyap, Desai return 6;
15083eb0822cSKashyap, Desai }
15093eb0822cSKashyap, Desai mptsas_set_rphy(ioc, phy_info, rphy);
15103eb0822cSKashyap, Desai return 0;
15113eb0822cSKashyap, Desai }
15123eb0822cSKashyap, Desai
15133eb0822cSKashyap, Desai /**
1514fc847ab4SJames Bottomley * mptsas_del_end_device - report a deleted end device to sas transport layer
15153eb0822cSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
151625985edcSLucas De Marchi * @phy_info: describes attached device
15173eb0822cSKashyap, Desai *
15183eb0822cSKashyap, Desai **/
15193eb0822cSKashyap, Desai static void
mptsas_del_end_device(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info)15203eb0822cSKashyap, Desai mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
15213eb0822cSKashyap, Desai {
15223eb0822cSKashyap, Desai struct sas_rphy *rphy;
15233eb0822cSKashyap, Desai struct sas_port *port;
15243eb0822cSKashyap, Desai struct mptsas_portinfo *port_info;
15253eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info_parent;
15263eb0822cSKashyap, Desai int i;
15273eb0822cSKashyap, Desai char *ds = NULL;
15283eb0822cSKashyap, Desai u8 fw_id;
15293eb0822cSKashyap, Desai u64 sas_address;
15303eb0822cSKashyap, Desai
15313eb0822cSKashyap, Desai if (!phy_info)
15323eb0822cSKashyap, Desai return;
15333eb0822cSKashyap, Desai
15343eb0822cSKashyap, Desai fw_id = phy_info->attached.id;
15353eb0822cSKashyap, Desai sas_address = phy_info->attached.sas_address;
15363eb0822cSKashyap, Desai
15373eb0822cSKashyap, Desai if (!phy_info->port_details) {
15383eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
15393eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
15403eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
15413eb0822cSKashyap, Desai return;
15423eb0822cSKashyap, Desai }
15433eb0822cSKashyap, Desai rphy = mptsas_get_rphy(phy_info);
15443eb0822cSKashyap, Desai if (!rphy) {
15453eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
15463eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
15473eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
15483eb0822cSKashyap, Desai return;
15493eb0822cSKashyap, Desai }
15503eb0822cSKashyap, Desai
15513eb0822cSKashyap, Desai if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
15523eb0822cSKashyap, Desai || phy_info->attached.device_info
15533eb0822cSKashyap, Desai & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
15543eb0822cSKashyap, Desai || phy_info->attached.device_info
15553eb0822cSKashyap, Desai & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
15563eb0822cSKashyap, Desai ds = "initiator";
15573eb0822cSKashyap, Desai if (phy_info->attached.device_info &
15583eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_SSP_TARGET)
15593eb0822cSKashyap, Desai ds = "ssp";
15603eb0822cSKashyap, Desai if (phy_info->attached.device_info &
15613eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_STP_TARGET)
15623eb0822cSKashyap, Desai ds = "stp";
15633eb0822cSKashyap, Desai if (phy_info->attached.device_info &
15643eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_SATA_DEVICE)
15653eb0822cSKashyap, Desai ds = "sata";
15663eb0822cSKashyap, Desai
15673eb0822cSKashyap, Desai dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
15683eb0822cSKashyap, Desai "removing %s device: fw_channel %d, fw_id %d, phy %d,"
15693eb0822cSKashyap, Desai "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
15703eb0822cSKashyap, Desai phy_info->attached.id, phy_info->attached.phy_id,
15713eb0822cSKashyap, Desai (unsigned long long) sas_address);
15723eb0822cSKashyap, Desai
15733eb0822cSKashyap, Desai port = mptsas_get_port(phy_info);
15743eb0822cSKashyap, Desai if (!port) {
15753eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
15763eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
15773eb0822cSKashyap, Desai __func__, fw_id, __LINE__));
15783eb0822cSKashyap, Desai return;
15793eb0822cSKashyap, Desai }
15803eb0822cSKashyap, Desai port_info = phy_info->portinfo;
15813eb0822cSKashyap, Desai phy_info_parent = port_info->phy_info;
15823eb0822cSKashyap, Desai for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
15833eb0822cSKashyap, Desai if (!phy_info_parent->phy)
15843eb0822cSKashyap, Desai continue;
15853eb0822cSKashyap, Desai if (phy_info_parent->attached.sas_address !=
15863eb0822cSKashyap, Desai sas_address)
15873eb0822cSKashyap, Desai continue;
15883eb0822cSKashyap, Desai dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
15893eb0822cSKashyap, Desai MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
15903eb0822cSKashyap, Desai ioc->name, phy_info_parent->phy_id,
15913eb0822cSKashyap, Desai phy_info_parent->phy);
15923eb0822cSKashyap, Desai sas_port_delete_phy(port, phy_info_parent->phy);
15933eb0822cSKashyap, Desai }
15943eb0822cSKashyap, Desai
15953eb0822cSKashyap, Desai dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
15963eb0822cSKashyap, Desai "delete port %d, sas_addr (0x%llx)\n", ioc->name,
15973eb0822cSKashyap, Desai port->port_identifier, (unsigned long long)sas_address);
15983eb0822cSKashyap, Desai sas_port_delete(port);
15993eb0822cSKashyap, Desai mptsas_set_port(ioc, phy_info, NULL);
16003eb0822cSKashyap, Desai mptsas_port_delete(ioc, phy_info->port_details);
16013eb0822cSKashyap, Desai }
16023eb0822cSKashyap, Desai
16035767d25fSJoe Lawrence static struct mptsas_phyinfo *
mptsas_refreshing_device_handles(MPT_ADAPTER * ioc,struct mptsas_devinfo * sas_device)16043eb0822cSKashyap, Desai mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
16053eb0822cSKashyap, Desai struct mptsas_devinfo *sas_device)
16063eb0822cSKashyap, Desai {
16073eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info;
16083eb0822cSKashyap, Desai struct mptsas_portinfo *port_info;
16093eb0822cSKashyap, Desai int i;
16103eb0822cSKashyap, Desai
16113eb0822cSKashyap, Desai phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
16123eb0822cSKashyap, Desai sas_device->sas_address);
16133eb0822cSKashyap, Desai if (!phy_info)
16143eb0822cSKashyap, Desai goto out;
16153eb0822cSKashyap, Desai port_info = phy_info->portinfo;
16163eb0822cSKashyap, Desai if (!port_info)
16173eb0822cSKashyap, Desai goto out;
16183eb0822cSKashyap, Desai mutex_lock(&ioc->sas_topology_mutex);
16193eb0822cSKashyap, Desai for (i = 0; i < port_info->num_phys; i++) {
16203eb0822cSKashyap, Desai if (port_info->phy_info[i].attached.sas_address !=
16213eb0822cSKashyap, Desai sas_device->sas_address)
16223eb0822cSKashyap, Desai continue;
16233eb0822cSKashyap, Desai port_info->phy_info[i].attached.channel = sas_device->channel;
16243eb0822cSKashyap, Desai port_info->phy_info[i].attached.id = sas_device->id;
16253eb0822cSKashyap, Desai port_info->phy_info[i].attached.sas_address =
16263eb0822cSKashyap, Desai sas_device->sas_address;
16273eb0822cSKashyap, Desai port_info->phy_info[i].attached.handle = sas_device->handle;
16283eb0822cSKashyap, Desai port_info->phy_info[i].attached.handle_parent =
16293eb0822cSKashyap, Desai sas_device->handle_parent;
16303eb0822cSKashyap, Desai port_info->phy_info[i].attached.handle_enclosure =
16313eb0822cSKashyap, Desai sas_device->handle_enclosure;
16323eb0822cSKashyap, Desai }
16333eb0822cSKashyap, Desai mutex_unlock(&ioc->sas_topology_mutex);
16343eb0822cSKashyap, Desai out:
16353eb0822cSKashyap, Desai return phy_info;
16363eb0822cSKashyap, Desai }
16373eb0822cSKashyap, Desai
16383eb0822cSKashyap, Desai /**
16393eb0822cSKashyap, Desai * mptsas_firmware_event_work - work thread for processing fw events
16403eb0822cSKashyap, Desai * @work: work queue payload containing info describing the event
16413eb0822cSKashyap, Desai * Context: user
16423eb0822cSKashyap, Desai *
16433eb0822cSKashyap, Desai */
16443eb0822cSKashyap, Desai static void
mptsas_firmware_event_work(struct work_struct * work)16453eb0822cSKashyap, Desai mptsas_firmware_event_work(struct work_struct *work)
16463eb0822cSKashyap, Desai {
16473eb0822cSKashyap, Desai struct fw_event_work *fw_event =
16483eb0822cSKashyap, Desai container_of(work, struct fw_event_work, work.work);
16493eb0822cSKashyap, Desai MPT_ADAPTER *ioc = fw_event->ioc;
16503eb0822cSKashyap, Desai
1651eedf92b9SKashyap, Desai /* special rescan topology handling */
1652eedf92b9SKashyap, Desai if (fw_event->event == -1) {
1653eedf92b9SKashyap, Desai if (ioc->in_rescan) {
1654eedf92b9SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1655eedf92b9SKashyap, Desai "%s: rescan ignored as it is in progress\n",
1656eedf92b9SKashyap, Desai ioc->name, __func__));
1657eedf92b9SKashyap, Desai return;
1658eedf92b9SKashyap, Desai }
1659eedf92b9SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1660eedf92b9SKashyap, Desai "reset\n", ioc->name, __func__));
1661eedf92b9SKashyap, Desai ioc->in_rescan = 1;
1662eedf92b9SKashyap, Desai mptsas_not_responding_devices(ioc);
1663eedf92b9SKashyap, Desai mptsas_scan_sas_topology(ioc);
1664eedf92b9SKashyap, Desai ioc->in_rescan = 0;
1665eedf92b9SKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
16669766096dSKashyap, Desai mptsas_fw_event_on(ioc);
1667eedf92b9SKashyap, Desai return;
1668eedf92b9SKashyap, Desai }
16693eb0822cSKashyap, Desai
16703eb0822cSKashyap, Desai /* events handling turned off during host reset */
16713eb0822cSKashyap, Desai if (ioc->fw_events_off) {
16723eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
16733eb0822cSKashyap, Desai return;
16743eb0822cSKashyap, Desai }
16753eb0822cSKashyap, Desai
16763eb0822cSKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
16773eb0822cSKashyap, Desai "event = (0x%02x)\n", ioc->name, __func__, fw_event,
16783eb0822cSKashyap, Desai (fw_event->event & 0xFF)));
16793eb0822cSKashyap, Desai
16803eb0822cSKashyap, Desai switch (fw_event->event) {
16813eb0822cSKashyap, Desai case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
16823eb0822cSKashyap, Desai mptsas_send_sas_event(fw_event);
16833eb0822cSKashyap, Desai break;
16843eb0822cSKashyap, Desai case MPI_EVENT_INTEGRATED_RAID:
16853eb0822cSKashyap, Desai mptsas_send_raid_event(fw_event);
16863eb0822cSKashyap, Desai break;
16873eb0822cSKashyap, Desai case MPI_EVENT_IR2:
16883eb0822cSKashyap, Desai mptsas_send_ir2_event(fw_event);
16893eb0822cSKashyap, Desai break;
16903eb0822cSKashyap, Desai case MPI_EVENT_PERSISTENT_TABLE_FULL:
16913eb0822cSKashyap, Desai mptbase_sas_persist_operation(ioc,
16923eb0822cSKashyap, Desai MPI_SAS_OP_CLEAR_NOT_PRESENT);
16933eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
16943eb0822cSKashyap, Desai break;
1695db7051b2SKashyap, Desai case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
169694e989deSColin Ian King mptsas_broadcast_primitive_work(fw_event);
1697db7051b2SKashyap, Desai break;
1698f9c34022SKashyap, Desai case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1699f9c34022SKashyap, Desai mptsas_send_expander_event(fw_event);
1700f9c34022SKashyap, Desai break;
1701f9c34022SKashyap, Desai case MPI_EVENT_SAS_PHY_LINK_STATUS:
1702f9c34022SKashyap, Desai mptsas_send_link_status_event(fw_event);
1703f9c34022SKashyap, Desai break;
170457e98513SKashyap, Desai case MPI_EVENT_QUEUE_FULL:
170557e98513SKashyap, Desai mptsas_handle_queue_full_event(fw_event);
170657e98513SKashyap, Desai break;
17073eb0822cSKashyap, Desai }
17083eb0822cSKashyap, Desai }
17093eb0822cSKashyap, Desai
17103eb0822cSKashyap, Desai
17113eb0822cSKashyap, Desai
1712f013db32SJames Bottomley static int
mptsas_slave_configure(struct scsi_device * sdev)1713f013db32SJames Bottomley mptsas_slave_configure(struct scsi_device *sdev)
1714f013db32SJames Bottomley {
17153eb0822cSKashyap, Desai struct Scsi_Host *host = sdev->host;
17163eb0822cSKashyap, Desai MPT_SCSI_HOST *hd = shost_priv(host);
17173eb0822cSKashyap, Desai MPT_ADAPTER *ioc = hd->ioc;
1718a7938b0bSKashyap, Desai VirtDevice *vdevice = sdev->hostdata;
17193c0c25b9SMoore, Eric
1720a7938b0bSKashyap, Desai if (vdevice->vtarget->deleted) {
1721a7938b0bSKashyap, Desai sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1722a7938b0bSKashyap, Desai vdevice->vtarget->deleted = 0;
1723a7938b0bSKashyap, Desai }
1724a7938b0bSKashyap, Desai
1725a7938b0bSKashyap, Desai /*
1726a7938b0bSKashyap, Desai * RAID volumes placed beyond the last expected port.
1727a7938b0bSKashyap, Desai * Ignore sending sas mode pages in that case..
1728a7938b0bSKashyap, Desai */
1729a7938b0bSKashyap, Desai if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1730a7938b0bSKashyap, Desai mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
1731e8bf3941SJames Bottomley goto out;
1732a7938b0bSKashyap, Desai }
1733e8bf3941SJames Bottomley
1734f013db32SJames Bottomley sas_read_port_mode_page(sdev);
1735f013db32SJames Bottomley
17363eb0822cSKashyap, Desai mptsas_add_device_component_starget(ioc, scsi_target(sdev));
17373eb0822cSKashyap, Desai
1738e8bf3941SJames Bottomley out:
1739f013db32SJames Bottomley return mptscsih_slave_configure(sdev);
1740f013db32SJames Bottomley }
1741f013db32SJames Bottomley
1742547f9a21SEric Moore static int
mptsas_target_alloc(struct scsi_target * starget)1743547f9a21SEric Moore mptsas_target_alloc(struct scsi_target *starget)
1744547f9a21SEric Moore {
1745547f9a21SEric Moore struct Scsi_Host *host = dev_to_shost(&starget->dev);
1746e7eae9f6SEric Moore MPT_SCSI_HOST *hd = shost_priv(host);
1747547f9a21SEric Moore VirtTarget *vtarget;
1748793955f5SEric Moore u8 id, channel;
1749547f9a21SEric Moore struct sas_rphy *rphy;
1750547f9a21SEric Moore struct mptsas_portinfo *p;
1751547f9a21SEric Moore int i;
1752e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
1753547f9a21SEric Moore
1754547f9a21SEric Moore vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1755547f9a21SEric Moore if (!vtarget)
1756547f9a21SEric Moore return -ENOMEM;
1757547f9a21SEric Moore
1758547f9a21SEric Moore vtarget->starget = starget;
1759e80b002bSEric Moore vtarget->ioc_id = ioc->id;
1760793955f5SEric Moore vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1761793955f5SEric Moore id = starget->id;
1762547f9a21SEric Moore channel = 0;
1763547f9a21SEric Moore
1764793955f5SEric Moore /*
1765793955f5SEric Moore * RAID volumes placed beyond the last expected port.
1766793955f5SEric Moore */
1767793955f5SEric Moore if (starget->channel == MPTSAS_RAID_CHANNEL) {
1768a7938b0bSKashyap, Desai if (!ioc->raid_data.pIocPg2) {
1769a7938b0bSKashyap, Desai kfree(vtarget);
1770a7938b0bSKashyap, Desai return -ENXIO;
1771a7938b0bSKashyap, Desai }
1772a7938b0bSKashyap, Desai for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1773a7938b0bSKashyap, Desai if (id == ioc->raid_data.pIocPg2->
1774a7938b0bSKashyap, Desai RaidVolume[i].VolumeID) {
1775a7938b0bSKashyap, Desai channel = ioc->raid_data.pIocPg2->
1776a7938b0bSKashyap, Desai RaidVolume[i].VolumeBus;
1777a7938b0bSKashyap, Desai }
1778a7938b0bSKashyap, Desai }
1779a7938b0bSKashyap, Desai vtarget->raidVolume = 1;
1780547f9a21SEric Moore goto out;
1781793955f5SEric Moore }
1782547f9a21SEric Moore
1783547f9a21SEric Moore rphy = dev_to_rphy(starget->dev.parent);
1784e80b002bSEric Moore mutex_lock(&ioc->sas_topology_mutex);
1785e80b002bSEric Moore list_for_each_entry(p, &ioc->sas_topology, list) {
1786547f9a21SEric Moore for (i = 0; i < p->num_phys; i++) {
1787547f9a21SEric Moore if (p->phy_info[i].attached.sas_address !=
1788547f9a21SEric Moore rphy->identify.sas_address)
1789547f9a21SEric Moore continue;
1790793955f5SEric Moore id = p->phy_info[i].attached.id;
1791547f9a21SEric Moore channel = p->phy_info[i].attached.channel;
1792547f9a21SEric Moore mptsas_set_starget(&p->phy_info[i], starget);
1793547f9a21SEric Moore
1794547f9a21SEric Moore /*
1795547f9a21SEric Moore * Exposing hidden raid components
1796547f9a21SEric Moore */
1797e80b002bSEric Moore if (mptscsih_is_phys_disk(ioc, channel, id)) {
1798e80b002bSEric Moore id = mptscsih_raid_id_to_num(ioc,
1799793955f5SEric Moore channel, id);
1800547f9a21SEric Moore vtarget->tflags |=
1801547f9a21SEric Moore MPT_TARGET_FLAGS_RAID_COMPONENT;
1802b506ade9SEric Moore p->phy_info[i].attached.phys_disk_num = id;
1803547f9a21SEric Moore }
1804e80b002bSEric Moore mutex_unlock(&ioc->sas_topology_mutex);
1805547f9a21SEric Moore goto out;
1806547f9a21SEric Moore }
1807547f9a21SEric Moore }
1808e80b002bSEric Moore mutex_unlock(&ioc->sas_topology_mutex);
1809547f9a21SEric Moore
1810547f9a21SEric Moore kfree(vtarget);
1811547f9a21SEric Moore return -ENXIO;
1812547f9a21SEric Moore
1813547f9a21SEric Moore out:
1814793955f5SEric Moore vtarget->id = id;
1815793955f5SEric Moore vtarget->channel = channel;
1816547f9a21SEric Moore starget->hostdata = vtarget;
1817547f9a21SEric Moore return 0;
1818547f9a21SEric Moore }
1819547f9a21SEric Moore
1820547f9a21SEric Moore static void
mptsas_target_destroy(struct scsi_target * starget)1821547f9a21SEric Moore mptsas_target_destroy(struct scsi_target *starget)
1822547f9a21SEric Moore {
1823547f9a21SEric Moore struct Scsi_Host *host = dev_to_shost(&starget->dev);
1824e7eae9f6SEric Moore MPT_SCSI_HOST *hd = shost_priv(host);
1825547f9a21SEric Moore struct sas_rphy *rphy;
1826547f9a21SEric Moore struct mptsas_portinfo *p;
1827547f9a21SEric Moore int i;
1828e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
18293eb0822cSKashyap, Desai VirtTarget *vtarget;
1830547f9a21SEric Moore
1831547f9a21SEric Moore if (!starget->hostdata)
1832547f9a21SEric Moore return;
1833547f9a21SEric Moore
18343eb0822cSKashyap, Desai vtarget = starget->hostdata;
18353eb0822cSKashyap, Desai
183657e98513SKashyap, Desai mptsas_del_device_component_by_os(ioc, starget->channel,
183757e98513SKashyap, Desai starget->id);
183857e98513SKashyap, Desai
18393eb0822cSKashyap, Desai
1840e8bf3941SJames Bottomley if (starget->channel == MPTSAS_RAID_CHANNEL)
1841547f9a21SEric Moore goto out;
1842547f9a21SEric Moore
1843547f9a21SEric Moore rphy = dev_to_rphy(starget->dev.parent);
1844e80b002bSEric Moore list_for_each_entry(p, &ioc->sas_topology, list) {
1845547f9a21SEric Moore for (i = 0; i < p->num_phys; i++) {
1846547f9a21SEric Moore if (p->phy_info[i].attached.sas_address !=
1847547f9a21SEric Moore rphy->identify.sas_address)
1848547f9a21SEric Moore continue;
18493eb0822cSKashyap, Desai
18503eb0822cSKashyap, Desai starget_printk(KERN_INFO, starget, MYIOC_s_FMT
18513eb0822cSKashyap, Desai "delete device: fw_channel %d, fw_id %d, phy %d, "
18523eb0822cSKashyap, Desai "sas_addr 0x%llx\n", ioc->name,
18533eb0822cSKashyap, Desai p->phy_info[i].attached.channel,
18543eb0822cSKashyap, Desai p->phy_info[i].attached.id,
18553eb0822cSKashyap, Desai p->phy_info[i].attached.phy_id, (unsigned long long)
18563eb0822cSKashyap, Desai p->phy_info[i].attached.sas_address);
18573eb0822cSKashyap, Desai
1858547f9a21SEric Moore mptsas_set_starget(&p->phy_info[i], NULL);
1859547f9a21SEric Moore }
1860547f9a21SEric Moore }
1861547f9a21SEric Moore
1862547f9a21SEric Moore out:
18633eb0822cSKashyap, Desai vtarget->starget = NULL;
1864547f9a21SEric Moore kfree(starget->hostdata);
1865547f9a21SEric Moore starget->hostdata = NULL;
1866547f9a21SEric Moore }
1867547f9a21SEric Moore
1868547f9a21SEric Moore
18690c33b27dSChristoph Hellwig static int
mptsas_slave_alloc(struct scsi_device * sdev)1870c7c82987SMoore, Eric Dean mptsas_slave_alloc(struct scsi_device *sdev)
18710c33b27dSChristoph Hellwig {
1872c7c82987SMoore, Eric Dean struct Scsi_Host *host = sdev->host;
1873e7eae9f6SEric Moore MPT_SCSI_HOST *hd = shost_priv(host);
18740c33b27dSChristoph Hellwig struct sas_rphy *rphy;
18750c33b27dSChristoph Hellwig struct mptsas_portinfo *p;
1876a69de507SEric Moore VirtDevice *vdevice;
1877c7c82987SMoore, Eric Dean struct scsi_target *starget;
18780c33b27dSChristoph Hellwig int i;
1879e80b002bSEric Moore MPT_ADAPTER *ioc = hd->ioc;
18800c33b27dSChristoph Hellwig
1881a69de507SEric Moore vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1882a69de507SEric Moore if (!vdevice) {
1883547f9a21SEric Moore printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
1884e80b002bSEric Moore ioc->name, sizeof(VirtDevice));
18850c33b27dSChristoph Hellwig return -ENOMEM;
18860c33b27dSChristoph Hellwig }
1887c7c82987SMoore, Eric Dean starget = scsi_target(sdev);
1888a69de507SEric Moore vdevice->vtarget = starget->hostdata;
18890c33b27dSChristoph Hellwig
1890e8bf3941SJames Bottomley if (sdev->channel == MPTSAS_RAID_CHANNEL)
1891816aa907SMoore, Eric goto out;
1892816aa907SMoore, Eric
1893c7c82987SMoore, Eric Dean rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
1894e80b002bSEric Moore mutex_lock(&ioc->sas_topology_mutex);
1895e80b002bSEric Moore list_for_each_entry(p, &ioc->sas_topology, list) {
18960c33b27dSChristoph Hellwig for (i = 0; i < p->num_phys; i++) {
1897547f9a21SEric Moore if (p->phy_info[i].attached.sas_address !=
1898547f9a21SEric Moore rphy->identify.sas_address)
1899547f9a21SEric Moore continue;
1900a69de507SEric Moore vdevice->lun = sdev->lun;
1901f44e5461SMoore, Eric /*
1902547f9a21SEric Moore * Exposing hidden raid components
1903f44e5461SMoore, Eric */
1904e80b002bSEric Moore if (mptscsih_is_phys_disk(ioc,
1905793955f5SEric Moore p->phy_info[i].attached.channel,
1906547f9a21SEric Moore p->phy_info[i].attached.id))
1907f44e5461SMoore, Eric sdev->no_uld_attach = 1;
1908e80b002bSEric Moore mutex_unlock(&ioc->sas_topology_mutex);
19090c33b27dSChristoph Hellwig goto out;
19100c33b27dSChristoph Hellwig }
19110c33b27dSChristoph Hellwig }
1912e80b002bSEric Moore mutex_unlock(&ioc->sas_topology_mutex);
19130c33b27dSChristoph Hellwig
1914a69de507SEric Moore kfree(vdevice);
191523f236edSChristoph Hellwig return -ENXIO;
19160c33b27dSChristoph Hellwig
19170c33b27dSChristoph Hellwig out:
1918a69de507SEric Moore vdevice->vtarget->num_luns++;
1919a69de507SEric Moore sdev->hostdata = vdevice;
19200c33b27dSChristoph Hellwig return 0;
19210c33b27dSChristoph Hellwig }
19220c33b27dSChristoph Hellwig
1923547f9a21SEric Moore static int
mptsas_qcmd(struct Scsi_Host * shost,struct scsi_cmnd * SCpnt)1924a48ac9e5SMatthew Wilcox mptsas_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *SCpnt)
19259a28f49aSChristoph Hellwig {
19267b5a65b9SKashyap, Desai MPT_SCSI_HOST *hd;
19277b5a65b9SKashyap, Desai MPT_ADAPTER *ioc;
1928a69de507SEric Moore VirtDevice *vdevice = SCpnt->device->hostdata;
19299a28f49aSChristoph Hellwig
1930a69de507SEric Moore if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
1931547f9a21SEric Moore SCpnt->result = DID_NO_CONNECT << 16;
19321ae6d167SBart Van Assche scsi_done(SCpnt);
1933547f9a21SEric Moore return 0;
1934547f9a21SEric Moore }
19357d3eecf7SMoore, Eric
1936a48ac9e5SMatthew Wilcox hd = shost_priv(shost);
19377b5a65b9SKashyap, Desai ioc = hd->ioc;
19387b5a65b9SKashyap, Desai
19397b5a65b9SKashyap, Desai if (ioc->sas_discovery_quiesce_io)
19407b5a65b9SKashyap, Desai return SCSI_MLQUEUE_HOST_BUSY;
19417b5a65b9SKashyap, Desai
194264e155adSKashyap, Desai if (ioc->debug_level & MPT_DEBUG_SCSI)
194364e155adSKashyap, Desai scsi_print_command(SCpnt);
1944793955f5SEric Moore
1945a48ac9e5SMatthew Wilcox return mptscsih_qcmd(SCpnt);
1946547f9a21SEric Moore }
19477d3eecf7SMoore, Eric
1948c9de7dc4SKashyap, Desai /**
1949cdcda465SRandy Dunlap * mptsas_eh_timed_out - resets the scsi_cmnd timeout
1950c9de7dc4SKashyap, Desai * if the device under question is currently in the
1951c9de7dc4SKashyap, Desai * device removal delay.
1952c9de7dc4SKashyap, Desai * @sc: scsi command that the midlayer is about to time out
1953c9de7dc4SKashyap, Desai *
1954c9de7dc4SKashyap, Desai **/
mptsas_eh_timed_out(struct scsi_cmnd * sc)1955dee7121eSBart Van Assche static enum scsi_timeout_action mptsas_eh_timed_out(struct scsi_cmnd *sc)
1956c9de7dc4SKashyap, Desai {
1957c9de7dc4SKashyap, Desai MPT_SCSI_HOST *hd;
1958c9de7dc4SKashyap, Desai MPT_ADAPTER *ioc;
1959c9de7dc4SKashyap, Desai VirtDevice *vdevice;
1960dee7121eSBart Van Assche enum scsi_timeout_action rc = SCSI_EH_NOT_HANDLED;
1961c9de7dc4SKashyap, Desai
1962c9de7dc4SKashyap, Desai hd = shost_priv(sc->device->host);
1963c9de7dc4SKashyap, Desai if (hd == NULL) {
1964c9de7dc4SKashyap, Desai printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
1965c9de7dc4SKashyap, Desai __func__, sc);
1966c9de7dc4SKashyap, Desai goto done;
1967c9de7dc4SKashyap, Desai }
1968c9de7dc4SKashyap, Desai
1969c9de7dc4SKashyap, Desai ioc = hd->ioc;
1970c9de7dc4SKashyap, Desai if (ioc->bus_type != SAS) {
1971c9de7dc4SKashyap, Desai printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
1972c9de7dc4SKashyap, Desai __func__, sc);
1973c9de7dc4SKashyap, Desai goto done;
1974c9de7dc4SKashyap, Desai }
1975c9de7dc4SKashyap, Desai
197698cbe371Skashyap.desai@lsi.com /* In case if IOC is in reset from internal context.
197798cbe371Skashyap.desai@lsi.com * Do not execute EEH for the same IOC. SML should to reset timer.
197898cbe371Skashyap.desai@lsi.com */
197998cbe371Skashyap.desai@lsi.com if (ioc->ioc_reset_in_progress) {
198098cbe371Skashyap.desai@lsi.com dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: ioc is in reset,"
198198cbe371Skashyap.desai@lsi.com "SML need to reset the timer (sc=%p)\n",
198298cbe371Skashyap.desai@lsi.com ioc->name, __func__, sc));
1983dee7121eSBart Van Assche rc = SCSI_EH_RESET_TIMER;
198498cbe371Skashyap.desai@lsi.com }
1985c9de7dc4SKashyap, Desai vdevice = sc->device->hostdata;
1986c9de7dc4SKashyap, Desai if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
1987c9de7dc4SKashyap, Desai || vdevice->vtarget->deleted)) {
1988c9de7dc4SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
1989c9de7dc4SKashyap, Desai "or in device removal delay (sc=%p)\n",
1990c9de7dc4SKashyap, Desai ioc->name, __func__, sc));
1991dee7121eSBart Van Assche rc = SCSI_EH_RESET_TIMER;
1992c9de7dc4SKashyap, Desai goto done;
1993c9de7dc4SKashyap, Desai }
1994c9de7dc4SKashyap, Desai
1995c9de7dc4SKashyap, Desai done:
1996c9de7dc4SKashyap, Desai return rc;
1997c9de7dc4SKashyap, Desai }
1998c9de7dc4SKashyap, Desai
19999a28f49aSChristoph Hellwig
200095a24cf1SBart Van Assche static const struct scsi_host_template mptsas_driver_template = {
2001f78496daSMoore, Eric Dean .module = THIS_MODULE,
20020c33b27dSChristoph Hellwig .proc_name = "mptsas",
2003cac19703SAl Viro .show_info = mptscsih_show_info,
2004568da769SKashyap, Desai .name = "MPT SAS Host",
20050c33b27dSChristoph Hellwig .info = mptscsih_info,
2006547f9a21SEric Moore .queuecommand = mptsas_qcmd,
2007547f9a21SEric Moore .target_alloc = mptsas_target_alloc,
20080c33b27dSChristoph Hellwig .slave_alloc = mptsas_slave_alloc,
2009f013db32SJames Bottomley .slave_configure = mptsas_slave_configure,
2010547f9a21SEric Moore .target_destroy = mptsas_target_destroy,
2011547f9a21SEric Moore .slave_destroy = mptscsih_slave_destroy,
20120c33b27dSChristoph Hellwig .change_queue_depth = mptscsih_change_queue_depth,
2013b6a05c82SChristoph Hellwig .eh_timed_out = mptsas_eh_timed_out,
20140c33b27dSChristoph Hellwig .eh_abort_handler = mptscsih_abort,
20150c33b27dSChristoph Hellwig .eh_device_reset_handler = mptscsih_dev_reset,
20160c33b27dSChristoph Hellwig .eh_host_reset_handler = mptscsih_host_reset,
20170c33b27dSChristoph Hellwig .bios_param = mptscsih_bios_param,
20189d2e9d66SKashyap, Desai .can_queue = MPT_SAS_CAN_QUEUE,
20190c33b27dSChristoph Hellwig .this_id = -1,
20200c33b27dSChristoph Hellwig .sg_tablesize = MPT_SCSI_SG_DEPTH,
20210c33b27dSChristoph Hellwig .max_sectors = 8192,
20220c33b27dSChristoph Hellwig .cmd_per_lun = 7,
20232899836fSBart Van Assche .shost_groups = mptscsih_host_attr_groups,
202494e5395dSMartin K. Petersen .no_write_same = 1,
20250c33b27dSChristoph Hellwig };
20260c33b27dSChristoph Hellwig
mptsas_get_linkerrors(struct sas_phy * phy)2027b5141128SChristoph Hellwig static int mptsas_get_linkerrors(struct sas_phy *phy)
2028b5141128SChristoph Hellwig {
2029b5141128SChristoph Hellwig MPT_ADAPTER *ioc = phy_to_ioc(phy);
2030b5141128SChristoph Hellwig ConfigExtendedPageHeader_t hdr;
2031b5141128SChristoph Hellwig CONFIGPARMS cfg;
2032b5141128SChristoph Hellwig SasPhyPage1_t *buffer;
2033b5141128SChristoph Hellwig dma_addr_t dma_handle;
2034b5141128SChristoph Hellwig int error;
2035b5141128SChristoph Hellwig
2036f4ad7b58SJames Bottomley /* FIXME: only have link errors on local phys */
2037f4ad7b58SJames Bottomley if (!scsi_is_sas_phy_local(phy))
2038f4ad7b58SJames Bottomley return -EINVAL;
2039f4ad7b58SJames Bottomley
2040b5141128SChristoph Hellwig hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
2041b5141128SChristoph Hellwig hdr.ExtPageLength = 0;
2042b5141128SChristoph Hellwig hdr.PageNumber = 1 /* page number 1*/;
2043b5141128SChristoph Hellwig hdr.Reserved1 = 0;
2044b5141128SChristoph Hellwig hdr.Reserved2 = 0;
2045b5141128SChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2046b5141128SChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2047b5141128SChristoph Hellwig
2048b5141128SChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
2049b5141128SChristoph Hellwig cfg.physAddr = -1;
2050b5141128SChristoph Hellwig cfg.pageAddr = phy->identify.phy_identifier;
2051b5141128SChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2052b5141128SChristoph Hellwig cfg.dir = 0; /* read */
20534b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2054b5141128SChristoph Hellwig
2055b5141128SChristoph Hellwig error = mpt_config(ioc, &cfg);
2056b5141128SChristoph Hellwig if (error)
2057b5141128SChristoph Hellwig return error;
2058b5141128SChristoph Hellwig if (!hdr.ExtPageLength)
2059b5141128SChristoph Hellwig return -ENXIO;
2060b5141128SChristoph Hellwig
206176a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
206276a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
2063b5141128SChristoph Hellwig if (!buffer)
2064b5141128SChristoph Hellwig return -ENOMEM;
2065b5141128SChristoph Hellwig
2066b5141128SChristoph Hellwig cfg.physAddr = dma_handle;
2067b5141128SChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2068b5141128SChristoph Hellwig
2069b5141128SChristoph Hellwig error = mpt_config(ioc, &cfg);
2070b5141128SChristoph Hellwig if (error)
2071b5141128SChristoph Hellwig goto out_free_consistent;
2072b5141128SChristoph Hellwig
2073d6ecdd63SPrakash, Sathya mptsas_print_phy_pg1(ioc, buffer);
2074b5141128SChristoph Hellwig
2075b5141128SChristoph Hellwig phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
2076b5141128SChristoph Hellwig phy->running_disparity_error_count =
2077b5141128SChristoph Hellwig le32_to_cpu(buffer->RunningDisparityErrorCount);
2078b5141128SChristoph Hellwig phy->loss_of_dword_sync_count =
2079b5141128SChristoph Hellwig le32_to_cpu(buffer->LossDwordSynchCount);
2080b5141128SChristoph Hellwig phy->phy_reset_problem_count =
2081b5141128SChristoph Hellwig le32_to_cpu(buffer->PhyResetProblemCount);
2082b5141128SChristoph Hellwig
2083b5141128SChristoph Hellwig out_free_consistent:
2084b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2085b114dda6SChristophe JAILLET dma_handle);
2086b5141128SChristoph Hellwig return error;
2087b5141128SChristoph Hellwig }
2088b5141128SChristoph Hellwig
mptsas_mgmt_done(MPT_ADAPTER * ioc,MPT_FRAME_HDR * req,MPT_FRAME_HDR * reply)2089da4fa655SChristoph Hellwig static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2090da4fa655SChristoph Hellwig MPT_FRAME_HDR *reply)
2091da4fa655SChristoph Hellwig {
2092f0f09d3bSKashyap, Desai ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
2093da4fa655SChristoph Hellwig if (reply != NULL) {
2094f0f09d3bSKashyap, Desai ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
2095da4fa655SChristoph Hellwig memcpy(ioc->sas_mgmt.reply, reply,
2096da4fa655SChristoph Hellwig min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
2097da4fa655SChristoph Hellwig }
20982f187862SKashyap, Desai
20992f187862SKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
21002f187862SKashyap, Desai ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
2101da4fa655SChristoph Hellwig complete(&ioc->sas_mgmt.done);
2102da4fa655SChristoph Hellwig return 1;
2103da4fa655SChristoph Hellwig }
21042f187862SKashyap, Desai return 0;
21052f187862SKashyap, Desai }
2106da4fa655SChristoph Hellwig
mptsas_phy_reset(struct sas_phy * phy,int hard_reset)2107da4fa655SChristoph Hellwig static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2108da4fa655SChristoph Hellwig {
2109da4fa655SChristoph Hellwig MPT_ADAPTER *ioc = phy_to_ioc(phy);
2110da4fa655SChristoph Hellwig SasIoUnitControlRequest_t *req;
2111da4fa655SChristoph Hellwig SasIoUnitControlReply_t *reply;
2112da4fa655SChristoph Hellwig MPT_FRAME_HDR *mf;
2113da4fa655SChristoph Hellwig MPIHeader_t *hdr;
2114da4fa655SChristoph Hellwig unsigned long timeleft;
2115da4fa655SChristoph Hellwig int error = -ERESTARTSYS;
2116da4fa655SChristoph Hellwig
2117f4ad7b58SJames Bottomley /* FIXME: fusion doesn't allow non-local phy reset */
2118f4ad7b58SJames Bottomley if (!scsi_is_sas_phy_local(phy))
2119f4ad7b58SJames Bottomley return -EINVAL;
2120f4ad7b58SJames Bottomley
2121da4fa655SChristoph Hellwig /* not implemented for expanders */
2122da4fa655SChristoph Hellwig if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2123da4fa655SChristoph Hellwig return -ENXIO;
2124da4fa655SChristoph Hellwig
2125eeb846ceSChristoph Hellwig if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
2126da4fa655SChristoph Hellwig goto out;
2127da4fa655SChristoph Hellwig
2128da4fa655SChristoph Hellwig mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2129da4fa655SChristoph Hellwig if (!mf) {
2130da4fa655SChristoph Hellwig error = -ENOMEM;
2131da4fa655SChristoph Hellwig goto out_unlock;
2132da4fa655SChristoph Hellwig }
2133da4fa655SChristoph Hellwig
2134da4fa655SChristoph Hellwig hdr = (MPIHeader_t *) mf;
2135da4fa655SChristoph Hellwig req = (SasIoUnitControlRequest_t *)mf;
2136da4fa655SChristoph Hellwig memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2137da4fa655SChristoph Hellwig req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2138da4fa655SChristoph Hellwig req->MsgContext = hdr->MsgContext;
2139da4fa655SChristoph Hellwig req->Operation = hard_reset ?
2140da4fa655SChristoph Hellwig MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2141da4fa655SChristoph Hellwig req->PhyNum = phy->identify.phy_identifier;
2142da4fa655SChristoph Hellwig
21432f187862SKashyap, Desai INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2144da4fa655SChristoph Hellwig mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2145da4fa655SChristoph Hellwig
2146da4fa655SChristoph Hellwig timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2147da4fa655SChristoph Hellwig 10 * HZ);
2148568da769SKashyap, Desai if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2149568da769SKashyap, Desai error = -ETIME;
2150da4fa655SChristoph Hellwig mpt_free_msg_frame(ioc, mf);
2151568da769SKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2152568da769SKashyap, Desai goto out_unlock;
2153568da769SKashyap, Desai if (!timeleft)
2154d0f698c4SKashyap, Desai mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
2155da4fa655SChristoph Hellwig goto out_unlock;
2156da4fa655SChristoph Hellwig }
2157da4fa655SChristoph Hellwig
2158da4fa655SChristoph Hellwig /* a reply frame is expected */
2159da4fa655SChristoph Hellwig if ((ioc->sas_mgmt.status &
2160f0f09d3bSKashyap, Desai MPT_MGMT_STATUS_RF_VALID) == 0) {
2161da4fa655SChristoph Hellwig error = -ENXIO;
2162da4fa655SChristoph Hellwig goto out_unlock;
2163da4fa655SChristoph Hellwig }
2164da4fa655SChristoph Hellwig
2165da4fa655SChristoph Hellwig /* process the completed Reply Message Frame */
2166da4fa655SChristoph Hellwig reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2167da4fa655SChristoph Hellwig if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
216829dd3609SEric Moore printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
2169cadbd4a5SHarvey Harrison ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
2170da4fa655SChristoph Hellwig error = -ENXIO;
2171da4fa655SChristoph Hellwig goto out_unlock;
2172da4fa655SChristoph Hellwig }
2173da4fa655SChristoph Hellwig
2174da4fa655SChristoph Hellwig error = 0;
2175da4fa655SChristoph Hellwig
2176da4fa655SChristoph Hellwig out_unlock:
21772f187862SKashyap, Desai CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2178eeb846ceSChristoph Hellwig mutex_unlock(&ioc->sas_mgmt.mutex);
2179da4fa655SChristoph Hellwig out:
2180da4fa655SChristoph Hellwig return error;
2181da4fa655SChristoph Hellwig }
2182b5141128SChristoph Hellwig
2183e3094447SChristoph Hellwig static int
mptsas_get_enclosure_identifier(struct sas_rphy * rphy,u64 * identifier)2184e3094447SChristoph Hellwig mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2185e3094447SChristoph Hellwig {
2186e3094447SChristoph Hellwig MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2187e3094447SChristoph Hellwig int i, error;
2188e3094447SChristoph Hellwig struct mptsas_portinfo *p;
2189e3094447SChristoph Hellwig struct mptsas_enclosure enclosure_info;
2190e3094447SChristoph Hellwig u64 enclosure_handle;
2191e3094447SChristoph Hellwig
2192e3094447SChristoph Hellwig mutex_lock(&ioc->sas_topology_mutex);
2193e3094447SChristoph Hellwig list_for_each_entry(p, &ioc->sas_topology, list) {
2194e3094447SChristoph Hellwig for (i = 0; i < p->num_phys; i++) {
2195e3094447SChristoph Hellwig if (p->phy_info[i].attached.sas_address ==
2196e3094447SChristoph Hellwig rphy->identify.sas_address) {
2197e3094447SChristoph Hellwig enclosure_handle = p->phy_info[i].
2198e3094447SChristoph Hellwig attached.handle_enclosure;
2199e3094447SChristoph Hellwig goto found_info;
2200e3094447SChristoph Hellwig }
2201e3094447SChristoph Hellwig }
2202e3094447SChristoph Hellwig }
2203e3094447SChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
2204e3094447SChristoph Hellwig return -ENXIO;
2205e3094447SChristoph Hellwig
2206e3094447SChristoph Hellwig found_info:
2207e3094447SChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
2208e3094447SChristoph Hellwig memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
220952435430SMoore, Eric error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
2210e3094447SChristoph Hellwig (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2211e3094447SChristoph Hellwig MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2212e3094447SChristoph Hellwig if (!error)
2213e3094447SChristoph Hellwig *identifier = enclosure_info.enclosure_logical_id;
2214e3094447SChristoph Hellwig return error;
2215e3094447SChristoph Hellwig }
2216e3094447SChristoph Hellwig
2217e3094447SChristoph Hellwig static int
mptsas_get_bay_identifier(struct sas_rphy * rphy)2218e3094447SChristoph Hellwig mptsas_get_bay_identifier(struct sas_rphy *rphy)
2219e3094447SChristoph Hellwig {
2220e3094447SChristoph Hellwig MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2221e3094447SChristoph Hellwig struct mptsas_portinfo *p;
2222e3094447SChristoph Hellwig int i, rc;
2223e3094447SChristoph Hellwig
2224e3094447SChristoph Hellwig mutex_lock(&ioc->sas_topology_mutex);
2225e3094447SChristoph Hellwig list_for_each_entry(p, &ioc->sas_topology, list) {
2226e3094447SChristoph Hellwig for (i = 0; i < p->num_phys; i++) {
2227e3094447SChristoph Hellwig if (p->phy_info[i].attached.sas_address ==
2228e3094447SChristoph Hellwig rphy->identify.sas_address) {
2229e3094447SChristoph Hellwig rc = p->phy_info[i].attached.slot;
2230e3094447SChristoph Hellwig goto out;
2231e3094447SChristoph Hellwig }
2232e3094447SChristoph Hellwig }
2233e3094447SChristoph Hellwig }
2234e3094447SChristoph Hellwig rc = -ENXIO;
2235e3094447SChristoph Hellwig out:
2236e3094447SChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
2237e3094447SChristoph Hellwig return rc;
2238e3094447SChristoph Hellwig }
2239e3094447SChristoph Hellwig
mptsas_smp_handler(struct bsg_job * job,struct Scsi_Host * shost,struct sas_rphy * rphy)2240651a0136SChristoph Hellwig static void mptsas_smp_handler(struct bsg_job *job, struct Scsi_Host *shost,
2241651a0136SChristoph Hellwig struct sas_rphy *rphy)
2242159e36feSFUJITA Tomonori {
2243159e36feSFUJITA Tomonori MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2244159e36feSFUJITA Tomonori MPT_FRAME_HDR *mf;
2245159e36feSFUJITA Tomonori SmpPassthroughRequest_t *smpreq;
2246159e36feSFUJITA Tomonori int flagsLength;
2247159e36feSFUJITA Tomonori unsigned long timeleft;
2248159e36feSFUJITA Tomonori char *psge;
2249159e36feSFUJITA Tomonori u64 sas_address = 0;
2250651a0136SChristoph Hellwig unsigned int reslen = 0;
2251651a0136SChristoph Hellwig int ret = -EINVAL;
2252159e36feSFUJITA Tomonori
2253159e36feSFUJITA Tomonori /* do we need to support multiple segments? */
2254651a0136SChristoph Hellwig if (job->request_payload.sg_cnt > 1 ||
2255651a0136SChristoph Hellwig job->reply_payload.sg_cnt > 1) {
2256458b76edSKent Overstreet printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u, rsp %u\n",
2257651a0136SChristoph Hellwig ioc->name, __func__, job->request_payload.payload_len,
2258651a0136SChristoph Hellwig job->reply_payload.payload_len);
2259651a0136SChristoph Hellwig goto out;
2260159e36feSFUJITA Tomonori }
2261159e36feSFUJITA Tomonori
2262159e36feSFUJITA Tomonori ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2263159e36feSFUJITA Tomonori if (ret)
2264159e36feSFUJITA Tomonori goto out;
2265159e36feSFUJITA Tomonori
2266159e36feSFUJITA Tomonori mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2267159e36feSFUJITA Tomonori if (!mf) {
2268159e36feSFUJITA Tomonori ret = -ENOMEM;
2269159e36feSFUJITA Tomonori goto out_unlock;
2270159e36feSFUJITA Tomonori }
2271159e36feSFUJITA Tomonori
2272159e36feSFUJITA Tomonori smpreq = (SmpPassthroughRequest_t *)mf;
2273159e36feSFUJITA Tomonori memset(smpreq, 0, sizeof(*smpreq));
2274159e36feSFUJITA Tomonori
2275651a0136SChristoph Hellwig smpreq->RequestDataLength =
2276651a0136SChristoph Hellwig cpu_to_le16(job->request_payload.payload_len - 4);
2277159e36feSFUJITA Tomonori smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2278159e36feSFUJITA Tomonori
2279159e36feSFUJITA Tomonori if (rphy)
2280159e36feSFUJITA Tomonori sas_address = rphy->identify.sas_address;
2281159e36feSFUJITA Tomonori else {
2282159e36feSFUJITA Tomonori struct mptsas_portinfo *port_info;
2283159e36feSFUJITA Tomonori
2284159e36feSFUJITA Tomonori mutex_lock(&ioc->sas_topology_mutex);
2285f9c34022SKashyap, Desai port_info = ioc->hba_port_info;
2286159e36feSFUJITA Tomonori if (port_info && port_info->phy_info)
2287159e36feSFUJITA Tomonori sas_address =
2288159e36feSFUJITA Tomonori port_info->phy_info[0].phy->identify.sas_address;
2289159e36feSFUJITA Tomonori mutex_unlock(&ioc->sas_topology_mutex);
2290159e36feSFUJITA Tomonori }
2291159e36feSFUJITA Tomonori
2292159e36feSFUJITA Tomonori *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2293159e36feSFUJITA Tomonori
2294159e36feSFUJITA Tomonori psge = (char *)
2295159e36feSFUJITA Tomonori (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2296159e36feSFUJITA Tomonori
2297159e36feSFUJITA Tomonori /* request */
2298159e36feSFUJITA Tomonori flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2299159e36feSFUJITA Tomonori MPI_SGE_FLAGS_END_OF_BUFFER |
230014d0f0b0SKashyap, Desai MPI_SGE_FLAGS_DIRECTION)
230114d0f0b0SKashyap, Desai << MPI_SGE_FLAGS_SHIFT;
2302159e36feSFUJITA Tomonori
2303651a0136SChristoph Hellwig if (!dma_map_sg(&ioc->pcidev->dev, job->request_payload.sg_list,
2304b114dda6SChristophe JAILLET 1, DMA_BIDIRECTIONAL))
2305159e36feSFUJITA Tomonori goto put_mf;
2306651a0136SChristoph Hellwig
2307651a0136SChristoph Hellwig flagsLength |= (sg_dma_len(job->request_payload.sg_list) - 4);
2308651a0136SChristoph Hellwig ioc->add_sge(psge, flagsLength,
2309651a0136SChristoph Hellwig sg_dma_address(job->request_payload.sg_list));
23102f187862SKashyap, Desai psge += ioc->SGE_size;
2311159e36feSFUJITA Tomonori
2312159e36feSFUJITA Tomonori /* response */
23132f187862SKashyap, Desai flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
23142f187862SKashyap, Desai MPI_SGE_FLAGS_SYSTEM_ADDRESS |
23152f187862SKashyap, Desai MPI_SGE_FLAGS_IOC_TO_HOST |
23162f187862SKashyap, Desai MPI_SGE_FLAGS_END_OF_BUFFER;
23172f187862SKashyap, Desai
23182f187862SKashyap, Desai flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2319651a0136SChristoph Hellwig
2320651a0136SChristoph Hellwig if (!dma_map_sg(&ioc->pcidev->dev, job->reply_payload.sg_list,
2321b114dda6SChristophe JAILLET 1, DMA_BIDIRECTIONAL))
2322651a0136SChristoph Hellwig goto unmap_out;
2323651a0136SChristoph Hellwig flagsLength |= sg_dma_len(job->reply_payload.sg_list) + 4;
2324651a0136SChristoph Hellwig ioc->add_sge(psge, flagsLength,
2325651a0136SChristoph Hellwig sg_dma_address(job->reply_payload.sg_list));
2326159e36feSFUJITA Tomonori
23272f187862SKashyap, Desai INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2328159e36feSFUJITA Tomonori mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2329159e36feSFUJITA Tomonori
2330159e36feSFUJITA Tomonori timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2331568da769SKashyap, Desai if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2332568da769SKashyap, Desai ret = -ETIME;
2333568da769SKashyap, Desai mpt_free_msg_frame(ioc, mf);
2334568da769SKashyap, Desai mf = NULL;
2335568da769SKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2336651a0136SChristoph Hellwig goto unmap_in;
2337568da769SKashyap, Desai if (!timeleft)
2338d0f698c4SKashyap, Desai mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
2339651a0136SChristoph Hellwig goto unmap_in;
2340159e36feSFUJITA Tomonori }
2341159e36feSFUJITA Tomonori mf = NULL;
2342159e36feSFUJITA Tomonori
2343f0f09d3bSKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2344159e36feSFUJITA Tomonori SmpPassthroughReply_t *smprep;
2345159e36feSFUJITA Tomonori
2346159e36feSFUJITA Tomonori smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2347651a0136SChristoph Hellwig memcpy(job->reply, smprep, sizeof(*smprep));
2348651a0136SChristoph Hellwig job->reply_len = sizeof(*smprep);
2349651a0136SChristoph Hellwig reslen = smprep->ResponseDataLength;
2350159e36feSFUJITA Tomonori } else {
23512f187862SKashyap, Desai printk(MYIOC_s_ERR_FMT
23522f187862SKashyap, Desai "%s: smp passthru reply failed to be returned\n",
2353cadbd4a5SHarvey Harrison ioc->name, __func__);
2354159e36feSFUJITA Tomonori ret = -ENXIO;
2355159e36feSFUJITA Tomonori }
2356651a0136SChristoph Hellwig
2357651a0136SChristoph Hellwig unmap_in:
2358651a0136SChristoph Hellwig dma_unmap_sg(&ioc->pcidev->dev, job->reply_payload.sg_list, 1,
2359b114dda6SChristophe JAILLET DMA_BIDIRECTIONAL);
2360651a0136SChristoph Hellwig unmap_out:
2361651a0136SChristoph Hellwig dma_unmap_sg(&ioc->pcidev->dev, job->request_payload.sg_list, 1,
2362b114dda6SChristophe JAILLET DMA_BIDIRECTIONAL);
2363159e36feSFUJITA Tomonori put_mf:
2364159e36feSFUJITA Tomonori if (mf)
2365159e36feSFUJITA Tomonori mpt_free_msg_frame(ioc, mf);
2366159e36feSFUJITA Tomonori out_unlock:
23672f187862SKashyap, Desai CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2368159e36feSFUJITA Tomonori mutex_unlock(&ioc->sas_mgmt.mutex);
2369159e36feSFUJITA Tomonori out:
2370651a0136SChristoph Hellwig bsg_job_done(job, ret, reslen);
2371159e36feSFUJITA Tomonori }
2372159e36feSFUJITA Tomonori
23730c33b27dSChristoph Hellwig static struct sas_function_template mptsas_transport_functions = {
2374b5141128SChristoph Hellwig .get_linkerrors = mptsas_get_linkerrors,
2375e3094447SChristoph Hellwig .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2376e3094447SChristoph Hellwig .get_bay_identifier = mptsas_get_bay_identifier,
2377da4fa655SChristoph Hellwig .phy_reset = mptsas_phy_reset,
2378159e36feSFUJITA Tomonori .smp_handler = mptsas_smp_handler,
23790c33b27dSChristoph Hellwig };
23800c33b27dSChristoph Hellwig
23810c33b27dSChristoph Hellwig static struct scsi_transport_template *mptsas_transport_template;
23820c33b27dSChristoph Hellwig
23830c33b27dSChristoph Hellwig static int
mptsas_sas_io_unit_pg0(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info)23840c33b27dSChristoph Hellwig mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
23850c33b27dSChristoph Hellwig {
23860c33b27dSChristoph Hellwig ConfigExtendedPageHeader_t hdr;
23870c33b27dSChristoph Hellwig CONFIGPARMS cfg;
23880c33b27dSChristoph Hellwig SasIOUnitPage0_t *buffer;
23890c33b27dSChristoph Hellwig dma_addr_t dma_handle;
23900c33b27dSChristoph Hellwig int error, i;
23910c33b27dSChristoph Hellwig
23920c33b27dSChristoph Hellwig hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
23930c33b27dSChristoph Hellwig hdr.ExtPageLength = 0;
23940c33b27dSChristoph Hellwig hdr.PageNumber = 0;
23950c33b27dSChristoph Hellwig hdr.Reserved1 = 0;
23960c33b27dSChristoph Hellwig hdr.Reserved2 = 0;
23970c33b27dSChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
23980c33b27dSChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
23990c33b27dSChristoph Hellwig
24000c33b27dSChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
24010c33b27dSChristoph Hellwig cfg.physAddr = -1;
24020c33b27dSChristoph Hellwig cfg.pageAddr = 0;
24030c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
24040c33b27dSChristoph Hellwig cfg.dir = 0; /* read */
24054b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
24060c33b27dSChristoph Hellwig
24070c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
24080c33b27dSChristoph Hellwig if (error)
24090c33b27dSChristoph Hellwig goto out;
24100c33b27dSChristoph Hellwig if (!hdr.ExtPageLength) {
24110c33b27dSChristoph Hellwig error = -ENXIO;
24120c33b27dSChristoph Hellwig goto out;
24130c33b27dSChristoph Hellwig }
24140c33b27dSChristoph Hellwig
241576a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
241676a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
24170c33b27dSChristoph Hellwig if (!buffer) {
24180c33b27dSChristoph Hellwig error = -ENOMEM;
24190c33b27dSChristoph Hellwig goto out;
24200c33b27dSChristoph Hellwig }
24210c33b27dSChristoph Hellwig
24220c33b27dSChristoph Hellwig cfg.physAddr = dma_handle;
24230c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
24240c33b27dSChristoph Hellwig
24250c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
24260c33b27dSChristoph Hellwig if (error)
24270c33b27dSChristoph Hellwig goto out_free_consistent;
24280c33b27dSChristoph Hellwig
24290c33b27dSChristoph Hellwig port_info->num_phys = buffer->NumPhys;
24300c33b27dSChristoph Hellwig port_info->phy_info = kcalloc(port_info->num_phys,
24312f187862SKashyap, Desai sizeof(struct mptsas_phyinfo), GFP_KERNEL);
24320c33b27dSChristoph Hellwig if (!port_info->phy_info) {
24330c33b27dSChristoph Hellwig error = -ENOMEM;
24340c33b27dSChristoph Hellwig goto out_free_consistent;
24350c33b27dSChristoph Hellwig }
24360c33b27dSChristoph Hellwig
2437edb9068dSPrakash, Sathya ioc->nvdata_version_persistent =
2438edb9068dSPrakash, Sathya le16_to_cpu(buffer->NvdataVersionPersistent);
2439edb9068dSPrakash, Sathya ioc->nvdata_version_default =
2440edb9068dSPrakash, Sathya le16_to_cpu(buffer->NvdataVersionDefault);
2441edb9068dSPrakash, Sathya
24420c33b27dSChristoph Hellwig for (i = 0; i < port_info->num_phys; i++) {
2443d6ecdd63SPrakash, Sathya mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
24440c33b27dSChristoph Hellwig port_info->phy_info[i].phy_id = i;
24450c33b27dSChristoph Hellwig port_info->phy_info[i].port_id =
24460c33b27dSChristoph Hellwig buffer->PhyData[i].Port;
24470c33b27dSChristoph Hellwig port_info->phy_info[i].negotiated_link_rate =
24480c33b27dSChristoph Hellwig buffer->PhyData[i].NegotiatedLinkRate;
2449547f9a21SEric Moore port_info->phy_info[i].portinfo = port_info;
24502ecce492SEric Moore port_info->phy_info[i].handle =
24512ecce492SEric Moore le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
24520c33b27dSChristoph Hellwig }
24530c33b27dSChristoph Hellwig
24540c33b27dSChristoph Hellwig out_free_consistent:
2455b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2456b114dda6SChristophe JAILLET dma_handle);
24570c33b27dSChristoph Hellwig out:
24580c33b27dSChristoph Hellwig return error;
24590c33b27dSChristoph Hellwig }
24600c33b27dSChristoph Hellwig
24610c33b27dSChristoph Hellwig static int
mptsas_sas_io_unit_pg1(MPT_ADAPTER * ioc)2462edb9068dSPrakash, Sathya mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2463edb9068dSPrakash, Sathya {
2464edb9068dSPrakash, Sathya ConfigExtendedPageHeader_t hdr;
2465edb9068dSPrakash, Sathya CONFIGPARMS cfg;
2466edb9068dSPrakash, Sathya SasIOUnitPage1_t *buffer;
2467edb9068dSPrakash, Sathya dma_addr_t dma_handle;
2468edb9068dSPrakash, Sathya int error;
2469aca794ddSKashyap, Desai u8 device_missing_delay;
2470edb9068dSPrakash, Sathya
2471edb9068dSPrakash, Sathya memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2472edb9068dSPrakash, Sathya memset(&cfg, 0, sizeof(CONFIGPARMS));
2473edb9068dSPrakash, Sathya
2474edb9068dSPrakash, Sathya cfg.cfghdr.ehdr = &hdr;
2475edb9068dSPrakash, Sathya cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
24764b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
2477edb9068dSPrakash, Sathya cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2478edb9068dSPrakash, Sathya cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2479edb9068dSPrakash, Sathya cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2480edb9068dSPrakash, Sathya cfg.cfghdr.ehdr->PageNumber = 1;
2481edb9068dSPrakash, Sathya
2482edb9068dSPrakash, Sathya error = mpt_config(ioc, &cfg);
2483edb9068dSPrakash, Sathya if (error)
2484edb9068dSPrakash, Sathya goto out;
2485edb9068dSPrakash, Sathya if (!hdr.ExtPageLength) {
2486edb9068dSPrakash, Sathya error = -ENXIO;
2487edb9068dSPrakash, Sathya goto out;
2488edb9068dSPrakash, Sathya }
2489edb9068dSPrakash, Sathya
249076a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
249176a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
2492edb9068dSPrakash, Sathya if (!buffer) {
2493edb9068dSPrakash, Sathya error = -ENOMEM;
2494edb9068dSPrakash, Sathya goto out;
2495edb9068dSPrakash, Sathya }
2496edb9068dSPrakash, Sathya
2497edb9068dSPrakash, Sathya cfg.physAddr = dma_handle;
2498edb9068dSPrakash, Sathya cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2499edb9068dSPrakash, Sathya
2500edb9068dSPrakash, Sathya error = mpt_config(ioc, &cfg);
2501edb9068dSPrakash, Sathya if (error)
2502edb9068dSPrakash, Sathya goto out_free_consistent;
2503edb9068dSPrakash, Sathya
2504edb9068dSPrakash, Sathya ioc->io_missing_delay =
2505edb9068dSPrakash, Sathya le16_to_cpu(buffer->IODeviceMissingDelay);
2506aca794ddSKashyap, Desai device_missing_delay = buffer->ReportDeviceMissingDelay;
2507edb9068dSPrakash, Sathya ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2508edb9068dSPrakash, Sathya (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2509edb9068dSPrakash, Sathya device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2510edb9068dSPrakash, Sathya
2511edb9068dSPrakash, Sathya out_free_consistent:
2512b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2513b114dda6SChristophe JAILLET dma_handle);
2514edb9068dSPrakash, Sathya out:
2515edb9068dSPrakash, Sathya return error;
2516edb9068dSPrakash, Sathya }
2517edb9068dSPrakash, Sathya
2518edb9068dSPrakash, Sathya static int
mptsas_sas_phy_pg0(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,u32 form,u32 form_specific)25190c33b27dSChristoph Hellwig mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
25200c33b27dSChristoph Hellwig u32 form, u32 form_specific)
25210c33b27dSChristoph Hellwig {
25220c33b27dSChristoph Hellwig ConfigExtendedPageHeader_t hdr;
25230c33b27dSChristoph Hellwig CONFIGPARMS cfg;
25240c33b27dSChristoph Hellwig SasPhyPage0_t *buffer;
25250c33b27dSChristoph Hellwig dma_addr_t dma_handle;
25260c33b27dSChristoph Hellwig int error;
25270c33b27dSChristoph Hellwig
25280c33b27dSChristoph Hellwig hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
25290c33b27dSChristoph Hellwig hdr.ExtPageLength = 0;
25300c33b27dSChristoph Hellwig hdr.PageNumber = 0;
25310c33b27dSChristoph Hellwig hdr.Reserved1 = 0;
25320c33b27dSChristoph Hellwig hdr.Reserved2 = 0;
25330c33b27dSChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
25340c33b27dSChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
25350c33b27dSChristoph Hellwig
25360c33b27dSChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
25370c33b27dSChristoph Hellwig cfg.dir = 0; /* read */
25384b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
25390c33b27dSChristoph Hellwig
25400c33b27dSChristoph Hellwig /* Get Phy Pg 0 for each Phy. */
25410c33b27dSChristoph Hellwig cfg.physAddr = -1;
25420c33b27dSChristoph Hellwig cfg.pageAddr = form + form_specific;
25430c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
25440c33b27dSChristoph Hellwig
25450c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
25460c33b27dSChristoph Hellwig if (error)
25470c33b27dSChristoph Hellwig goto out;
25480c33b27dSChristoph Hellwig
25490c33b27dSChristoph Hellwig if (!hdr.ExtPageLength) {
25500c33b27dSChristoph Hellwig error = -ENXIO;
25510c33b27dSChristoph Hellwig goto out;
25520c33b27dSChristoph Hellwig }
25530c33b27dSChristoph Hellwig
255476a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
255576a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
25560c33b27dSChristoph Hellwig if (!buffer) {
25570c33b27dSChristoph Hellwig error = -ENOMEM;
25580c33b27dSChristoph Hellwig goto out;
25590c33b27dSChristoph Hellwig }
25600c33b27dSChristoph Hellwig
25610c33b27dSChristoph Hellwig cfg.physAddr = dma_handle;
25620c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
25630c33b27dSChristoph Hellwig
25640c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
25650c33b27dSChristoph Hellwig if (error)
25660c33b27dSChristoph Hellwig goto out_free_consistent;
25670c33b27dSChristoph Hellwig
2568d6ecdd63SPrakash, Sathya mptsas_print_phy_pg0(ioc, buffer);
25690c33b27dSChristoph Hellwig
25700c33b27dSChristoph Hellwig phy_info->hw_link_rate = buffer->HwLinkRate;
25710c33b27dSChristoph Hellwig phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
25720c33b27dSChristoph Hellwig phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
25730c33b27dSChristoph Hellwig phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
25740c33b27dSChristoph Hellwig
25750c33b27dSChristoph Hellwig out_free_consistent:
2576b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2577b114dda6SChristophe JAILLET dma_handle);
25780c33b27dSChristoph Hellwig out:
25790c33b27dSChristoph Hellwig return error;
25800c33b27dSChristoph Hellwig }
25810c33b27dSChristoph Hellwig
25820c33b27dSChristoph Hellwig static int
mptsas_sas_device_pg0(MPT_ADAPTER * ioc,struct mptsas_devinfo * device_info,u32 form,u32 form_specific)25830c33b27dSChristoph Hellwig mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
25840c33b27dSChristoph Hellwig u32 form, u32 form_specific)
25850c33b27dSChristoph Hellwig {
25860c33b27dSChristoph Hellwig ConfigExtendedPageHeader_t hdr;
25870c33b27dSChristoph Hellwig CONFIGPARMS cfg;
25880c33b27dSChristoph Hellwig SasDevicePage0_t *buffer;
25890c33b27dSChristoph Hellwig dma_addr_t dma_handle;
25900c33b27dSChristoph Hellwig __le64 sas_address;
2591bd23e94cSMoore, Eric int error=0;
2592bd23e94cSMoore, Eric
25930c33b27dSChristoph Hellwig hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
25940c33b27dSChristoph Hellwig hdr.ExtPageLength = 0;
25950c33b27dSChristoph Hellwig hdr.PageNumber = 0;
25960c33b27dSChristoph Hellwig hdr.Reserved1 = 0;
25970c33b27dSChristoph Hellwig hdr.Reserved2 = 0;
25980c33b27dSChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
25990c33b27dSChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
26000c33b27dSChristoph Hellwig
26010c33b27dSChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
26020c33b27dSChristoph Hellwig cfg.pageAddr = form + form_specific;
26030c33b27dSChristoph Hellwig cfg.physAddr = -1;
26040c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
26050c33b27dSChristoph Hellwig cfg.dir = 0; /* read */
26064b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
26070c33b27dSChristoph Hellwig
2608db9c9174SMoore, Eric memset(device_info, 0, sizeof(struct mptsas_devinfo));
26090c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
26100c33b27dSChristoph Hellwig if (error)
26110c33b27dSChristoph Hellwig goto out;
26120c33b27dSChristoph Hellwig if (!hdr.ExtPageLength) {
26130c33b27dSChristoph Hellwig error = -ENXIO;
26140c33b27dSChristoph Hellwig goto out;
26150c33b27dSChristoph Hellwig }
26160c33b27dSChristoph Hellwig
261776a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
261876a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
26190c33b27dSChristoph Hellwig if (!buffer) {
26200c33b27dSChristoph Hellwig error = -ENOMEM;
26210c33b27dSChristoph Hellwig goto out;
26220c33b27dSChristoph Hellwig }
26230c33b27dSChristoph Hellwig
26240c33b27dSChristoph Hellwig cfg.physAddr = dma_handle;
26250c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
26260c33b27dSChristoph Hellwig
26270c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
26280cf0f23cSKashyap, Desai
26290cf0f23cSKashyap, Desai if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
26300cf0f23cSKashyap, Desai error = -ENODEV;
26310cf0f23cSKashyap, Desai goto out_free_consistent;
26320cf0f23cSKashyap, Desai }
26330cf0f23cSKashyap, Desai
26340c33b27dSChristoph Hellwig if (error)
26350c33b27dSChristoph Hellwig goto out_free_consistent;
26360c33b27dSChristoph Hellwig
2637d6ecdd63SPrakash, Sathya mptsas_print_device_pg0(ioc, buffer);
26380c33b27dSChristoph Hellwig
26392f187862SKashyap, Desai memset(device_info, 0, sizeof(struct mptsas_devinfo));
26400c33b27dSChristoph Hellwig device_info->handle = le16_to_cpu(buffer->DevHandle);
2641c73787eeSMoore, Eric device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
2642e3094447SChristoph Hellwig device_info->handle_enclosure =
2643e3094447SChristoph Hellwig le16_to_cpu(buffer->EnclosureHandle);
2644e3094447SChristoph Hellwig device_info->slot = le16_to_cpu(buffer->Slot);
26450c33b27dSChristoph Hellwig device_info->phy_id = buffer->PhyNum;
26460c33b27dSChristoph Hellwig device_info->port_id = buffer->PhysicalPort;
26479a28f49aSChristoph Hellwig device_info->id = buffer->TargetID;
2648b506ade9SEric Moore device_info->phys_disk_num = ~0;
26499a28f49aSChristoph Hellwig device_info->channel = buffer->Bus;
26500c33b27dSChristoph Hellwig memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
26510c33b27dSChristoph Hellwig device_info->sas_address = le64_to_cpu(sas_address);
26520c33b27dSChristoph Hellwig device_info->device_info =
26530c33b27dSChristoph Hellwig le32_to_cpu(buffer->DeviceInfo);
265451106ab5SKashyap, Desai device_info->flags = le16_to_cpu(buffer->Flags);
26550c33b27dSChristoph Hellwig
26560c33b27dSChristoph Hellwig out_free_consistent:
2657b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2658b114dda6SChristophe JAILLET dma_handle);
26590c33b27dSChristoph Hellwig out:
26600c33b27dSChristoph Hellwig return error;
26610c33b27dSChristoph Hellwig }
26620c33b27dSChristoph Hellwig
26630c33b27dSChristoph Hellwig static int
mptsas_sas_expander_pg0(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info,u32 form,u32 form_specific)26640c33b27dSChristoph Hellwig mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
26650c33b27dSChristoph Hellwig u32 form, u32 form_specific)
26660c33b27dSChristoph Hellwig {
26670c33b27dSChristoph Hellwig ConfigExtendedPageHeader_t hdr;
26680c33b27dSChristoph Hellwig CONFIGPARMS cfg;
26690c33b27dSChristoph Hellwig SasExpanderPage0_t *buffer;
26700c33b27dSChristoph Hellwig dma_addr_t dma_handle;
2671547f9a21SEric Moore int i, error;
26722f187862SKashyap, Desai __le64 sas_address;
26730c33b27dSChristoph Hellwig
26742f187862SKashyap, Desai memset(port_info, 0, sizeof(struct mptsas_portinfo));
26750c33b27dSChristoph Hellwig hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
26760c33b27dSChristoph Hellwig hdr.ExtPageLength = 0;
26770c33b27dSChristoph Hellwig hdr.PageNumber = 0;
26780c33b27dSChristoph Hellwig hdr.Reserved1 = 0;
26790c33b27dSChristoph Hellwig hdr.Reserved2 = 0;
26800c33b27dSChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
26810c33b27dSChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
26820c33b27dSChristoph Hellwig
26830c33b27dSChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
26840c33b27dSChristoph Hellwig cfg.physAddr = -1;
26850c33b27dSChristoph Hellwig cfg.pageAddr = form + form_specific;
26860c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
26870c33b27dSChristoph Hellwig cfg.dir = 0; /* read */
26884b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
26890c33b27dSChristoph Hellwig
2690db9c9174SMoore, Eric memset(port_info, 0, sizeof(struct mptsas_portinfo));
26910c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
26920c33b27dSChristoph Hellwig if (error)
26930c33b27dSChristoph Hellwig goto out;
26940c33b27dSChristoph Hellwig
26950c33b27dSChristoph Hellwig if (!hdr.ExtPageLength) {
26960c33b27dSChristoph Hellwig error = -ENXIO;
26970c33b27dSChristoph Hellwig goto out;
26980c33b27dSChristoph Hellwig }
26990c33b27dSChristoph Hellwig
270076a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
270176a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
27020c33b27dSChristoph Hellwig if (!buffer) {
27030c33b27dSChristoph Hellwig error = -ENOMEM;
27040c33b27dSChristoph Hellwig goto out;
27050c33b27dSChristoph Hellwig }
27060c33b27dSChristoph Hellwig
27070c33b27dSChristoph Hellwig cfg.physAddr = dma_handle;
27080c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
27090c33b27dSChristoph Hellwig
27100c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
27110cf0f23cSKashyap, Desai if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
271251f39eaeSKrzysztof Oledzki error = -ENODEV;
271351f39eaeSKrzysztof Oledzki goto out_free_consistent;
271451f39eaeSKrzysztof Oledzki }
271551f39eaeSKrzysztof Oledzki
27160cf0f23cSKashyap, Desai if (error)
27170cf0f23cSKashyap, Desai goto out_free_consistent;
27180cf0f23cSKashyap, Desai
27190c33b27dSChristoph Hellwig /* save config data */
27202f187862SKashyap, Desai port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
27210c33b27dSChristoph Hellwig port_info->phy_info = kcalloc(port_info->num_phys,
27222f187862SKashyap, Desai sizeof(struct mptsas_phyinfo), GFP_KERNEL);
27230c33b27dSChristoph Hellwig if (!port_info->phy_info) {
27240c33b27dSChristoph Hellwig error = -ENOMEM;
27250c33b27dSChristoph Hellwig goto out_free_consistent;
27260c33b27dSChristoph Hellwig }
27270c33b27dSChristoph Hellwig
27282f187862SKashyap, Desai memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
27292ecce492SEric Moore for (i = 0; i < port_info->num_phys; i++) {
2730547f9a21SEric Moore port_info->phy_info[i].portinfo = port_info;
27312ecce492SEric Moore port_info->phy_info[i].handle =
27322ecce492SEric Moore le16_to_cpu(buffer->DevHandle);
27332f187862SKashyap, Desai port_info->phy_info[i].identify.sas_address =
27342f187862SKashyap, Desai le64_to_cpu(sas_address);
27352f187862SKashyap, Desai port_info->phy_info[i].identify.handle_parent =
27362f187862SKashyap, Desai le16_to_cpu(buffer->ParentDevHandle);
27372ecce492SEric Moore }
2738547f9a21SEric Moore
27390c33b27dSChristoph Hellwig out_free_consistent:
2740b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2741b114dda6SChristophe JAILLET dma_handle);
27420c33b27dSChristoph Hellwig out:
27430c33b27dSChristoph Hellwig return error;
27440c33b27dSChristoph Hellwig }
27450c33b27dSChristoph Hellwig
27460c33b27dSChristoph Hellwig static int
mptsas_sas_expander_pg1(MPT_ADAPTER * ioc,struct mptsas_phyinfo * phy_info,u32 form,u32 form_specific)27470c33b27dSChristoph Hellwig mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
27480c33b27dSChristoph Hellwig u32 form, u32 form_specific)
27490c33b27dSChristoph Hellwig {
27500c33b27dSChristoph Hellwig ConfigExtendedPageHeader_t hdr;
27510c33b27dSChristoph Hellwig CONFIGPARMS cfg;
27520c33b27dSChristoph Hellwig SasExpanderPage1_t *buffer;
27530c33b27dSChristoph Hellwig dma_addr_t dma_handle;
2754bd23e94cSMoore, Eric int error=0;
2755bd23e94cSMoore, Eric
27562f187862SKashyap, Desai hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
27570c33b27dSChristoph Hellwig hdr.ExtPageLength = 0;
27580c33b27dSChristoph Hellwig hdr.PageNumber = 1;
27590c33b27dSChristoph Hellwig hdr.Reserved1 = 0;
27600c33b27dSChristoph Hellwig hdr.Reserved2 = 0;
27610c33b27dSChristoph Hellwig hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
27620c33b27dSChristoph Hellwig hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
27630c33b27dSChristoph Hellwig
27640c33b27dSChristoph Hellwig cfg.cfghdr.ehdr = &hdr;
27650c33b27dSChristoph Hellwig cfg.physAddr = -1;
27660c33b27dSChristoph Hellwig cfg.pageAddr = form + form_specific;
27670c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
27680c33b27dSChristoph Hellwig cfg.dir = 0; /* read */
27694b97650bSKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
27700c33b27dSChristoph Hellwig
27710c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
27720c33b27dSChristoph Hellwig if (error)
27730c33b27dSChristoph Hellwig goto out;
27740c33b27dSChristoph Hellwig
27750c33b27dSChristoph Hellwig if (!hdr.ExtPageLength) {
27760c33b27dSChristoph Hellwig error = -ENXIO;
27770c33b27dSChristoph Hellwig goto out;
27780c33b27dSChristoph Hellwig }
27790c33b27dSChristoph Hellwig
278076a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4,
278176a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
27820c33b27dSChristoph Hellwig if (!buffer) {
27830c33b27dSChristoph Hellwig error = -ENOMEM;
27840c33b27dSChristoph Hellwig goto out;
27850c33b27dSChristoph Hellwig }
27860c33b27dSChristoph Hellwig
27870c33b27dSChristoph Hellwig cfg.physAddr = dma_handle;
27880c33b27dSChristoph Hellwig cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
27890c33b27dSChristoph Hellwig
27900c33b27dSChristoph Hellwig error = mpt_config(ioc, &cfg);
27912f187862SKashyap, Desai
27922f187862SKashyap, Desai if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
27932f187862SKashyap, Desai error = -ENODEV;
27940cf0f23cSKashyap, Desai goto out_free_consistent;
27952f187862SKashyap, Desai }
27962f187862SKashyap, Desai
27970c33b27dSChristoph Hellwig if (error)
27980c33b27dSChristoph Hellwig goto out_free_consistent;
27990c33b27dSChristoph Hellwig
28000c33b27dSChristoph Hellwig
2801d6ecdd63SPrakash, Sathya mptsas_print_expander_pg1(ioc, buffer);
28020c33b27dSChristoph Hellwig
28030c33b27dSChristoph Hellwig /* save config data */
2804024358eeSEric Moore phy_info->phy_id = buffer->PhyIdentifier;
28050c33b27dSChristoph Hellwig phy_info->port_id = buffer->PhysicalPort;
28060c33b27dSChristoph Hellwig phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
28070c33b27dSChristoph Hellwig phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
28080c33b27dSChristoph Hellwig phy_info->hw_link_rate = buffer->HwLinkRate;
28090c33b27dSChristoph Hellwig phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
28100c33b27dSChristoph Hellwig phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
28110c33b27dSChristoph Hellwig
28120c33b27dSChristoph Hellwig out_free_consistent:
2813b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.ExtPageLength * 4, buffer,
2814b114dda6SChristophe JAILLET dma_handle);
28150c33b27dSChristoph Hellwig out:
28160c33b27dSChristoph Hellwig return error;
28170c33b27dSChristoph Hellwig }
28180c33b27dSChristoph Hellwig
2819e0f553abSKashyap, Desai struct rep_manu_request{
2820e0f553abSKashyap, Desai u8 smp_frame_type;
2821e0f553abSKashyap, Desai u8 function;
2822e0f553abSKashyap, Desai u8 reserved;
2823e0f553abSKashyap, Desai u8 request_length;
2824e0f553abSKashyap, Desai };
2825e0f553abSKashyap, Desai
2826e0f553abSKashyap, Desai struct rep_manu_reply{
2827e0f553abSKashyap, Desai u8 smp_frame_type; /* 0x41 */
2828e0f553abSKashyap, Desai u8 function; /* 0x01 */
2829e0f553abSKashyap, Desai u8 function_result;
2830e0f553abSKashyap, Desai u8 response_length;
2831e0f553abSKashyap, Desai u16 expander_change_count;
2832e0f553abSKashyap, Desai u8 reserved0[2];
2833e0f553abSKashyap, Desai u8 sas_format:1;
2834e0f553abSKashyap, Desai u8 reserved1:7;
2835e0f553abSKashyap, Desai u8 reserved2[3];
2836e0f553abSKashyap, Desai u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2837e0f553abSKashyap, Desai u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2838e0f553abSKashyap, Desai u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2839e0f553abSKashyap, Desai u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2840e0f553abSKashyap, Desai u16 component_id;
2841e0f553abSKashyap, Desai u8 component_revision_id;
2842e0f553abSKashyap, Desai u8 reserved3;
2843e0f553abSKashyap, Desai u8 vendor_specific[8];
2844e0f553abSKashyap, Desai };
2845e0f553abSKashyap, Desai
2846e0f553abSKashyap, Desai /**
2847cdcda465SRandy Dunlap * mptsas_exp_repmanufacture_info - sets expander manufacturer info
2848e0f553abSKashyap, Desai * @ioc: per adapter object
2849e0f553abSKashyap, Desai * @sas_address: expander sas address
2850e0f553abSKashyap, Desai * @edev: the sas_expander_device object
2851e0f553abSKashyap, Desai *
2852cdcda465SRandy Dunlap * For an edge expander or a fanout expander:
2853cdcda465SRandy Dunlap * fills in the sas_expander_device object when SMP port is created.
2854e0f553abSKashyap, Desai *
2855cdcda465SRandy Dunlap * Return: 0 for success, non-zero for failure.
2856e0f553abSKashyap, Desai */
2857e0f553abSKashyap, Desai static int
mptsas_exp_repmanufacture_info(MPT_ADAPTER * ioc,u64 sas_address,struct sas_expander_device * edev)2858e0f553abSKashyap, Desai mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2859e0f553abSKashyap, Desai u64 sas_address, struct sas_expander_device *edev)
2860e0f553abSKashyap, Desai {
2861e0f553abSKashyap, Desai MPT_FRAME_HDR *mf;
2862e0f553abSKashyap, Desai SmpPassthroughRequest_t *smpreq;
2863e0f553abSKashyap, Desai SmpPassthroughReply_t *smprep;
2864e0f553abSKashyap, Desai struct rep_manu_reply *manufacture_reply;
2865e0f553abSKashyap, Desai struct rep_manu_request *manufacture_request;
2866e0f553abSKashyap, Desai int ret;
2867e0f553abSKashyap, Desai int flagsLength;
2868e0f553abSKashyap, Desai unsigned long timeleft;
2869e0f553abSKashyap, Desai char *psge;
2870e0f553abSKashyap, Desai unsigned long flags;
2871e0f553abSKashyap, Desai void *data_out = NULL;
2872e0f553abSKashyap, Desai dma_addr_t data_out_dma = 0;
2873e0f553abSKashyap, Desai u32 sz;
2874e0f553abSKashyap, Desai
2875e0f553abSKashyap, Desai spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2876e0f553abSKashyap, Desai if (ioc->ioc_reset_in_progress) {
2877e0f553abSKashyap, Desai spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2878e0f553abSKashyap, Desai printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2879e0f553abSKashyap, Desai __func__, ioc->name);
2880e0f553abSKashyap, Desai return -EFAULT;
2881e0f553abSKashyap, Desai }
2882e0f553abSKashyap, Desai spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2883e0f553abSKashyap, Desai
2884e0f553abSKashyap, Desai ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2885e0f553abSKashyap, Desai if (ret)
2886e0f553abSKashyap, Desai goto out;
2887e0f553abSKashyap, Desai
2888e0f553abSKashyap, Desai mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2889e0f553abSKashyap, Desai if (!mf) {
2890e0f553abSKashyap, Desai ret = -ENOMEM;
2891e0f553abSKashyap, Desai goto out_unlock;
2892e0f553abSKashyap, Desai }
2893e0f553abSKashyap, Desai
2894e0f553abSKashyap, Desai smpreq = (SmpPassthroughRequest_t *)mf;
2895e0f553abSKashyap, Desai memset(smpreq, 0, sizeof(*smpreq));
2896e0f553abSKashyap, Desai
2897e0f553abSKashyap, Desai sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2898e0f553abSKashyap, Desai
28997a960b3aSChristophe JAILLET data_out = dma_alloc_coherent(&ioc->pcidev->dev, sz, &data_out_dma,
29007a960b3aSChristophe JAILLET GFP_KERNEL);
2901e0f553abSKashyap, Desai if (!data_out) {
2902e0f553abSKashyap, Desai printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2903e0f553abSKashyap, Desai __FILE__, __LINE__, __func__);
2904e0f553abSKashyap, Desai ret = -ENOMEM;
2905e0f553abSKashyap, Desai goto put_mf;
2906e0f553abSKashyap, Desai }
2907e0f553abSKashyap, Desai
2908e0f553abSKashyap, Desai manufacture_request = data_out;
2909e0f553abSKashyap, Desai manufacture_request->smp_frame_type = 0x40;
2910e0f553abSKashyap, Desai manufacture_request->function = 1;
2911e0f553abSKashyap, Desai manufacture_request->reserved = 0;
2912e0f553abSKashyap, Desai manufacture_request->request_length = 0;
2913e0f553abSKashyap, Desai
2914e0f553abSKashyap, Desai smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2915e0f553abSKashyap, Desai smpreq->PhysicalPort = 0xFF;
2916e0f553abSKashyap, Desai *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2917e0f553abSKashyap, Desai smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2918e0f553abSKashyap, Desai
2919e0f553abSKashyap, Desai psge = (char *)
2920e0f553abSKashyap, Desai (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2921e0f553abSKashyap, Desai
2922e0f553abSKashyap, Desai flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2923e0f553abSKashyap, Desai MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2924e0f553abSKashyap, Desai MPI_SGE_FLAGS_HOST_TO_IOC |
2925e0f553abSKashyap, Desai MPI_SGE_FLAGS_END_OF_BUFFER;
2926e0f553abSKashyap, Desai flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2927e0f553abSKashyap, Desai flagsLength |= sizeof(struct rep_manu_request);
2928e0f553abSKashyap, Desai
2929e0f553abSKashyap, Desai ioc->add_sge(psge, flagsLength, data_out_dma);
2930e0f553abSKashyap, Desai psge += ioc->SGE_size;
2931e0f553abSKashyap, Desai
2932e0f553abSKashyap, Desai flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2933e0f553abSKashyap, Desai MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2934e0f553abSKashyap, Desai MPI_SGE_FLAGS_IOC_TO_HOST |
2935e0f553abSKashyap, Desai MPI_SGE_FLAGS_END_OF_BUFFER;
2936e0f553abSKashyap, Desai flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2937e0f553abSKashyap, Desai flagsLength |= sizeof(struct rep_manu_reply);
2938e0f553abSKashyap, Desai ioc->add_sge(psge, flagsLength, data_out_dma +
2939e0f553abSKashyap, Desai sizeof(struct rep_manu_request));
2940e0f553abSKashyap, Desai
2941e0f553abSKashyap, Desai INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2942e0f553abSKashyap, Desai mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2943e0f553abSKashyap, Desai
2944e0f553abSKashyap, Desai timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2945e0f553abSKashyap, Desai if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2946e0f553abSKashyap, Desai ret = -ETIME;
2947e0f553abSKashyap, Desai mpt_free_msg_frame(ioc, mf);
2948e0f553abSKashyap, Desai mf = NULL;
2949e0f553abSKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2950e0f553abSKashyap, Desai goto out_free;
2951e0f553abSKashyap, Desai if (!timeleft)
2952d0f698c4SKashyap, Desai mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
2953e0f553abSKashyap, Desai goto out_free;
2954e0f553abSKashyap, Desai }
2955e0f553abSKashyap, Desai
2956e0f553abSKashyap, Desai mf = NULL;
2957e0f553abSKashyap, Desai
2958e0f553abSKashyap, Desai if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2959e0f553abSKashyap, Desai u8 *tmp;
2960e0f553abSKashyap, Desai
2961e0f553abSKashyap, Desai smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2962e0f553abSKashyap, Desai if (le16_to_cpu(smprep->ResponseDataLength) !=
2963e0f553abSKashyap, Desai sizeof(struct rep_manu_reply))
2964e0f553abSKashyap, Desai goto out_free;
2965e0f553abSKashyap, Desai
2966e0f553abSKashyap, Desai manufacture_reply = data_out + sizeof(struct rep_manu_request);
2967e0f553abSKashyap, Desai strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2968e0f553abSKashyap, Desai SAS_EXPANDER_VENDOR_ID_LEN);
2969e0f553abSKashyap, Desai strncpy(edev->product_id, manufacture_reply->product_id,
2970e0f553abSKashyap, Desai SAS_EXPANDER_PRODUCT_ID_LEN);
2971e0f553abSKashyap, Desai strncpy(edev->product_rev, manufacture_reply->product_rev,
2972e0f553abSKashyap, Desai SAS_EXPANDER_PRODUCT_REV_LEN);
2973e0f553abSKashyap, Desai edev->level = manufacture_reply->sas_format;
2974e0f553abSKashyap, Desai if (manufacture_reply->sas_format) {
2975e0f553abSKashyap, Desai strncpy(edev->component_vendor_id,
2976e0f553abSKashyap, Desai manufacture_reply->component_vendor_id,
2977e0f553abSKashyap, Desai SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2978e0f553abSKashyap, Desai tmp = (u8 *)&manufacture_reply->component_id;
2979e0f553abSKashyap, Desai edev->component_id = tmp[0] << 8 | tmp[1];
2980e0f553abSKashyap, Desai edev->component_revision_id =
2981e0f553abSKashyap, Desai manufacture_reply->component_revision_id;
2982e0f553abSKashyap, Desai }
2983e0f553abSKashyap, Desai } else {
2984e0f553abSKashyap, Desai printk(MYIOC_s_ERR_FMT
2985e0f553abSKashyap, Desai "%s: smp passthru reply failed to be returned\n",
2986e0f553abSKashyap, Desai ioc->name, __func__);
2987e0f553abSKashyap, Desai ret = -ENXIO;
2988e0f553abSKashyap, Desai }
2989e0f553abSKashyap, Desai out_free:
2990e0f553abSKashyap, Desai if (data_out_dma)
2991b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, sz, data_out,
2992b114dda6SChristophe JAILLET data_out_dma);
2993e0f553abSKashyap, Desai put_mf:
2994e0f553abSKashyap, Desai if (mf)
2995e0f553abSKashyap, Desai mpt_free_msg_frame(ioc, mf);
2996e0f553abSKashyap, Desai out_unlock:
2997e0f553abSKashyap, Desai CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2998e0f553abSKashyap, Desai mutex_unlock(&ioc->sas_mgmt.mutex);
2999e0f553abSKashyap, Desai out:
3000e0f553abSKashyap, Desai return ret;
3001e0f553abSKashyap, Desai }
3002e0f553abSKashyap, Desai
30030c33b27dSChristoph Hellwig static void
mptsas_parse_device_info(struct sas_identify * identify,struct mptsas_devinfo * device_info)30040c33b27dSChristoph Hellwig mptsas_parse_device_info(struct sas_identify *identify,
30050c33b27dSChristoph Hellwig struct mptsas_devinfo *device_info)
30060c33b27dSChristoph Hellwig {
30070c33b27dSChristoph Hellwig u16 protocols;
30080c33b27dSChristoph Hellwig
30090c33b27dSChristoph Hellwig identify->sas_address = device_info->sas_address;
30100c33b27dSChristoph Hellwig identify->phy_identifier = device_info->phy_id;
30110c33b27dSChristoph Hellwig
30120c33b27dSChristoph Hellwig /*
30130c33b27dSChristoph Hellwig * Fill in Phy Initiator Port Protocol.
30140c33b27dSChristoph Hellwig * Bits 6:3, more than one bit can be set, fall through cases.
30150c33b27dSChristoph Hellwig */
30160c33b27dSChristoph Hellwig protocols = device_info->device_info & 0x78;
30170c33b27dSChristoph Hellwig identify->initiator_port_protocols = 0;
30180c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
30190c33b27dSChristoph Hellwig identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
30200c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
30210c33b27dSChristoph Hellwig identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
30220c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
30230c33b27dSChristoph Hellwig identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
30240c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
30250c33b27dSChristoph Hellwig identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
30260c33b27dSChristoph Hellwig
30270c33b27dSChristoph Hellwig /*
30280c33b27dSChristoph Hellwig * Fill in Phy Target Port Protocol.
30290c33b27dSChristoph Hellwig * Bits 10:7, more than one bit can be set, fall through cases.
30300c33b27dSChristoph Hellwig */
30310c33b27dSChristoph Hellwig protocols = device_info->device_info & 0x780;
30320c33b27dSChristoph Hellwig identify->target_port_protocols = 0;
30330c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
30340c33b27dSChristoph Hellwig identify->target_port_protocols |= SAS_PROTOCOL_SSP;
30350c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
30360c33b27dSChristoph Hellwig identify->target_port_protocols |= SAS_PROTOCOL_STP;
30370c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
30380c33b27dSChristoph Hellwig identify->target_port_protocols |= SAS_PROTOCOL_SMP;
30390c33b27dSChristoph Hellwig if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
30400c33b27dSChristoph Hellwig identify->target_port_protocols |= SAS_PROTOCOL_SATA;
30410c33b27dSChristoph Hellwig
30420c33b27dSChristoph Hellwig /*
30430c33b27dSChristoph Hellwig * Fill in Attached device type.
30440c33b27dSChristoph Hellwig */
30450c33b27dSChristoph Hellwig switch (device_info->device_info &
30460c33b27dSChristoph Hellwig MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
30470c33b27dSChristoph Hellwig case MPI_SAS_DEVICE_INFO_NO_DEVICE:
30480c33b27dSChristoph Hellwig identify->device_type = SAS_PHY_UNUSED;
30490c33b27dSChristoph Hellwig break;
30500c33b27dSChristoph Hellwig case MPI_SAS_DEVICE_INFO_END_DEVICE:
30510c33b27dSChristoph Hellwig identify->device_type = SAS_END_DEVICE;
30520c33b27dSChristoph Hellwig break;
30530c33b27dSChristoph Hellwig case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
30540c33b27dSChristoph Hellwig identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
30550c33b27dSChristoph Hellwig break;
30560c33b27dSChristoph Hellwig case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
30570c33b27dSChristoph Hellwig identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
30580c33b27dSChristoph Hellwig break;
30590c33b27dSChristoph Hellwig }
30600c33b27dSChristoph Hellwig }
30610c33b27dSChristoph Hellwig
mptsas_probe_one_phy(struct device * dev,struct mptsas_phyinfo * phy_info,int index,int local)30620c33b27dSChristoph Hellwig static int mptsas_probe_one_phy(struct device *dev,
3063ac01bbbdSChristoph Hellwig struct mptsas_phyinfo *phy_info, int index, int local)
30640c33b27dSChristoph Hellwig {
3065e6b2d76aSMoore, Eric MPT_ADAPTER *ioc;
30669a28f49aSChristoph Hellwig struct sas_phy *phy;
3067547f9a21SEric Moore struct sas_port *port;
3068547f9a21SEric Moore int error = 0;
3069c9de7dc4SKashyap, Desai VirtTarget *vtarget;
30700c33b27dSChristoph Hellwig
3071547f9a21SEric Moore if (!dev) {
3072547f9a21SEric Moore error = -ENODEV;
3073547f9a21SEric Moore goto out;
3074547f9a21SEric Moore }
3075e6b2d76aSMoore, Eric
3076e6b2d76aSMoore, Eric if (!phy_info->phy) {
30779a28f49aSChristoph Hellwig phy = sas_phy_alloc(dev, index);
3078547f9a21SEric Moore if (!phy) {
3079547f9a21SEric Moore error = -ENOMEM;
3080547f9a21SEric Moore goto out;
3081547f9a21SEric Moore }
3082e6b2d76aSMoore, Eric } else
3083e6b2d76aSMoore, Eric phy = phy_info->phy;
30840c33b27dSChristoph Hellwig
30859a28f49aSChristoph Hellwig mptsas_parse_device_info(&phy->identify, &phy_info->identify);
30860c33b27dSChristoph Hellwig
30870c33b27dSChristoph Hellwig /*
30880c33b27dSChristoph Hellwig * Set Negotiated link rate.
30890c33b27dSChristoph Hellwig */
30900c33b27dSChristoph Hellwig switch (phy_info->negotiated_link_rate) {
30910c33b27dSChristoph Hellwig case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
30929a28f49aSChristoph Hellwig phy->negotiated_linkrate = SAS_PHY_DISABLED;
30930c33b27dSChristoph Hellwig break;
30940c33b27dSChristoph Hellwig case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
30959a28f49aSChristoph Hellwig phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
30960c33b27dSChristoph Hellwig break;
30970c33b27dSChristoph Hellwig case MPI_SAS_IOUNIT0_RATE_1_5:
30989a28f49aSChristoph Hellwig phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
30990c33b27dSChristoph Hellwig break;
31000c33b27dSChristoph Hellwig case MPI_SAS_IOUNIT0_RATE_3_0:
31019a28f49aSChristoph Hellwig phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
31020c33b27dSChristoph Hellwig break;
3103d75733d5SKashyap, Desai case MPI_SAS_IOUNIT0_RATE_6_0:
3104d75733d5SKashyap, Desai phy->negotiated_linkrate = SAS_LINK_RATE_6_0_GBPS;
3105d75733d5SKashyap, Desai break;
31060c33b27dSChristoph Hellwig case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
31070c33b27dSChristoph Hellwig case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
31080c33b27dSChristoph Hellwig default:
31099a28f49aSChristoph Hellwig phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
31100c33b27dSChristoph Hellwig break;
31110c33b27dSChristoph Hellwig }
31120c33b27dSChristoph Hellwig
31130c33b27dSChristoph Hellwig /*
31140c33b27dSChristoph Hellwig * Set Max hardware link rate.
31150c33b27dSChristoph Hellwig */
31160c33b27dSChristoph Hellwig switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
31170c33b27dSChristoph Hellwig case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
31189a28f49aSChristoph Hellwig phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
31190c33b27dSChristoph Hellwig break;
31200c33b27dSChristoph Hellwig case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
31219a28f49aSChristoph Hellwig phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
31220c33b27dSChristoph Hellwig break;
31230c33b27dSChristoph Hellwig default:
31240c33b27dSChristoph Hellwig break;
31250c33b27dSChristoph Hellwig }
31260c33b27dSChristoph Hellwig
31270c33b27dSChristoph Hellwig /*
31280c33b27dSChristoph Hellwig * Set Max programmed link rate.
31290c33b27dSChristoph Hellwig */
31300c33b27dSChristoph Hellwig switch (phy_info->programmed_link_rate &
31310c33b27dSChristoph Hellwig MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
31320c33b27dSChristoph Hellwig case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
31339a28f49aSChristoph Hellwig phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
31340c33b27dSChristoph Hellwig break;
31350c33b27dSChristoph Hellwig case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
31369a28f49aSChristoph Hellwig phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
31370c33b27dSChristoph Hellwig break;
31380c33b27dSChristoph Hellwig default:
31390c33b27dSChristoph Hellwig break;
31400c33b27dSChristoph Hellwig }
31410c33b27dSChristoph Hellwig
31420c33b27dSChristoph Hellwig /*
31430c33b27dSChristoph Hellwig * Set Min hardware link rate.
31440c33b27dSChristoph Hellwig */
31450c33b27dSChristoph Hellwig switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
31460c33b27dSChristoph Hellwig case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
31479a28f49aSChristoph Hellwig phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
31480c33b27dSChristoph Hellwig break;
31490c33b27dSChristoph Hellwig case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
31509a28f49aSChristoph Hellwig phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
31510c33b27dSChristoph Hellwig break;
31520c33b27dSChristoph Hellwig default:
31530c33b27dSChristoph Hellwig break;
31540c33b27dSChristoph Hellwig }
31550c33b27dSChristoph Hellwig
31560c33b27dSChristoph Hellwig /*
31570c33b27dSChristoph Hellwig * Set Min programmed link rate.
31580c33b27dSChristoph Hellwig */
31590c33b27dSChristoph Hellwig switch (phy_info->programmed_link_rate &
31600c33b27dSChristoph Hellwig MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
31610c33b27dSChristoph Hellwig case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
31629a28f49aSChristoph Hellwig phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
31630c33b27dSChristoph Hellwig break;
31640c33b27dSChristoph Hellwig case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
31659a28f49aSChristoph Hellwig phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
31660c33b27dSChristoph Hellwig break;
31670c33b27dSChristoph Hellwig default:
31680c33b27dSChristoph Hellwig break;
31690c33b27dSChristoph Hellwig }
31700c33b27dSChristoph Hellwig
3171e6b2d76aSMoore, Eric if (!phy_info->phy) {
3172e6b2d76aSMoore, Eric
31739a28f49aSChristoph Hellwig error = sas_phy_add(phy);
31740c33b27dSChristoph Hellwig if (error) {
31759a28f49aSChristoph Hellwig sas_phy_free(phy);
3176547f9a21SEric Moore goto out;
31770c33b27dSChristoph Hellwig }
31789a28f49aSChristoph Hellwig phy_info->phy = phy;
3179e6b2d76aSMoore, Eric }
31800c33b27dSChristoph Hellwig
3181547f9a21SEric Moore if (!phy_info->attached.handle ||
3182547f9a21SEric Moore !phy_info->port_details)
3183547f9a21SEric Moore goto out;
3184547f9a21SEric Moore
3185547f9a21SEric Moore port = mptsas_get_port(phy_info);
3186547f9a21SEric Moore ioc = phy_to_ioc(phy_info->phy);
3187547f9a21SEric Moore
3188547f9a21SEric Moore if (phy_info->sas_port_add_phy) {
3189547f9a21SEric Moore
3190547f9a21SEric Moore if (!port) {
3191dc22f16dSEric Moore port = sas_port_alloc_num(dev);
3192547f9a21SEric Moore if (!port) {
3193547f9a21SEric Moore error = -ENOMEM;
3194547f9a21SEric Moore goto out;
3195547f9a21SEric Moore }
3196547f9a21SEric Moore error = sas_port_add(port);
3197547f9a21SEric Moore if (error) {
3198d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3199547f9a21SEric Moore "%s: exit at line=%d\n", ioc->name,
3200cadbd4a5SHarvey Harrison __func__, __LINE__));
3201547f9a21SEric Moore goto out;
3202547f9a21SEric Moore }
3203d6ecdd63SPrakash, Sathya mptsas_set_port(ioc, phy_info, port);
32042f187862SKashyap, Desai devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
32052f187862SKashyap, Desai MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
32062f187862SKashyap, Desai ioc->name, port->port_identifier,
32072f187862SKashyap, Desai (unsigned long long)phy_info->
32082f187862SKashyap, Desai attached.sas_address));
3209547f9a21SEric Moore }
32102f187862SKashyap, Desai dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
32112f187862SKashyap, Desai "sas_port_add_phy: phy_id=%d\n",
321229dd3609SEric Moore ioc->name, phy_info->phy_id));
3213547f9a21SEric Moore sas_port_add_phy(port, phy_info->phy);
3214547f9a21SEric Moore phy_info->sas_port_add_phy = 0;
32152f187862SKashyap, Desai devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
32162f187862SKashyap, Desai MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
32172f187862SKashyap, Desai phy_info->phy_id, phy_info->phy));
3218547f9a21SEric Moore }
3219547f9a21SEric Moore if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
3220e6b2d76aSMoore, Eric
32210c33b27dSChristoph Hellwig struct sas_rphy *rphy;
32222686de27SJames Bottomley struct device *parent;
3223f013db32SJames Bottomley struct sas_identify identify;
32240c33b27dSChristoph Hellwig
32252686de27SJames Bottomley parent = dev->parent->parent;
3226e6b2d76aSMoore, Eric /*
3227e6b2d76aSMoore, Eric * Let the hotplug_work thread handle processing
3228e6b2d76aSMoore, Eric * the adding/removing of devices that occur
3229e6b2d76aSMoore, Eric * after start of day.
3230e6b2d76aSMoore, Eric */
32312f187862SKashyap, Desai if (mptsas_is_end_device(&phy_info->attached) &&
32322f187862SKashyap, Desai phy_info->attached.handle_parent) {
3233547f9a21SEric Moore goto out;
32342f187862SKashyap, Desai }
3235e6b2d76aSMoore, Eric
3236f013db32SJames Bottomley mptsas_parse_device_info(&identify, &phy_info->attached);
32372686de27SJames Bottomley if (scsi_is_host_device(parent)) {
32382686de27SJames Bottomley struct mptsas_portinfo *port_info;
32392686de27SJames Bottomley int i;
32402686de27SJames Bottomley
3241f9c34022SKashyap, Desai port_info = ioc->hba_port_info;
32422686de27SJames Bottomley
32432686de27SJames Bottomley for (i = 0; i < port_info->num_phys; i++)
32442686de27SJames Bottomley if (port_info->phy_info[i].identify.sas_address ==
32450c269e6dSJames Bottomley identify.sas_address) {
32460c269e6dSJames Bottomley sas_port_mark_backlink(port);
32472686de27SJames Bottomley goto out;
32480c269e6dSJames Bottomley }
32492686de27SJames Bottomley
32502686de27SJames Bottomley } else if (scsi_is_sas_rphy(parent)) {
32512686de27SJames Bottomley struct sas_rphy *parent_rphy = dev_to_rphy(parent);
32522686de27SJames Bottomley if (identify.sas_address ==
32530c269e6dSJames Bottomley parent_rphy->identify.sas_address) {
32540c269e6dSJames Bottomley sas_port_mark_backlink(port);
32552686de27SJames Bottomley goto out;
32562686de27SJames Bottomley }
32570c269e6dSJames Bottomley }
32582686de27SJames Bottomley
3259f013db32SJames Bottomley switch (identify.device_type) {
3260f013db32SJames Bottomley case SAS_END_DEVICE:
3261547f9a21SEric Moore rphy = sas_end_device_alloc(port);
3262f013db32SJames Bottomley break;
3263f013db32SJames Bottomley case SAS_EDGE_EXPANDER_DEVICE:
3264f013db32SJames Bottomley case SAS_FANOUT_EXPANDER_DEVICE:
3265547f9a21SEric Moore rphy = sas_expander_alloc(port, identify.device_type);
3266f013db32SJames Bottomley break;
3267f013db32SJames Bottomley default:
3268f013db32SJames Bottomley rphy = NULL;
3269f013db32SJames Bottomley break;
3270f013db32SJames Bottomley }
3271547f9a21SEric Moore if (!rphy) {
3272d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3273547f9a21SEric Moore "%s: exit at line=%d\n", ioc->name,
3274cadbd4a5SHarvey Harrison __func__, __LINE__));
3275547f9a21SEric Moore goto out;
3276547f9a21SEric Moore }
32770c33b27dSChristoph Hellwig
3278f013db32SJames Bottomley rphy->identify = identify;
32790c33b27dSChristoph Hellwig error = sas_rphy_add(rphy);
32800c33b27dSChristoph Hellwig if (error) {
3281d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3282547f9a21SEric Moore "%s: exit at line=%d\n", ioc->name,
3283cadbd4a5SHarvey Harrison __func__, __LINE__));
32840c33b27dSChristoph Hellwig sas_rphy_free(rphy);
3285547f9a21SEric Moore goto out;
3286547f9a21SEric Moore }
3287d6ecdd63SPrakash, Sathya mptsas_set_rphy(ioc, phy_info, rphy);
3288e0f553abSKashyap, Desai if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3289e0f553abSKashyap, Desai identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3290e0f553abSKashyap, Desai mptsas_exp_repmanufacture_info(ioc,
3291e0f553abSKashyap, Desai identify.sas_address,
3292e0f553abSKashyap, Desai rphy_to_expander_device(rphy));
3293547f9a21SEric Moore }
3294547f9a21SEric Moore
3295c9de7dc4SKashyap, Desai /* If the device exists, verify it wasn't previously flagged
3296c9de7dc4SKashyap, Desai as a missing device. If so, clear it */
3297c9de7dc4SKashyap, Desai vtarget = mptsas_find_vtarget(ioc,
3298c9de7dc4SKashyap, Desai phy_info->attached.channel,
3299c9de7dc4SKashyap, Desai phy_info->attached.id);
3300c9de7dc4SKashyap, Desai if (vtarget && vtarget->inDMD) {
3301c9de7dc4SKashyap, Desai printk(KERN_INFO "Device returned, unsetting inDMD\n");
3302c9de7dc4SKashyap, Desai vtarget->inDMD = 0;
3303c9de7dc4SKashyap, Desai }
3304c9de7dc4SKashyap, Desai
3305547f9a21SEric Moore out:
33060c33b27dSChristoph Hellwig return error;
33070c33b27dSChristoph Hellwig }
33080c33b27dSChristoph Hellwig
33090c33b27dSChristoph Hellwig static int
mptsas_probe_hba_phys(MPT_ADAPTER * ioc)3310e6b2d76aSMoore, Eric mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
33110c33b27dSChristoph Hellwig {
3312e6b2d76aSMoore, Eric struct mptsas_portinfo *port_info, *hba;
33130c33b27dSChristoph Hellwig int error = -ENOMEM, i;
33140c33b27dSChristoph Hellwig
3315f9c34022SKashyap, Desai hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3316e6b2d76aSMoore, Eric if (! hba)
33170c33b27dSChristoph Hellwig goto out;
33180c33b27dSChristoph Hellwig
3319e6b2d76aSMoore, Eric error = mptsas_sas_io_unit_pg0(ioc, hba);
33200c33b27dSChristoph Hellwig if (error)
33210c33b27dSChristoph Hellwig goto out_free_port_info;
33220c33b27dSChristoph Hellwig
3323edb9068dSPrakash, Sathya mptsas_sas_io_unit_pg1(ioc);
33249a28f49aSChristoph Hellwig mutex_lock(&ioc->sas_topology_mutex);
3325f9c34022SKashyap, Desai port_info = ioc->hba_port_info;
3326e6b2d76aSMoore, Eric if (!port_info) {
3327f9c34022SKashyap, Desai ioc->hba_port_info = port_info = hba;
3328f9c34022SKashyap, Desai ioc->hba_port_num_phy = port_info->num_phys;
33290c33b27dSChristoph Hellwig list_add_tail(&port_info->list, &ioc->sas_topology);
3330e6b2d76aSMoore, Eric } else {
33312ecce492SEric Moore for (i = 0; i < hba->num_phys; i++) {
3332e6b2d76aSMoore, Eric port_info->phy_info[i].negotiated_link_rate =
3333e6b2d76aSMoore, Eric hba->phy_info[i].negotiated_link_rate;
33342ecce492SEric Moore port_info->phy_info[i].handle =
33352ecce492SEric Moore hba->phy_info[i].handle;
33362ecce492SEric Moore port_info->phy_info[i].port_id =
33372ecce492SEric Moore hba->phy_info[i].port_id;
33382ecce492SEric Moore }
3339e6b2d76aSMoore, Eric kfree(hba->phy_info);
3340e6b2d76aSMoore, Eric kfree(hba);
3341e6b2d76aSMoore, Eric hba = NULL;
3342e6b2d76aSMoore, Eric }
33439a28f49aSChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
3344f9c34022SKashyap, Desai #if defined(CPQ_CIM)
3345f9c34022SKashyap, Desai ioc->num_ports = port_info->num_phys;
3346f9c34022SKashyap, Desai #endif
33470c33b27dSChristoph Hellwig for (i = 0; i < port_info->num_phys; i++) {
33480c33b27dSChristoph Hellwig mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
33490c33b27dSChristoph Hellwig (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
33500c33b27dSChristoph Hellwig MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
3351f9c34022SKashyap, Desai port_info->phy_info[i].identify.handle =
3352f9c34022SKashyap, Desai port_info->phy_info[i].handle;
33530c33b27dSChristoph Hellwig mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
33542ecce492SEric Moore (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
33552ecce492SEric Moore MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3356f9c34022SKashyap, Desai port_info->phy_info[i].identify.handle);
3357f9c34022SKashyap, Desai if (!ioc->hba_port_sas_addr)
3358f9c34022SKashyap, Desai ioc->hba_port_sas_addr =
3359f9c34022SKashyap, Desai port_info->phy_info[i].identify.sas_address;
3360024358eeSEric Moore port_info->phy_info[i].identify.phy_id =
33612ecce492SEric Moore port_info->phy_info[i].phy_id = i;
3362547f9a21SEric Moore if (port_info->phy_info[i].attached.handle)
33630c33b27dSChristoph Hellwig mptsas_sas_device_pg0(ioc,
33640c33b27dSChristoph Hellwig &port_info->phy_info[i].attached,
33650c33b27dSChristoph Hellwig (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
33660c33b27dSChristoph Hellwig MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
33670c33b27dSChristoph Hellwig port_info->phy_info[i].attached.handle);
33680c33b27dSChristoph Hellwig }
33690c33b27dSChristoph Hellwig
3370547f9a21SEric Moore mptsas_setup_wide_ports(ioc, port_info);
3371547f9a21SEric Moore
3372547f9a21SEric Moore for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
33730c33b27dSChristoph Hellwig mptsas_probe_one_phy(&ioc->sh->shost_gendev,
3374e6b2d76aSMoore, Eric &port_info->phy_info[i], ioc->sas_index, 1);
33750c33b27dSChristoph Hellwig
33760c33b27dSChristoph Hellwig return 0;
33770c33b27dSChristoph Hellwig
33780c33b27dSChristoph Hellwig out_free_port_info:
3379e6b2d76aSMoore, Eric kfree(hba);
33800c33b27dSChristoph Hellwig out:
33810c33b27dSChristoph Hellwig return error;
33820c33b27dSChristoph Hellwig }
33830c33b27dSChristoph Hellwig
3384f9c34022SKashyap, Desai static void
mptsas_expander_refresh(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info)3385f9c34022SKashyap, Desai mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
33860c33b27dSChristoph Hellwig {
3387f9c34022SKashyap, Desai struct mptsas_portinfo *parent;
3388f9c34022SKashyap, Desai struct device *parent_dev;
3389547f9a21SEric Moore struct sas_rphy *rphy;
3390f9c34022SKashyap, Desai int i;
3391f9c34022SKashyap, Desai u64 sas_address; /* expander sas address */
3392f9c34022SKashyap, Desai u32 handle;
33930c33b27dSChristoph Hellwig
3394f9c34022SKashyap, Desai handle = port_info->phy_info[0].handle;
3395f9c34022SKashyap, Desai sas_address = port_info->phy_info[0].identify.sas_address;
33960c33b27dSChristoph Hellwig for (i = 0; i < port_info->num_phys; i++) {
33970c33b27dSChristoph Hellwig mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
33980c33b27dSChristoph Hellwig (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3399f9c34022SKashyap, Desai MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
34000c33b27dSChristoph Hellwig
34010c33b27dSChristoph Hellwig mptsas_sas_device_pg0(ioc,
34020c33b27dSChristoph Hellwig &port_info->phy_info[i].identify,
34030c33b27dSChristoph Hellwig (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
34040c33b27dSChristoph Hellwig MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
34050c33b27dSChristoph Hellwig port_info->phy_info[i].identify.handle);
3406024358eeSEric Moore port_info->phy_info[i].identify.phy_id =
3407024358eeSEric Moore port_info->phy_info[i].phy_id;
34080c33b27dSChristoph Hellwig
34090c33b27dSChristoph Hellwig if (port_info->phy_info[i].attached.handle) {
34100c33b27dSChristoph Hellwig mptsas_sas_device_pg0(ioc,
34110c33b27dSChristoph Hellwig &port_info->phy_info[i].attached,
34120c33b27dSChristoph Hellwig (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
34130c33b27dSChristoph Hellwig MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
34140c33b27dSChristoph Hellwig port_info->phy_info[i].attached.handle);
3415db9c9174SMoore, Eric port_info->phy_info[i].attached.phy_id =
3416db9c9174SMoore, Eric port_info->phy_info[i].phy_id;
34170c33b27dSChristoph Hellwig }
3418547f9a21SEric Moore }
34190c33b27dSChristoph Hellwig
34209a28f49aSChristoph Hellwig mutex_lock(&ioc->sas_topology_mutex);
3421f9c34022SKashyap, Desai parent = mptsas_find_portinfo_by_handle(ioc,
3422f9c34022SKashyap, Desai port_info->phy_info[0].identify.handle_parent);
3423f9c34022SKashyap, Desai if (!parent) {
3424f9c34022SKashyap, Desai mutex_unlock(&ioc->sas_topology_mutex);
3425f9c34022SKashyap, Desai return;
3426f9c34022SKashyap, Desai }
3427f9c34022SKashyap, Desai for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3428f9c34022SKashyap, Desai i++) {
3429f9c34022SKashyap, Desai if (parent->phy_info[i].attached.sas_address == sas_address) {
3430f9c34022SKashyap, Desai rphy = mptsas_get_rphy(&parent->phy_info[i]);
3431f9c34022SKashyap, Desai parent_dev = &rphy->dev;
34320c33b27dSChristoph Hellwig }
34330c33b27dSChristoph Hellwig }
34349a28f49aSChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
34350c33b27dSChristoph Hellwig
3436547f9a21SEric Moore mptsas_setup_wide_ports(ioc, port_info);
3437547f9a21SEric Moore for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3438f9c34022SKashyap, Desai mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3439e6b2d76aSMoore, Eric ioc->sas_index, 0);
34400c33b27dSChristoph Hellwig }
34410c33b27dSChristoph Hellwig
3442e6b2d76aSMoore, Eric static void
mptsas_expander_event_add(MPT_ADAPTER * ioc,MpiEventDataSasExpanderStatusChange_t * expander_data)3443f9c34022SKashyap, Desai mptsas_expander_event_add(MPT_ADAPTER *ioc,
3444f9c34022SKashyap, Desai MpiEventDataSasExpanderStatusChange_t *expander_data)
3445e6b2d76aSMoore, Eric {
3446f9c34022SKashyap, Desai struct mptsas_portinfo *port_info;
3447e6b2d76aSMoore, Eric int i;
3448f9c34022SKashyap, Desai __le64 sas_address;
3449f9c34022SKashyap, Desai
3450f9c34022SKashyap, Desai port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
34514dec8004Szhouchuangao BUG_ON(!port_info);
3452f9c34022SKashyap, Desai port_info->num_phys = (expander_data->NumPhys) ?
3453f9c34022SKashyap, Desai expander_data->NumPhys : 1;
3454f9c34022SKashyap, Desai port_info->phy_info = kcalloc(port_info->num_phys,
3455f9c34022SKashyap, Desai sizeof(struct mptsas_phyinfo), GFP_KERNEL);
34564dec8004Szhouchuangao BUG_ON(!port_info->phy_info);
3457f9c34022SKashyap, Desai memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3458f9c34022SKashyap, Desai for (i = 0; i < port_info->num_phys; i++) {
3459f9c34022SKashyap, Desai port_info->phy_info[i].portinfo = port_info;
3460f9c34022SKashyap, Desai port_info->phy_info[i].handle =
3461f9c34022SKashyap, Desai le16_to_cpu(expander_data->DevHandle);
3462f9c34022SKashyap, Desai port_info->phy_info[i].identify.sas_address =
3463f9c34022SKashyap, Desai le64_to_cpu(sas_address);
3464f9c34022SKashyap, Desai port_info->phy_info[i].identify.handle_parent =
3465f9c34022SKashyap, Desai le16_to_cpu(expander_data->ParentDevHandle);
3466f9c34022SKashyap, Desai }
3467e6b2d76aSMoore, Eric
3468e6b2d76aSMoore, Eric mutex_lock(&ioc->sas_topology_mutex);
3469f9c34022SKashyap, Desai list_add_tail(&port_info->list, &ioc->sas_topology);
3470f9c34022SKashyap, Desai mutex_unlock(&ioc->sas_topology_mutex);
3471e6b2d76aSMoore, Eric
3472f9c34022SKashyap, Desai printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3473f9c34022SKashyap, Desai "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3474f9c34022SKashyap, Desai (unsigned long long)sas_address);
3475f9c34022SKashyap, Desai
3476f9c34022SKashyap, Desai mptsas_expander_refresh(ioc, port_info);
3477f9c34022SKashyap, Desai }
3478f9c34022SKashyap, Desai
3479f9c34022SKashyap, Desai /**
3480f9c34022SKashyap, Desai * mptsas_delete_expander_siblings - remove siblings attached to expander
3481f9c34022SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
3482f9c34022SKashyap, Desai * @parent: the parent port_info object
3483f9c34022SKashyap, Desai * @expander: the expander port_info object
3484f9c34022SKashyap, Desai **/
3485f9c34022SKashyap, Desai static void
mptsas_delete_expander_siblings(MPT_ADAPTER * ioc,struct mptsas_portinfo * parent,struct mptsas_portinfo * expander)3486f9c34022SKashyap, Desai mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3487f9c34022SKashyap, Desai *parent, struct mptsas_portinfo *expander)
3488f9c34022SKashyap, Desai {
3489f9c34022SKashyap, Desai struct mptsas_phyinfo *phy_info;
3490f9c34022SKashyap, Desai struct mptsas_portinfo *port_info;
3491f9c34022SKashyap, Desai struct sas_rphy *rphy;
3492f9c34022SKashyap, Desai int i;
3493f9c34022SKashyap, Desai
3494f9c34022SKashyap, Desai phy_info = expander->phy_info;
3495f9c34022SKashyap, Desai for (i = 0; i < expander->num_phys; i++, phy_info++) {
3496f9c34022SKashyap, Desai rphy = mptsas_get_rphy(phy_info);
3497f9c34022SKashyap, Desai if (!rphy)
3498e6b2d76aSMoore, Eric continue;
3499f9c34022SKashyap, Desai if (rphy->identify.device_type == SAS_END_DEVICE)
3500f9c34022SKashyap, Desai mptsas_del_end_device(ioc, phy_info);
3501f9c34022SKashyap, Desai }
3502e6b2d76aSMoore, Eric
3503f9c34022SKashyap, Desai phy_info = expander->phy_info;
3504f9c34022SKashyap, Desai for (i = 0; i < expander->num_phys; i++, phy_info++) {
3505f9c34022SKashyap, Desai rphy = mptsas_get_rphy(phy_info);
3506f9c34022SKashyap, Desai if (!rphy)
3507f9c34022SKashyap, Desai continue;
3508f9c34022SKashyap, Desai if (rphy->identify.device_type ==
3509f9c34022SKashyap, Desai MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3510f9c34022SKashyap, Desai rphy->identify.device_type ==
3511f9c34022SKashyap, Desai MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3512f9c34022SKashyap, Desai port_info = mptsas_find_portinfo_by_sas_address(ioc,
3513f9c34022SKashyap, Desai rphy->identify.sas_address);
3514f9c34022SKashyap, Desai if (!port_info)
3515f9c34022SKashyap, Desai continue;
3516f9c34022SKashyap, Desai if (port_info == parent) /* backlink rphy */
3517f9c34022SKashyap, Desai continue;
3518f9c34022SKashyap, Desai /*
3519f9c34022SKashyap, Desai Delete this expander even if the expdevpage is exists
3520f9c34022SKashyap, Desai because the parent expander is already deleted
3521f9c34022SKashyap, Desai */
3522f9c34022SKashyap, Desai mptsas_expander_delete(ioc, port_info, 1);
3523f9c34022SKashyap, Desai }
3524f9c34022SKashyap, Desai }
3525f9c34022SKashyap, Desai }
3526f9c34022SKashyap, Desai
3527f9c34022SKashyap, Desai
3528f9c34022SKashyap, Desai /**
3529f9c34022SKashyap, Desai * mptsas_expander_delete - remove this expander
3530f9c34022SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
3531f9c34022SKashyap, Desai * @port_info: expander port_info struct
3532f9c34022SKashyap, Desai * @force: Flag to forcefully delete the expander
3533f9c34022SKashyap, Desai *
3534f9c34022SKashyap, Desai **/
3535f9c34022SKashyap, Desai
mptsas_expander_delete(MPT_ADAPTER * ioc,struct mptsas_portinfo * port_info,u8 force)3536f9c34022SKashyap, Desai static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3537f9c34022SKashyap, Desai struct mptsas_portinfo *port_info, u8 force)
3538f9c34022SKashyap, Desai {
3539f9c34022SKashyap, Desai
3540f9c34022SKashyap, Desai struct mptsas_portinfo *parent;
3541f9c34022SKashyap, Desai int i;
3542f9c34022SKashyap, Desai u64 expander_sas_address;
3543f9c34022SKashyap, Desai struct mptsas_phyinfo *phy_info;
3544f9c34022SKashyap, Desai struct mptsas_portinfo buffer;
3545f9c34022SKashyap, Desai struct mptsas_portinfo_details *port_details;
3546f9c34022SKashyap, Desai struct sas_port *port;
3547f9c34022SKashyap, Desai
3548f9c34022SKashyap, Desai if (!port_info)
3549f9c34022SKashyap, Desai return;
3550f9c34022SKashyap, Desai
3551f9c34022SKashyap, Desai /* see if expander is still there before deleting */
3552f9c34022SKashyap, Desai mptsas_sas_expander_pg0(ioc, &buffer,
3553e6b2d76aSMoore, Eric (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
35542ecce492SEric Moore MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3555f9c34022SKashyap, Desai port_info->phy_info[0].identify.handle);
3556f9c34022SKashyap, Desai
3557f9c34022SKashyap, Desai if (buffer.num_phys) {
3558f9c34022SKashyap, Desai kfree(buffer.phy_info);
3559f9c34022SKashyap, Desai if (!force)
3560f9c34022SKashyap, Desai return;
3561f9c34022SKashyap, Desai }
3562f9c34022SKashyap, Desai
3563e6b2d76aSMoore, Eric
3564e6b2d76aSMoore, Eric /*
3565e6b2d76aSMoore, Eric * Obtain the port_info instance to the parent port
3566e6b2d76aSMoore, Eric */
3567f9c34022SKashyap, Desai port_details = NULL;
3568547f9a21SEric Moore expander_sas_address =
3569547f9a21SEric Moore port_info->phy_info[0].identify.sas_address;
3570f9c34022SKashyap, Desai parent = mptsas_find_portinfo_by_handle(ioc,
3571f9c34022SKashyap, Desai port_info->phy_info[0].identify.handle_parent);
3572f9c34022SKashyap, Desai mptsas_delete_expander_siblings(ioc, parent, port_info);
3573f9c34022SKashyap, Desai if (!parent)
3574f9c34022SKashyap, Desai goto out;
3575547f9a21SEric Moore
3576e6b2d76aSMoore, Eric /*
3577e6b2d76aSMoore, Eric * Delete rphys in the parent that point
3578f9c34022SKashyap, Desai * to this expander.
3579e6b2d76aSMoore, Eric */
3580547f9a21SEric Moore phy_info = parent->phy_info;
3581f9c34022SKashyap, Desai port = NULL;
3582547f9a21SEric Moore for (i = 0; i < parent->num_phys; i++, phy_info++) {
3583f9c34022SKashyap, Desai if (!phy_info->phy)
3584e6b2d76aSMoore, Eric continue;
3585547f9a21SEric Moore if (phy_info->attached.sas_address !=
3586547f9a21SEric Moore expander_sas_address)
3587547f9a21SEric Moore continue;
3588f9c34022SKashyap, Desai if (!port) {
3589f9c34022SKashyap, Desai port = mptsas_get_port(phy_info);
3590f9c34022SKashyap, Desai port_details = phy_info->port_details;
3591e6b2d76aSMoore, Eric }
3592f9c34022SKashyap, Desai dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3593f9c34022SKashyap, Desai MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3594f9c34022SKashyap, Desai phy_info->phy_id, phy_info->phy);
3595f9c34022SKashyap, Desai sas_port_delete_phy(port, phy_info->phy);
3596f9c34022SKashyap, Desai }
3597f9c34022SKashyap, Desai if (port) {
3598f9c34022SKashyap, Desai dev_printk(KERN_DEBUG, &port->dev,
3599f9c34022SKashyap, Desai MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3600f9c34022SKashyap, Desai ioc->name, port->port_identifier,
3601f9c34022SKashyap, Desai (unsigned long long)expander_sas_address);
3602f9c34022SKashyap, Desai sas_port_delete(port);
3603f9c34022SKashyap, Desai mptsas_port_delete(ioc, port_details);
3604f9c34022SKashyap, Desai }
3605f9c34022SKashyap, Desai out:
3606547f9a21SEric Moore
3607f9c34022SKashyap, Desai printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3608f9c34022SKashyap, Desai "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3609f9c34022SKashyap, Desai (unsigned long long)expander_sas_address);
3610547f9a21SEric Moore
3611f9c34022SKashyap, Desai /*
3612f9c34022SKashyap, Desai * free link
3613f9c34022SKashyap, Desai */
3614e6b2d76aSMoore, Eric list_del(&port_info->list);
3615e6b2d76aSMoore, Eric kfree(port_info->phy_info);
3616e6b2d76aSMoore, Eric kfree(port_info);
3617e6b2d76aSMoore, Eric }
3618f9c34022SKashyap, Desai
3619f9c34022SKashyap, Desai
3620f9c34022SKashyap, Desai /**
3621f9c34022SKashyap, Desai * mptsas_send_expander_event - expanders events
3622cdcda465SRandy Dunlap * @fw_event: event data
3623f9c34022SKashyap, Desai *
3624f9c34022SKashyap, Desai *
3625f9c34022SKashyap, Desai * This function handles adding, removing, and refreshing
3626f9c34022SKashyap, Desai * device handles within the expander objects.
3627e6b2d76aSMoore, Eric */
3628f9c34022SKashyap, Desai static void
mptsas_send_expander_event(struct fw_event_work * fw_event)3629f9c34022SKashyap, Desai mptsas_send_expander_event(struct fw_event_work *fw_event)
3630f9c34022SKashyap, Desai {
3631f9c34022SKashyap, Desai MPT_ADAPTER *ioc;
3632f9c34022SKashyap, Desai MpiEventDataSasExpanderStatusChange_t *expander_data;
3633f9c34022SKashyap, Desai struct mptsas_portinfo *port_info;
3634f9c34022SKashyap, Desai __le64 sas_address;
3635f9c34022SKashyap, Desai int i;
3636f9c34022SKashyap, Desai
3637f9c34022SKashyap, Desai ioc = fw_event->ioc;
3638f9c34022SKashyap, Desai expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3639f9c34022SKashyap, Desai fw_event->event_data;
3640f9c34022SKashyap, Desai memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3641f44fd181SKashyap, Desai sas_address = le64_to_cpu(sas_address);
3642f9c34022SKashyap, Desai port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3643f9c34022SKashyap, Desai
3644f9c34022SKashyap, Desai if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3645f9c34022SKashyap, Desai if (port_info) {
3646f9c34022SKashyap, Desai for (i = 0; i < port_info->num_phys; i++) {
3647f9c34022SKashyap, Desai port_info->phy_info[i].portinfo = port_info;
3648f9c34022SKashyap, Desai port_info->phy_info[i].handle =
3649f9c34022SKashyap, Desai le16_to_cpu(expander_data->DevHandle);
3650f9c34022SKashyap, Desai port_info->phy_info[i].identify.sas_address =
3651f9c34022SKashyap, Desai le64_to_cpu(sas_address);
3652f9c34022SKashyap, Desai port_info->phy_info[i].identify.handle_parent =
3653f9c34022SKashyap, Desai le16_to_cpu(expander_data->ParentDevHandle);
3654e6b2d76aSMoore, Eric }
3655f9c34022SKashyap, Desai mptsas_expander_refresh(ioc, port_info);
3656f9c34022SKashyap, Desai } else if (!port_info && expander_data->NumPhys)
3657f9c34022SKashyap, Desai mptsas_expander_event_add(ioc, expander_data);
3658f9c34022SKashyap, Desai } else if (expander_data->ReasonCode ==
3659f9c34022SKashyap, Desai MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3660f9c34022SKashyap, Desai mptsas_expander_delete(ioc, port_info, 0);
3661f9c34022SKashyap, Desai
3662f9c34022SKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
3663f9c34022SKashyap, Desai }
3664f9c34022SKashyap, Desai
3665f9c34022SKashyap, Desai
3666f9c34022SKashyap, Desai /**
3667cdcda465SRandy Dunlap * mptsas_expander_add - adds a newly discovered expander
3668f9c34022SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
3669cdcda465SRandy Dunlap * @handle: device handle
3670f9c34022SKashyap, Desai *
3671f9c34022SKashyap, Desai */
36725767d25fSJoe Lawrence static struct mptsas_portinfo *
mptsas_expander_add(MPT_ADAPTER * ioc,u16 handle)3673f9c34022SKashyap, Desai mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3674f9c34022SKashyap, Desai {
3675f9c34022SKashyap, Desai struct mptsas_portinfo buffer, *port_info;
3676f9c34022SKashyap, Desai int i;
3677f9c34022SKashyap, Desai
3678f9c34022SKashyap, Desai if ((mptsas_sas_expander_pg0(ioc, &buffer,
3679f9c34022SKashyap, Desai (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3680f9c34022SKashyap, Desai MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3681f9c34022SKashyap, Desai return NULL;
3682f9c34022SKashyap, Desai
3683e3af2e3bSChristophe JAILLET port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3684f9c34022SKashyap, Desai if (!port_info) {
3685f9c34022SKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3686f9c34022SKashyap, Desai "%s: exit at line=%d\n", ioc->name,
3687f9c34022SKashyap, Desai __func__, __LINE__));
3688f9c34022SKashyap, Desai return NULL;
3689f9c34022SKashyap, Desai }
3690f9c34022SKashyap, Desai port_info->num_phys = buffer.num_phys;
3691f9c34022SKashyap, Desai port_info->phy_info = buffer.phy_info;
3692f9c34022SKashyap, Desai for (i = 0; i < port_info->num_phys; i++)
3693f9c34022SKashyap, Desai port_info->phy_info[i].portinfo = port_info;
3694f9c34022SKashyap, Desai mutex_lock(&ioc->sas_topology_mutex);
3695f9c34022SKashyap, Desai list_add_tail(&port_info->list, &ioc->sas_topology);
3696e6b2d76aSMoore, Eric mutex_unlock(&ioc->sas_topology_mutex);
3697f9c34022SKashyap, Desai printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3698f9c34022SKashyap, Desai "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3699f9c34022SKashyap, Desai (unsigned long long)buffer.phy_info[0].identify.sas_address);
3700f9c34022SKashyap, Desai mptsas_expander_refresh(ioc, port_info);
3701f9c34022SKashyap, Desai return port_info;
3702f9c34022SKashyap, Desai }
3703f9c34022SKashyap, Desai
3704f9c34022SKashyap, Desai static void
mptsas_send_link_status_event(struct fw_event_work * fw_event)3705f9c34022SKashyap, Desai mptsas_send_link_status_event(struct fw_event_work *fw_event)
3706f9c34022SKashyap, Desai {
3707f9c34022SKashyap, Desai MPT_ADAPTER *ioc;
3708f9c34022SKashyap, Desai MpiEventDataSasPhyLinkStatus_t *link_data;
3709f9c34022SKashyap, Desai struct mptsas_portinfo *port_info;
3710f9c34022SKashyap, Desai struct mptsas_phyinfo *phy_info = NULL;
3711f9c34022SKashyap, Desai __le64 sas_address;
3712f9c34022SKashyap, Desai u8 phy_num;
3713f9c34022SKashyap, Desai u8 link_rate;
3714f9c34022SKashyap, Desai
3715f9c34022SKashyap, Desai ioc = fw_event->ioc;
3716f9c34022SKashyap, Desai link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3717f9c34022SKashyap, Desai
3718f9c34022SKashyap, Desai memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3719f9c34022SKashyap, Desai sas_address = le64_to_cpu(sas_address);
3720f9c34022SKashyap, Desai link_rate = link_data->LinkRates >> 4;
3721f9c34022SKashyap, Desai phy_num = link_data->PhyNum;
3722f9c34022SKashyap, Desai
3723f9c34022SKashyap, Desai port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3724f9c34022SKashyap, Desai if (port_info) {
3725f9c34022SKashyap, Desai phy_info = &port_info->phy_info[phy_num];
3726f9c34022SKashyap, Desai if (phy_info)
3727f9c34022SKashyap, Desai phy_info->negotiated_link_rate = link_rate;
3728f9c34022SKashyap, Desai }
3729f9c34022SKashyap, Desai
3730f9c34022SKashyap, Desai if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3731d75733d5SKashyap, Desai link_rate == MPI_SAS_IOUNIT0_RATE_3_0 ||
3732d75733d5SKashyap, Desai link_rate == MPI_SAS_IOUNIT0_RATE_6_0) {
3733f9c34022SKashyap, Desai
3734eedf92b9SKashyap, Desai if (!port_info) {
3735eedf92b9SKashyap, Desai if (ioc->old_sas_discovery_protocal) {
3736eedf92b9SKashyap, Desai port_info = mptsas_expander_add(ioc,
3737eedf92b9SKashyap, Desai le16_to_cpu(link_data->DevHandle));
3738eedf92b9SKashyap, Desai if (port_info)
3739f9c34022SKashyap, Desai goto out;
3740eedf92b9SKashyap, Desai }
3741eedf92b9SKashyap, Desai goto out;
3742eedf92b9SKashyap, Desai }
3743f9c34022SKashyap, Desai
3744f9c34022SKashyap, Desai if (port_info == ioc->hba_port_info)
3745f9c34022SKashyap, Desai mptsas_probe_hba_phys(ioc);
3746f9c34022SKashyap, Desai else
3747f9c34022SKashyap, Desai mptsas_expander_refresh(ioc, port_info);
3748f9c34022SKashyap, Desai } else if (phy_info && phy_info->phy) {
3749f9c34022SKashyap, Desai if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3750f9c34022SKashyap, Desai phy_info->phy->negotiated_linkrate =
3751f9c34022SKashyap, Desai SAS_PHY_DISABLED;
3752f9c34022SKashyap, Desai else if (link_rate ==
3753f9c34022SKashyap, Desai MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3754f9c34022SKashyap, Desai phy_info->phy->negotiated_linkrate =
3755f9c34022SKashyap, Desai SAS_LINK_RATE_FAILED;
3756c9de7dc4SKashyap, Desai else {
3757f9c34022SKashyap, Desai phy_info->phy->negotiated_linkrate =
3758f9c34022SKashyap, Desai SAS_LINK_RATE_UNKNOWN;
3759c9de7dc4SKashyap, Desai if (ioc->device_missing_delay &&
3760c9de7dc4SKashyap, Desai mptsas_is_end_device(&phy_info->attached)) {
3761c9de7dc4SKashyap, Desai struct scsi_device *sdev;
3762c9de7dc4SKashyap, Desai VirtDevice *vdevice;
3763c9de7dc4SKashyap, Desai u8 channel, id;
3764c9de7dc4SKashyap, Desai id = phy_info->attached.id;
3765c9de7dc4SKashyap, Desai channel = phy_info->attached.channel;
3766c9de7dc4SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3767c9de7dc4SKashyap, Desai "Link down for fw_id %d:fw_channel %d\n",
3768c9de7dc4SKashyap, Desai ioc->name, phy_info->attached.id,
3769c9de7dc4SKashyap, Desai phy_info->attached.channel));
3770c9de7dc4SKashyap, Desai
3771c9de7dc4SKashyap, Desai shost_for_each_device(sdev, ioc->sh) {
3772c9de7dc4SKashyap, Desai vdevice = sdev->hostdata;
3773c9de7dc4SKashyap, Desai if ((vdevice == NULL) ||
3774c9de7dc4SKashyap, Desai (vdevice->vtarget == NULL))
3775c9de7dc4SKashyap, Desai continue;
3776c9de7dc4SKashyap, Desai if ((vdevice->vtarget->tflags &
3777c9de7dc4SKashyap, Desai MPT_TARGET_FLAGS_RAID_COMPONENT ||
3778c9de7dc4SKashyap, Desai vdevice->vtarget->raidVolume))
3779c9de7dc4SKashyap, Desai continue;
3780c9de7dc4SKashyap, Desai if (vdevice->vtarget->id == id &&
3781c9de7dc4SKashyap, Desai vdevice->vtarget->channel ==
3782c9de7dc4SKashyap, Desai channel)
3783c9de7dc4SKashyap, Desai devtprintk(ioc,
3784c9de7dc4SKashyap, Desai printk(MYIOC_s_DEBUG_FMT
3785c9de7dc4SKashyap, Desai "SDEV OUTSTANDING CMDS"
3786c9de7dc4SKashyap, Desai "%d\n", ioc->name,
37878278807aSMing Lei scsi_device_busy(sdev)));
3788c9de7dc4SKashyap, Desai }
3789c9de7dc4SKashyap, Desai
3790c9de7dc4SKashyap, Desai }
3791c9de7dc4SKashyap, Desai }
3792f9c34022SKashyap, Desai }
3793f9c34022SKashyap, Desai out:
3794f9c34022SKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
3795f9c34022SKashyap, Desai }
3796f9c34022SKashyap, Desai
3797eedf92b9SKashyap, Desai static void
mptsas_not_responding_devices(MPT_ADAPTER * ioc)3798eedf92b9SKashyap, Desai mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3799eedf92b9SKashyap, Desai {
3800eedf92b9SKashyap, Desai struct mptsas_portinfo buffer, *port_info;
3801eedf92b9SKashyap, Desai struct mptsas_device_info *sas_info;
3802eedf92b9SKashyap, Desai struct mptsas_devinfo sas_device;
3803eedf92b9SKashyap, Desai u32 handle;
3804eedf92b9SKashyap, Desai VirtTarget *vtarget = NULL;
3805eedf92b9SKashyap, Desai struct mptsas_phyinfo *phy_info;
3806eedf92b9SKashyap, Desai u8 found_expander;
3807eedf92b9SKashyap, Desai int retval, retry_count;
3808eedf92b9SKashyap, Desai unsigned long flags;
3809eedf92b9SKashyap, Desai
3810eedf92b9SKashyap, Desai mpt_findImVolumes(ioc);
3811eedf92b9SKashyap, Desai
3812eedf92b9SKashyap, Desai spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3813eedf92b9SKashyap, Desai if (ioc->ioc_reset_in_progress) {
3814eedf92b9SKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3815eedf92b9SKashyap, Desai "%s: exiting due to a parallel reset \n", ioc->name,
3816eedf92b9SKashyap, Desai __func__));
3817eedf92b9SKashyap, Desai spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3818eedf92b9SKashyap, Desai return;
3819eedf92b9SKashyap, Desai }
3820eedf92b9SKashyap, Desai spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3821eedf92b9SKashyap, Desai
3822eedf92b9SKashyap, Desai /* devices, logical volumes */
3823eedf92b9SKashyap, Desai mutex_lock(&ioc->sas_device_info_mutex);
3824eedf92b9SKashyap, Desai redo_device_scan:
3825eedf92b9SKashyap, Desai list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
382657e98513SKashyap, Desai if (sas_info->is_cached)
382757e98513SKashyap, Desai continue;
3828a7938b0bSKashyap, Desai if (!sas_info->is_logical_volume) {
3829eedf92b9SKashyap, Desai sas_device.handle = 0;
3830eedf92b9SKashyap, Desai retry_count = 0;
3831eedf92b9SKashyap, Desai retry_page:
3832eedf92b9SKashyap, Desai retval = mptsas_sas_device_pg0(ioc, &sas_device,
3833eedf92b9SKashyap, Desai (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3834eedf92b9SKashyap, Desai << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3835eedf92b9SKashyap, Desai (sas_info->fw.channel << 8) +
3836eedf92b9SKashyap, Desai sas_info->fw.id);
3837eedf92b9SKashyap, Desai
3838eedf92b9SKashyap, Desai if (sas_device.handle)
3839eedf92b9SKashyap, Desai continue;
3840eedf92b9SKashyap, Desai if (retval == -EBUSY) {
3841eedf92b9SKashyap, Desai spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3842eedf92b9SKashyap, Desai if (ioc->ioc_reset_in_progress) {
3843eedf92b9SKashyap, Desai dfailprintk(ioc,
3844eedf92b9SKashyap, Desai printk(MYIOC_s_DEBUG_FMT
3845eedf92b9SKashyap, Desai "%s: exiting due to reset\n",
3846eedf92b9SKashyap, Desai ioc->name, __func__));
3847eedf92b9SKashyap, Desai spin_unlock_irqrestore
3848eedf92b9SKashyap, Desai (&ioc->taskmgmt_lock, flags);
3849a7938b0bSKashyap, Desai mutex_unlock(&ioc->
3850a7938b0bSKashyap, Desai sas_device_info_mutex);
3851eedf92b9SKashyap, Desai return;
3852eedf92b9SKashyap, Desai }
3853eedf92b9SKashyap, Desai spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3854eedf92b9SKashyap, Desai flags);
3855eedf92b9SKashyap, Desai }
3856eedf92b9SKashyap, Desai
3857eedf92b9SKashyap, Desai if (retval && (retval != -ENODEV)) {
3858eedf92b9SKashyap, Desai if (retry_count < 10) {
3859eedf92b9SKashyap, Desai retry_count++;
3860eedf92b9SKashyap, Desai goto retry_page;
3861eedf92b9SKashyap, Desai } else {
3862eedf92b9SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3863eedf92b9SKashyap, Desai "%s: Config page retry exceeded retry "
3864eedf92b9SKashyap, Desai "count deleting device 0x%llx\n",
3865eedf92b9SKashyap, Desai ioc->name, __func__,
3866eedf92b9SKashyap, Desai sas_info->sas_address));
3867eedf92b9SKashyap, Desai }
3868eedf92b9SKashyap, Desai }
3869eedf92b9SKashyap, Desai
3870eedf92b9SKashyap, Desai /* delete device */
3871eedf92b9SKashyap, Desai vtarget = mptsas_find_vtarget(ioc,
3872eedf92b9SKashyap, Desai sas_info->fw.channel, sas_info->fw.id);
3873a7938b0bSKashyap, Desai
3874eedf92b9SKashyap, Desai if (vtarget)
3875eedf92b9SKashyap, Desai vtarget->deleted = 1;
3876a7938b0bSKashyap, Desai
3877eedf92b9SKashyap, Desai phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3878eedf92b9SKashyap, Desai sas_info->sas_address);
3879a7938b0bSKashyap, Desai
3880eedf92b9SKashyap, Desai mptsas_del_end_device(ioc, phy_info);
3881eedf92b9SKashyap, Desai goto redo_device_scan;
3882a7938b0bSKashyap, Desai } else
3883a7938b0bSKashyap, Desai mptsas_volume_delete(ioc, sas_info->fw.id);
3884eedf92b9SKashyap, Desai }
3885129dd981SJiri Slaby mutex_unlock(&ioc->sas_device_info_mutex);
3886eedf92b9SKashyap, Desai
3887eedf92b9SKashyap, Desai /* expanders */
3888eedf92b9SKashyap, Desai mutex_lock(&ioc->sas_topology_mutex);
3889eedf92b9SKashyap, Desai redo_expander_scan:
3890eedf92b9SKashyap, Desai list_for_each_entry(port_info, &ioc->sas_topology, list) {
3891eedf92b9SKashyap, Desai
38929f21316fSJoe Lawrence if (!(port_info->phy_info[0].identify.device_info &
38939f21316fSJoe Lawrence MPI_SAS_DEVICE_INFO_SMP_TARGET))
3894eedf92b9SKashyap, Desai continue;
3895eedf92b9SKashyap, Desai found_expander = 0;
3896eedf92b9SKashyap, Desai handle = 0xFFFF;
3897eedf92b9SKashyap, Desai while (!mptsas_sas_expander_pg0(ioc, &buffer,
3898eedf92b9SKashyap, Desai (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3899eedf92b9SKashyap, Desai MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3900eedf92b9SKashyap, Desai !found_expander) {
3901eedf92b9SKashyap, Desai
3902eedf92b9SKashyap, Desai handle = buffer.phy_info[0].handle;
3903eedf92b9SKashyap, Desai if (buffer.phy_info[0].identify.sas_address ==
3904eedf92b9SKashyap, Desai port_info->phy_info[0].identify.sas_address) {
3905eedf92b9SKashyap, Desai found_expander = 1;
3906eedf92b9SKashyap, Desai }
3907eedf92b9SKashyap, Desai kfree(buffer.phy_info);
3908eedf92b9SKashyap, Desai }
3909eedf92b9SKashyap, Desai
3910eedf92b9SKashyap, Desai if (!found_expander) {
3911eedf92b9SKashyap, Desai mptsas_expander_delete(ioc, port_info, 0);
3912eedf92b9SKashyap, Desai goto redo_expander_scan;
3913eedf92b9SKashyap, Desai }
3914eedf92b9SKashyap, Desai }
3915129dd981SJiri Slaby mutex_unlock(&ioc->sas_topology_mutex);
3916eedf92b9SKashyap, Desai }
3917eedf92b9SKashyap, Desai
3918f9c34022SKashyap, Desai /**
3919f9c34022SKashyap, Desai * mptsas_probe_expanders - adding expanders
3920f9c34022SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
3921f9c34022SKashyap, Desai *
3922f9c34022SKashyap, Desai **/
3923f9c34022SKashyap, Desai static void
mptsas_probe_expanders(MPT_ADAPTER * ioc)3924f9c34022SKashyap, Desai mptsas_probe_expanders(MPT_ADAPTER *ioc)
3925f9c34022SKashyap, Desai {
3926f9c34022SKashyap, Desai struct mptsas_portinfo buffer, *port_info;
3927f9c34022SKashyap, Desai u32 handle;
3928f9c34022SKashyap, Desai int i;
3929f9c34022SKashyap, Desai
3930f9c34022SKashyap, Desai handle = 0xFFFF;
3931f9c34022SKashyap, Desai while (!mptsas_sas_expander_pg0(ioc, &buffer,
3932f9c34022SKashyap, Desai (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3933f9c34022SKashyap, Desai MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3934f9c34022SKashyap, Desai
3935f9c34022SKashyap, Desai handle = buffer.phy_info[0].handle;
3936f9c34022SKashyap, Desai port_info = mptsas_find_portinfo_by_sas_address(ioc,
3937f9c34022SKashyap, Desai buffer.phy_info[0].identify.sas_address);
3938f9c34022SKashyap, Desai
3939f9c34022SKashyap, Desai if (port_info) {
3940f9c34022SKashyap, Desai /* refreshing handles */
3941f9c34022SKashyap, Desai for (i = 0; i < buffer.num_phys; i++) {
3942f9c34022SKashyap, Desai port_info->phy_info[i].handle = handle;
3943f9c34022SKashyap, Desai port_info->phy_info[i].identify.handle_parent =
3944f9c34022SKashyap, Desai buffer.phy_info[0].identify.handle_parent;
3945f9c34022SKashyap, Desai }
3946f9c34022SKashyap, Desai mptsas_expander_refresh(ioc, port_info);
3947f9c34022SKashyap, Desai kfree(buffer.phy_info);
3948f9c34022SKashyap, Desai continue;
3949f9c34022SKashyap, Desai }
3950f9c34022SKashyap, Desai
3951f9c34022SKashyap, Desai port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3952f9c34022SKashyap, Desai if (!port_info) {
3953f9c34022SKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3954f9c34022SKashyap, Desai "%s: exit at line=%d\n", ioc->name,
3955f9c34022SKashyap, Desai __func__, __LINE__));
3956f9c34022SKashyap, Desai return;
3957f9c34022SKashyap, Desai }
3958f9c34022SKashyap, Desai port_info->num_phys = buffer.num_phys;
3959f9c34022SKashyap, Desai port_info->phy_info = buffer.phy_info;
3960f9c34022SKashyap, Desai for (i = 0; i < port_info->num_phys; i++)
3961f9c34022SKashyap, Desai port_info->phy_info[i].portinfo = port_info;
3962f9c34022SKashyap, Desai mutex_lock(&ioc->sas_topology_mutex);
3963f9c34022SKashyap, Desai list_add_tail(&port_info->list, &ioc->sas_topology);
3964f9c34022SKashyap, Desai mutex_unlock(&ioc->sas_topology_mutex);
3965f9c34022SKashyap, Desai printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3966f9c34022SKashyap, Desai "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3967f9c34022SKashyap, Desai (unsigned long long)buffer.phy_info[0].identify.sas_address);
3968f9c34022SKashyap, Desai mptsas_expander_refresh(ioc, port_info);
3969f9c34022SKashyap, Desai }
3970f9c34022SKashyap, Desai }
3971f9c34022SKashyap, Desai
3972f9c34022SKashyap, Desai static void
mptsas_probe_devices(MPT_ADAPTER * ioc)3973f9c34022SKashyap, Desai mptsas_probe_devices(MPT_ADAPTER *ioc)
3974f9c34022SKashyap, Desai {
3975f9c34022SKashyap, Desai u16 handle;
3976f9c34022SKashyap, Desai struct mptsas_devinfo sas_device;
3977f9c34022SKashyap, Desai struct mptsas_phyinfo *phy_info;
3978f9c34022SKashyap, Desai
3979f9c34022SKashyap, Desai handle = 0xFFFF;
3980f9c34022SKashyap, Desai while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3981f9c34022SKashyap, Desai MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3982f9c34022SKashyap, Desai
3983f9c34022SKashyap, Desai handle = sas_device.handle;
3984f9c34022SKashyap, Desai
3985f9c34022SKashyap, Desai if ((sas_device.device_info &
3986f9c34022SKashyap, Desai (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3987f9c34022SKashyap, Desai MPI_SAS_DEVICE_INFO_STP_TARGET |
3988f9c34022SKashyap, Desai MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3989f9c34022SKashyap, Desai continue;
3990f9c34022SKashyap, Desai
399151106ab5SKashyap, Desai /* If there is no FW B_T mapping for this device then continue
399251106ab5SKashyap, Desai * */
399351106ab5SKashyap, Desai if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
399451106ab5SKashyap, Desai || !(sas_device.flags &
399551106ab5SKashyap, Desai MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
399651106ab5SKashyap, Desai continue;
399751106ab5SKashyap, Desai
3998f9c34022SKashyap, Desai phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3999f9c34022SKashyap, Desai if (!phy_info)
4000f9c34022SKashyap, Desai continue;
4001f9c34022SKashyap, Desai
4002f9c34022SKashyap, Desai if (mptsas_get_rphy(phy_info))
4003f9c34022SKashyap, Desai continue;
4004f9c34022SKashyap, Desai
4005f9c34022SKashyap, Desai mptsas_add_end_device(ioc, phy_info);
4006f9c34022SKashyap, Desai }
4007e6b2d76aSMoore, Eric }
4008e6b2d76aSMoore, Eric
40092f187862SKashyap, Desai /**
4010cdcda465SRandy Dunlap * mptsas_scan_sas_topology - scans new SAS topology
4011cdcda465SRandy Dunlap * (part of probe or rescan)
40122f187862SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
40132f187862SKashyap, Desai *
40142f187862SKashyap, Desai **/
40150c33b27dSChristoph Hellwig static void
mptsas_scan_sas_topology(MPT_ADAPTER * ioc)40160c33b27dSChristoph Hellwig mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
40170c33b27dSChristoph Hellwig {
4018f9c34022SKashyap, Desai struct scsi_device *sdev;
4019f44e5461SMoore, Eric int i;
40200c33b27dSChristoph Hellwig
4021e6b2d76aSMoore, Eric mptsas_probe_hba_phys(ioc);
4022f9c34022SKashyap, Desai mptsas_probe_expanders(ioc);
4023f9c34022SKashyap, Desai mptsas_probe_devices(ioc);
4024f9c34022SKashyap, Desai
4025f44e5461SMoore, Eric /*
4026f44e5461SMoore, Eric Reporting RAID volumes.
4027f44e5461SMoore, Eric */
4028f9c34022SKashyap, Desai if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
4029f9c34022SKashyap, Desai !ioc->raid_data.pIocPg2->NumActiveVolumes)
4030f9c34022SKashyap, Desai return;
4031f44e5461SMoore, Eric for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4032f9c34022SKashyap, Desai sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4033f9c34022SKashyap, Desai ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4034f9c34022SKashyap, Desai if (sdev) {
4035f9c34022SKashyap, Desai scsi_device_put(sdev);
4036f9c34022SKashyap, Desai continue;
4037f9c34022SKashyap, Desai }
4038f9c34022SKashyap, Desai printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4039f9c34022SKashyap, Desai "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4040f9c34022SKashyap, Desai ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
4041e8bf3941SJames Bottomley scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4042f44e5461SMoore, Eric ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4043f44e5461SMoore, Eric }
4044e6b2d76aSMoore, Eric }
4045e6b2d76aSMoore, Eric
404657e98513SKashyap, Desai
404757e98513SKashyap, Desai static void
mptsas_handle_queue_full_event(struct fw_event_work * fw_event)404857e98513SKashyap, Desai mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
404957e98513SKashyap, Desai {
405057e98513SKashyap, Desai MPT_ADAPTER *ioc;
405157e98513SKashyap, Desai EventDataQueueFull_t *qfull_data;
405257e98513SKashyap, Desai struct mptsas_device_info *sas_info;
405357e98513SKashyap, Desai struct scsi_device *sdev;
405457e98513SKashyap, Desai int depth;
405557e98513SKashyap, Desai int id = -1;
405657e98513SKashyap, Desai int channel = -1;
405757e98513SKashyap, Desai int fw_id, fw_channel;
405857e98513SKashyap, Desai u16 current_depth;
405957e98513SKashyap, Desai
406057e98513SKashyap, Desai
406157e98513SKashyap, Desai ioc = fw_event->ioc;
406257e98513SKashyap, Desai qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
406357e98513SKashyap, Desai fw_id = qfull_data->TargetID;
406457e98513SKashyap, Desai fw_channel = qfull_data->Bus;
406557e98513SKashyap, Desai current_depth = le16_to_cpu(qfull_data->CurrentDepth);
406657e98513SKashyap, Desai
406757e98513SKashyap, Desai /* if hidden raid component, look for the volume id */
406857e98513SKashyap, Desai mutex_lock(&ioc->sas_device_info_mutex);
406957e98513SKashyap, Desai if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
407057e98513SKashyap, Desai list_for_each_entry(sas_info, &ioc->sas_device_info_list,
407157e98513SKashyap, Desai list) {
407257e98513SKashyap, Desai if (sas_info->is_cached ||
407357e98513SKashyap, Desai sas_info->is_logical_volume)
407457e98513SKashyap, Desai continue;
407557e98513SKashyap, Desai if (sas_info->is_hidden_raid_component &&
407657e98513SKashyap, Desai (sas_info->fw.channel == fw_channel &&
407757e98513SKashyap, Desai sas_info->fw.id == fw_id)) {
407857e98513SKashyap, Desai id = sas_info->volume_id;
407957e98513SKashyap, Desai channel = MPTSAS_RAID_CHANNEL;
408057e98513SKashyap, Desai goto out;
408157e98513SKashyap, Desai }
408257e98513SKashyap, Desai }
408357e98513SKashyap, Desai } else {
408457e98513SKashyap, Desai list_for_each_entry(sas_info, &ioc->sas_device_info_list,
408557e98513SKashyap, Desai list) {
408657e98513SKashyap, Desai if (sas_info->is_cached ||
408757e98513SKashyap, Desai sas_info->is_hidden_raid_component ||
408857e98513SKashyap, Desai sas_info->is_logical_volume)
408957e98513SKashyap, Desai continue;
409057e98513SKashyap, Desai if (sas_info->fw.channel == fw_channel &&
409157e98513SKashyap, Desai sas_info->fw.id == fw_id) {
409257e98513SKashyap, Desai id = sas_info->os.id;
409357e98513SKashyap, Desai channel = sas_info->os.channel;
409457e98513SKashyap, Desai goto out;
409557e98513SKashyap, Desai }
409657e98513SKashyap, Desai }
409757e98513SKashyap, Desai
409857e98513SKashyap, Desai }
409957e98513SKashyap, Desai
410057e98513SKashyap, Desai out:
410157e98513SKashyap, Desai mutex_unlock(&ioc->sas_device_info_mutex);
410257e98513SKashyap, Desai
410357e98513SKashyap, Desai if (id != -1) {
410457e98513SKashyap, Desai shost_for_each_device(sdev, ioc->sh) {
410557e98513SKashyap, Desai if (sdev->id == id && sdev->channel == channel) {
410657e98513SKashyap, Desai if (current_depth > sdev->queue_depth) {
410757e98513SKashyap, Desai sdev_printk(KERN_INFO, sdev,
410857e98513SKashyap, Desai "strange observation, the queue "
410957e98513SKashyap, Desai "depth is (%d) meanwhile fw queue "
411057e98513SKashyap, Desai "depth (%d)\n", sdev->queue_depth,
411157e98513SKashyap, Desai current_depth);
411257e98513SKashyap, Desai continue;
411357e98513SKashyap, Desai }
411457e98513SKashyap, Desai depth = scsi_track_queue_full(sdev,
41152865c073STomas Henzl sdev->queue_depth - 1);
411657e98513SKashyap, Desai if (depth > 0)
411757e98513SKashyap, Desai sdev_printk(KERN_INFO, sdev,
411857e98513SKashyap, Desai "Queue depth reduced to (%d)\n",
411957e98513SKashyap, Desai depth);
412057e98513SKashyap, Desai else if (depth < 0)
412157e98513SKashyap, Desai sdev_printk(KERN_INFO, sdev,
412257e98513SKashyap, Desai "Tagged Command Queueing is being "
412357e98513SKashyap, Desai "disabled\n");
412457e98513SKashyap, Desai else if (depth == 0)
41252865c073STomas Henzl sdev_printk(KERN_DEBUG, sdev,
412657e98513SKashyap, Desai "Queue depth not changed yet\n");
412757e98513SKashyap, Desai }
412857e98513SKashyap, Desai }
412957e98513SKashyap, Desai }
413057e98513SKashyap, Desai
413157e98513SKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
413257e98513SKashyap, Desai }
413357e98513SKashyap, Desai
413457e98513SKashyap, Desai
41359a28f49aSChristoph Hellwig static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER * ioc,u64 sas_address)4136547f9a21SEric Moore mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
41379a28f49aSChristoph Hellwig {
41389a28f49aSChristoph Hellwig struct mptsas_portinfo *port_info;
41399a28f49aSChristoph Hellwig struct mptsas_phyinfo *phy_info = NULL;
4140547f9a21SEric Moore int i;
41419a28f49aSChristoph Hellwig
41429a28f49aSChristoph Hellwig mutex_lock(&ioc->sas_topology_mutex);
41439a28f49aSChristoph Hellwig list_for_each_entry(port_info, &ioc->sas_topology, list) {
41449a28f49aSChristoph Hellwig for (i = 0; i < port_info->num_phys; i++) {
4145547f9a21SEric Moore if (!mptsas_is_end_device(
4146547f9a21SEric Moore &port_info->phy_info[i].attached))
4147547f9a21SEric Moore continue;
4148b506ade9SEric Moore if (port_info->phy_info[i].attached.sas_address
4149b506ade9SEric Moore != sas_address)
4150b506ade9SEric Moore continue;
41519a28f49aSChristoph Hellwig phy_info = &port_info->phy_info[i];
41529a28f49aSChristoph Hellwig break;
41539a28f49aSChristoph Hellwig }
41549a28f49aSChristoph Hellwig }
41559a28f49aSChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
41569a28f49aSChristoph Hellwig return phy_info;
41579a28f49aSChristoph Hellwig }
41589a28f49aSChristoph Hellwig
4159a7938b0bSKashyap, Desai /**
4160cdcda465SRandy Dunlap * mptsas_find_phyinfo_by_phys_disk_num - find phyinfo for the
4161cdcda465SRandy Dunlap * specified @phys_disk_num
4162a7938b0bSKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
4163cdcda465SRandy Dunlap * @phys_disk_num: (hot plug) physical disk number (for RAID support)
4164cdcda465SRandy Dunlap * @channel: channel number
4165cdcda465SRandy Dunlap * @id: Logical Target ID
4166a7938b0bSKashyap, Desai *
4167a7938b0bSKashyap, Desai **/
4168b506ade9SEric Moore static struct mptsas_phyinfo *
mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER * ioc,u8 phys_disk_num,u8 channel,u8 id)4169a7938b0bSKashyap, Desai mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4170a7938b0bSKashyap, Desai u8 channel, u8 id)
4171b506ade9SEric Moore {
4172b506ade9SEric Moore struct mptsas_phyinfo *phy_info = NULL;
4173a7938b0bSKashyap, Desai struct mptsas_portinfo *port_info;
4174a7938b0bSKashyap, Desai RaidPhysDiskPage1_t *phys_disk = NULL;
4175a7938b0bSKashyap, Desai int num_paths;
4176a7938b0bSKashyap, Desai u64 sas_address = 0;
4177b506ade9SEric Moore int i;
4178b506ade9SEric Moore
4179a7938b0bSKashyap, Desai phy_info = NULL;
4180a7938b0bSKashyap, Desai if (!ioc->raid_data.pIocPg3)
4181a7938b0bSKashyap, Desai return NULL;
4182a7938b0bSKashyap, Desai /* dual port support */
4183a7938b0bSKashyap, Desai num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4184a7938b0bSKashyap, Desai if (!num_paths)
4185a7938b0bSKashyap, Desai goto out;
4186a7938b0bSKashyap, Desai phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4187a7938b0bSKashyap, Desai (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4188a7938b0bSKashyap, Desai if (!phys_disk)
4189a7938b0bSKashyap, Desai goto out;
4190a7938b0bSKashyap, Desai mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4191a7938b0bSKashyap, Desai for (i = 0; i < num_paths; i++) {
4192a7938b0bSKashyap, Desai if ((phys_disk->Path[i].Flags & 1) != 0)
4193a7938b0bSKashyap, Desai /* entry no longer valid */
4194a7938b0bSKashyap, Desai continue;
4195a7938b0bSKashyap, Desai if ((id == phys_disk->Path[i].PhysDiskID) &&
4196a7938b0bSKashyap, Desai (channel == phys_disk->Path[i].PhysDiskBus)) {
4197a7938b0bSKashyap, Desai memcpy(&sas_address, &phys_disk->Path[i].WWID,
4198a7938b0bSKashyap, Desai sizeof(u64));
4199a7938b0bSKashyap, Desai phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4200a7938b0bSKashyap, Desai sas_address);
4201a7938b0bSKashyap, Desai goto out;
4202a7938b0bSKashyap, Desai }
4203a7938b0bSKashyap, Desai }
4204a7938b0bSKashyap, Desai
4205a7938b0bSKashyap, Desai out:
4206a7938b0bSKashyap, Desai kfree(phys_disk);
4207a7938b0bSKashyap, Desai if (phy_info)
4208a7938b0bSKashyap, Desai return phy_info;
4209a7938b0bSKashyap, Desai
4210a7938b0bSKashyap, Desai /*
4211a7938b0bSKashyap, Desai * Extra code to handle RAID0 case, where the sas_address is not updated
4212a7938b0bSKashyap, Desai * in phys_disk_page_1 when hotswapped
4213a7938b0bSKashyap, Desai */
4214b506ade9SEric Moore mutex_lock(&ioc->sas_topology_mutex);
4215b506ade9SEric Moore list_for_each_entry(port_info, &ioc->sas_topology, list) {
4216a7938b0bSKashyap, Desai for (i = 0; i < port_info->num_phys && !phy_info; i++) {
4217b506ade9SEric Moore if (!mptsas_is_end_device(
4218b506ade9SEric Moore &port_info->phy_info[i].attached))
4219b506ade9SEric Moore continue;
4220b506ade9SEric Moore if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4221b506ade9SEric Moore continue;
4222a7938b0bSKashyap, Desai if ((port_info->phy_info[i].attached.phys_disk_num ==
4223a7938b0bSKashyap, Desai phys_disk_num) &&
4224a7938b0bSKashyap, Desai (port_info->phy_info[i].attached.id == id) &&
4225a7938b0bSKashyap, Desai (port_info->phy_info[i].attached.channel ==
4226a7938b0bSKashyap, Desai channel))
42279a28f49aSChristoph Hellwig phy_info = &port_info->phy_info[i];
42289a28f49aSChristoph Hellwig }
42299a28f49aSChristoph Hellwig }
42309a28f49aSChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
42319a28f49aSChristoph Hellwig return phy_info;
42329a28f49aSChristoph Hellwig }
42339a28f49aSChristoph Hellwig
42349a28f49aSChristoph Hellwig static void
mptsas_reprobe_lun(struct scsi_device * sdev,void * data)4235f44e5461SMoore, Eric mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4236f44e5461SMoore, Eric {
4237f44e5461SMoore, Eric sdev->no_uld_attach = data ? 1 : 0;
4238*ac3c9fb6SZeng Heng WARN_ON(scsi_device_reprobe(sdev));
4239f44e5461SMoore, Eric }
4240f44e5461SMoore, Eric
4241f44e5461SMoore, Eric static void
mptsas_reprobe_target(struct scsi_target * starget,int uld_attach)4242f44e5461SMoore, Eric mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4243f44e5461SMoore, Eric {
4244f44e5461SMoore, Eric starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4245f44e5461SMoore, Eric mptsas_reprobe_lun);
4246f44e5461SMoore, Eric }
4247f44e5461SMoore, Eric
4248b506ade9SEric Moore static void
mptsas_adding_inactive_raid_components(MPT_ADAPTER * ioc,u8 channel,u8 id)4249b506ade9SEric Moore mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4250b506ade9SEric Moore {
4251b506ade9SEric Moore CONFIGPARMS cfg;
4252b506ade9SEric Moore ConfigPageHeader_t hdr;
4253b506ade9SEric Moore dma_addr_t dma_handle;
4254b506ade9SEric Moore pRaidVolumePage0_t buffer = NULL;
4255b506ade9SEric Moore RaidPhysDiskPage0_t phys_disk;
4256b506ade9SEric Moore int i;
42573eb0822cSKashyap, Desai struct mptsas_phyinfo *phy_info;
42583eb0822cSKashyap, Desai struct mptsas_devinfo sas_device;
4259b506ade9SEric Moore
4260b506ade9SEric Moore memset(&cfg, 0 , sizeof(CONFIGPARMS));
4261b506ade9SEric Moore memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4262b506ade9SEric Moore hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4263b506ade9SEric Moore cfg.pageAddr = (channel << 8) + id;
4264b506ade9SEric Moore cfg.cfghdr.hdr = &hdr;
4265b506ade9SEric Moore cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4266568da769SKashyap, Desai cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
4267b506ade9SEric Moore
4268b506ade9SEric Moore if (mpt_config(ioc, &cfg) != 0)
4269b506ade9SEric Moore goto out;
4270b506ade9SEric Moore
4271b506ade9SEric Moore if (!hdr.PageLength)
4272b506ade9SEric Moore goto out;
4273b506ade9SEric Moore
427476a334d7SChristophe JAILLET buffer = dma_alloc_coherent(&ioc->pcidev->dev, hdr.PageLength * 4,
427576a334d7SChristophe JAILLET &dma_handle, GFP_KERNEL);
4276b506ade9SEric Moore
4277b506ade9SEric Moore if (!buffer)
4278b506ade9SEric Moore goto out;
4279b506ade9SEric Moore
4280b506ade9SEric Moore cfg.physAddr = dma_handle;
4281b506ade9SEric Moore cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4282b506ade9SEric Moore
4283b506ade9SEric Moore if (mpt_config(ioc, &cfg) != 0)
4284b506ade9SEric Moore goto out;
4285b506ade9SEric Moore
4286b506ade9SEric Moore if (!(buffer->VolumeStatus.Flags &
4287b506ade9SEric Moore MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4288b506ade9SEric Moore goto out;
4289b506ade9SEric Moore
4290b506ade9SEric Moore if (!buffer->NumPhysDisks)
4291b506ade9SEric Moore goto out;
4292b506ade9SEric Moore
4293b506ade9SEric Moore for (i = 0; i < buffer->NumPhysDisks; i++) {
4294b506ade9SEric Moore
4295b506ade9SEric Moore if (mpt_raid_phys_disk_pg0(ioc,
4296b506ade9SEric Moore buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4297b506ade9SEric Moore continue;
4298b506ade9SEric Moore
42993eb0822cSKashyap, Desai if (mptsas_sas_device_pg0(ioc, &sas_device,
43003eb0822cSKashyap, Desai (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
43013eb0822cSKashyap, Desai MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
43023eb0822cSKashyap, Desai (phys_disk.PhysDiskBus << 8) +
43033eb0822cSKashyap, Desai phys_disk.PhysDiskID))
43043eb0822cSKashyap, Desai continue;
4305b506ade9SEric Moore
430651106ab5SKashyap, Desai /* If there is no FW B_T mapping for this device then continue
430751106ab5SKashyap, Desai * */
430851106ab5SKashyap, Desai if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
430951106ab5SKashyap, Desai || !(sas_device.flags &
431051106ab5SKashyap, Desai MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
431151106ab5SKashyap, Desai continue;
431251106ab5SKashyap, Desai
431351106ab5SKashyap, Desai
43143eb0822cSKashyap, Desai phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
43153eb0822cSKashyap, Desai sas_device.sas_address);
43163eb0822cSKashyap, Desai mptsas_add_end_device(ioc, phy_info);
4317b506ade9SEric Moore }
4318b506ade9SEric Moore
4319b506ade9SEric Moore out:
4320b506ade9SEric Moore if (buffer)
4321b114dda6SChristophe JAILLET dma_free_coherent(&ioc->pcidev->dev, hdr.PageLength * 4,
4322b114dda6SChristophe JAILLET buffer, dma_handle);
4323b506ade9SEric Moore }
4324e6b2d76aSMoore, Eric /*
4325e6b2d76aSMoore, Eric * Work queue thread to handle SAS hotplug events
4326e6b2d76aSMoore, Eric */
4327f44e5461SMoore, Eric static void
mptsas_hotplug_work(MPT_ADAPTER * ioc,struct fw_event_work * fw_event,struct mptsas_hotplug_event * hot_plug_info)43283eb0822cSKashyap, Desai mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
43293eb0822cSKashyap, Desai struct mptsas_hotplug_event *hot_plug_info)
43309a28f49aSChristoph Hellwig {
43319a28f49aSChristoph Hellwig struct mptsas_phyinfo *phy_info;
4332547f9a21SEric Moore struct scsi_target * starget;
4333c73787eeSMoore, Eric struct mptsas_devinfo sas_device;
4334f44e5461SMoore, Eric VirtTarget *vtarget;
43353eb0822cSKashyap, Desai int i;
4336cc7e9f5fSKashyap, Desai struct mptsas_portinfo *port_info;
4337547f9a21SEric Moore
43383eb0822cSKashyap, Desai switch (hot_plug_info->event_type) {
43393eb0822cSKashyap, Desai
43403eb0822cSKashyap, Desai case MPTSAS_ADD_PHYSDISK:
43413eb0822cSKashyap, Desai
43423eb0822cSKashyap, Desai if (!ioc->raid_data.pIocPg2)
43433eb0822cSKashyap, Desai break;
43443eb0822cSKashyap, Desai
43453eb0822cSKashyap, Desai for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
43463eb0822cSKashyap, Desai if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
43473eb0822cSKashyap, Desai hot_plug_info->id) {
43483eb0822cSKashyap, Desai printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4349c09a21d8SColin Ian King "to add hidden disk - target_id matches "
43503eb0822cSKashyap, Desai "volume_id\n", ioc->name);
43513eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
43523eb0822cSKashyap, Desai return;
43533eb0822cSKashyap, Desai }
43543eb0822cSKashyap, Desai }
43553eb0822cSKashyap, Desai mpt_findImVolumes(ioc);
4356df561f66SGustavo A. R. Silva fallthrough;
43573eb0822cSKashyap, Desai
43583eb0822cSKashyap, Desai case MPTSAS_ADD_DEVICE:
43593eb0822cSKashyap, Desai memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
43603eb0822cSKashyap, Desai mptsas_sas_device_pg0(ioc, &sas_device,
43613eb0822cSKashyap, Desai (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
43623eb0822cSKashyap, Desai MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
43633eb0822cSKashyap, Desai (hot_plug_info->channel << 8) +
43643eb0822cSKashyap, Desai hot_plug_info->id);
43653eb0822cSKashyap, Desai
436651106ab5SKashyap, Desai /* If there is no FW B_T mapping for this device then break
436751106ab5SKashyap, Desai * */
436851106ab5SKashyap, Desai if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
436951106ab5SKashyap, Desai || !(sas_device.flags &
437051106ab5SKashyap, Desai MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
437151106ab5SKashyap, Desai break;
437251106ab5SKashyap, Desai
43733eb0822cSKashyap, Desai if (!sas_device.handle)
43743eb0822cSKashyap, Desai return;
43753eb0822cSKashyap, Desai
43763eb0822cSKashyap, Desai phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4377ee3e2d83SHannes Reinecke /* Device hot plug */
4378ee3e2d83SHannes Reinecke if (!phy_info) {
4379cc7e9f5fSKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4380ee3e2d83SHannes Reinecke "%s %d HOT PLUG: "
4381cc7e9f5fSKashyap, Desai "parent handle of device %x\n", ioc->name,
4382cc7e9f5fSKashyap, Desai __func__, __LINE__, sas_device.handle_parent));
4383cc7e9f5fSKashyap, Desai port_info = mptsas_find_portinfo_by_handle(ioc,
4384cc7e9f5fSKashyap, Desai sas_device.handle_parent);
4385cc7e9f5fSKashyap, Desai
4386cc7e9f5fSKashyap, Desai if (port_info == ioc->hba_port_info)
4387cc7e9f5fSKashyap, Desai mptsas_probe_hba_phys(ioc);
4388cc7e9f5fSKashyap, Desai else if (port_info)
4389cc7e9f5fSKashyap, Desai mptsas_expander_refresh(ioc, port_info);
4390cc7e9f5fSKashyap, Desai else {
4391cc7e9f5fSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4392cc7e9f5fSKashyap, Desai "%s %d port info is NULL\n",
4393cc7e9f5fSKashyap, Desai ioc->name, __func__, __LINE__));
43943eb0822cSKashyap, Desai break;
4395cc7e9f5fSKashyap, Desai }
4396cc7e9f5fSKashyap, Desai phy_info = mptsas_refreshing_device_handles
4397cc7e9f5fSKashyap, Desai (ioc, &sas_device);
4398cc7e9f5fSKashyap, Desai }
4399cc7e9f5fSKashyap, Desai
4400cc7e9f5fSKashyap, Desai if (!phy_info) {
4401cc7e9f5fSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4402cc7e9f5fSKashyap, Desai "%s %d phy info is NULL\n",
4403cc7e9f5fSKashyap, Desai ioc->name, __func__, __LINE__));
4404cc7e9f5fSKashyap, Desai break;
4405cc7e9f5fSKashyap, Desai }
44063eb0822cSKashyap, Desai
44073eb0822cSKashyap, Desai if (mptsas_get_rphy(phy_info))
44083eb0822cSKashyap, Desai break;
44093eb0822cSKashyap, Desai
44103eb0822cSKashyap, Desai mptsas_add_end_device(ioc, phy_info);
44113eb0822cSKashyap, Desai break;
44123eb0822cSKashyap, Desai
44139a28f49aSChristoph Hellwig case MPTSAS_DEL_DEVICE:
44143eb0822cSKashyap, Desai phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
44153eb0822cSKashyap, Desai hot_plug_info->sas_address);
44163eb0822cSKashyap, Desai mptsas_del_end_device(ioc, phy_info);
44173eb0822cSKashyap, Desai break;
44189a28f49aSChristoph Hellwig
44193eb0822cSKashyap, Desai case MPTSAS_DEL_PHYSDISK:
44203eb0822cSKashyap, Desai
44213eb0822cSKashyap, Desai mpt_findImVolumes(ioc);
44223eb0822cSKashyap, Desai
44233eb0822cSKashyap, Desai phy_info = mptsas_find_phyinfo_by_phys_disk_num(
4424a7938b0bSKashyap, Desai ioc, hot_plug_info->phys_disk_num,
4425a7938b0bSKashyap, Desai hot_plug_info->channel,
4426a7938b0bSKashyap, Desai hot_plug_info->id);
44273eb0822cSKashyap, Desai mptsas_del_end_device(ioc, phy_info);
44283eb0822cSKashyap, Desai break;
44293eb0822cSKashyap, Desai
44303eb0822cSKashyap, Desai case MPTSAS_ADD_PHYSDISK_REPROBE:
44313eb0822cSKashyap, Desai
4432b506ade9SEric Moore if (mptsas_sas_device_pg0(ioc, &sas_device,
4433b506ade9SEric Moore (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4434b506ade9SEric Moore MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
44353eb0822cSKashyap, Desai (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4436d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
44373eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
44383eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
4439b506ade9SEric Moore break;
4440b506ade9SEric Moore }
44413eb0822cSKashyap, Desai
444251106ab5SKashyap, Desai /* If there is no FW B_T mapping for this device then break
444351106ab5SKashyap, Desai * */
444451106ab5SKashyap, Desai if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
444551106ab5SKashyap, Desai || !(sas_device.flags &
444651106ab5SKashyap, Desai MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
444751106ab5SKashyap, Desai break;
444851106ab5SKashyap, Desai
4449b506ade9SEric Moore phy_info = mptsas_find_phyinfo_by_sas_address(
4450b506ade9SEric Moore ioc, sas_device.sas_address);
4451b506ade9SEric Moore
4452b506ade9SEric Moore if (!phy_info) {
4453d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
44543eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
44553eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
4456547f9a21SEric Moore break;
4457547f9a21SEric Moore }
4458f44e5461SMoore, Eric
4459547f9a21SEric Moore starget = mptsas_get_starget(phy_info);
44603eb0822cSKashyap, Desai if (!starget) {
44613eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
44623eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
44633eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
44643eb0822cSKashyap, Desai break;
44653eb0822cSKashyap, Desai }
4466547f9a21SEric Moore
44673eb0822cSKashyap, Desai vtarget = starget->hostdata;
4468547f9a21SEric Moore if (!vtarget) {
4469d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
44703eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
44713eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
4472f44e5461SMoore, Eric break;
4473547f9a21SEric Moore }
4474547f9a21SEric Moore
4475bd23e94cSMoore, Eric mpt_findImVolumes(ioc);
4476bd23e94cSMoore, Eric
44773eb0822cSKashyap, Desai starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
44783eb0822cSKashyap, Desai "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
44793eb0822cSKashyap, Desai ioc->name, hot_plug_info->channel, hot_plug_info->id,
44803eb0822cSKashyap, Desai hot_plug_info->phys_disk_num, (unsigned long long)
44813eb0822cSKashyap, Desai sas_device.sas_address);
44823eb0822cSKashyap, Desai
44833eb0822cSKashyap, Desai vtarget->id = hot_plug_info->phys_disk_num;
44843eb0822cSKashyap, Desai vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
44853eb0822cSKashyap, Desai phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
44863eb0822cSKashyap, Desai mptsas_reprobe_target(starget, 1);
44873eb0822cSKashyap, Desai break;
44883eb0822cSKashyap, Desai
44893eb0822cSKashyap, Desai case MPTSAS_DEL_PHYSDISK_REPROBE:
44903eb0822cSKashyap, Desai
4491e3094447SChristoph Hellwig if (mptsas_sas_device_pg0(ioc, &sas_device,
4492c73787eeSMoore, Eric (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4493b506ade9SEric Moore MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
44943eb0822cSKashyap, Desai (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4495d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
44963eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n",
44973eb0822cSKashyap, Desai ioc->name, __func__,
44983eb0822cSKashyap, Desai hot_plug_info->id, __LINE__));
4499f44e5461SMoore, Eric break;
4500e6b2d76aSMoore, Eric }
4501e6b2d76aSMoore, Eric
450251106ab5SKashyap, Desai /* If there is no FW B_T mapping for this device then break
450351106ab5SKashyap, Desai * */
450451106ab5SKashyap, Desai if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
450551106ab5SKashyap, Desai || !(sas_device.flags &
450651106ab5SKashyap, Desai MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
450751106ab5SKashyap, Desai break;
450851106ab5SKashyap, Desai
4509547f9a21SEric Moore phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4510547f9a21SEric Moore sas_device.sas_address);
45113eb0822cSKashyap, Desai if (!phy_info) {
4512d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
45133eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
45143eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
4515f44e5461SMoore, Eric break;
4516547f9a21SEric Moore }
4517547f9a21SEric Moore
4518547f9a21SEric Moore starget = mptsas_get_starget(phy_info);
45193eb0822cSKashyap, Desai if (!starget) {
45203eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
45213eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
45223eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
45233eb0822cSKashyap, Desai break;
45243eb0822cSKashyap, Desai }
4525b506ade9SEric Moore
4526547f9a21SEric Moore vtarget = starget->hostdata;
4527547f9a21SEric Moore if (!vtarget) {
4528d6ecdd63SPrakash, Sathya dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
45293eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
45303eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
4531547f9a21SEric Moore break;
4532547f9a21SEric Moore }
45333eb0822cSKashyap, Desai
45343eb0822cSKashyap, Desai if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
45353eb0822cSKashyap, Desai dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
45363eb0822cSKashyap, Desai "%s: fw_id=%d exit at line=%d\n", ioc->name,
45373eb0822cSKashyap, Desai __func__, hot_plug_info->id, __LINE__));
45383eb0822cSKashyap, Desai break;
45393eb0822cSKashyap, Desai }
45403eb0822cSKashyap, Desai
45413eb0822cSKashyap, Desai mpt_findImVolumes(ioc);
45423eb0822cSKashyap, Desai
45433eb0822cSKashyap, Desai starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
45443eb0822cSKashyap, Desai " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
45453eb0822cSKashyap, Desai ioc->name, hot_plug_info->channel, hot_plug_info->id,
45463eb0822cSKashyap, Desai hot_plug_info->phys_disk_num, (unsigned long long)
45473eb0822cSKashyap, Desai sas_device.sas_address);
45483eb0822cSKashyap, Desai
45493eb0822cSKashyap, Desai vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
45503eb0822cSKashyap, Desai vtarget->id = hot_plug_info->id;
4551b506ade9SEric Moore phy_info->attached.phys_disk_num = ~0;
45523eb0822cSKashyap, Desai mptsas_reprobe_target(starget, 0);
45533eb0822cSKashyap, Desai mptsas_add_device_component_by_fw(ioc,
45543eb0822cSKashyap, Desai hot_plug_info->channel, hot_plug_info->id);
45559a28f49aSChristoph Hellwig break;
45569a28f49aSChristoph Hellwig
4557c73787eeSMoore, Eric case MPTSAS_ADD_RAID:
45583eb0822cSKashyap, Desai
4559c73787eeSMoore, Eric mpt_findImVolumes(ioc);
45603eb0822cSKashyap, Desai printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
45613eb0822cSKashyap, Desai "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
45623eb0822cSKashyap, Desai hot_plug_info->id);
45633eb0822cSKashyap, Desai scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
45643eb0822cSKashyap, Desai hot_plug_info->id, 0);
4565c73787eeSMoore, Eric break;
45663eb0822cSKashyap, Desai
4567c73787eeSMoore, Eric case MPTSAS_DEL_RAID:
45683eb0822cSKashyap, Desai
4569c73787eeSMoore, Eric mpt_findImVolumes(ioc);
45703eb0822cSKashyap, Desai printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
45713eb0822cSKashyap, Desai "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
45723eb0822cSKashyap, Desai hot_plug_info->id);
45733eb0822cSKashyap, Desai scsi_remove_device(hot_plug_info->sdev);
45743eb0822cSKashyap, Desai scsi_device_put(hot_plug_info->sdev);
4575c73787eeSMoore, Eric break;
45763eb0822cSKashyap, Desai
4577b506ade9SEric Moore case MPTSAS_ADD_INACTIVE_VOLUME:
45783eb0822cSKashyap, Desai
45793eb0822cSKashyap, Desai mpt_findImVolumes(ioc);
4580b506ade9SEric Moore mptsas_adding_inactive_raid_components(ioc,
45813eb0822cSKashyap, Desai hot_plug_info->channel, hot_plug_info->id);
4582b506ade9SEric Moore break;
45833eb0822cSKashyap, Desai
4584bd23e94cSMoore, Eric default:
4585bd23e94cSMoore, Eric break;
45869a28f49aSChristoph Hellwig }
45879a28f49aSChristoph Hellwig
45883eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
45899a28f49aSChristoph Hellwig }
45909a28f49aSChristoph Hellwig
45919a28f49aSChristoph Hellwig static void
mptsas_send_sas_event(struct fw_event_work * fw_event)45923eb0822cSKashyap, Desai mptsas_send_sas_event(struct fw_event_work *fw_event)
45939a28f49aSChristoph Hellwig {
45943eb0822cSKashyap, Desai MPT_ADAPTER *ioc;
45953eb0822cSKashyap, Desai struct mptsas_hotplug_event hot_plug_info;
45963eb0822cSKashyap, Desai EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
45973eb0822cSKashyap, Desai u32 device_info;
45983eb0822cSKashyap, Desai u64 sas_address;
45993eb0822cSKashyap, Desai
46003eb0822cSKashyap, Desai ioc = fw_event->ioc;
46013eb0822cSKashyap, Desai sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
46023eb0822cSKashyap, Desai fw_event->event_data;
46033eb0822cSKashyap, Desai device_info = le32_to_cpu(sas_event_data->DeviceInfo);
46049a28f49aSChristoph Hellwig
46059a28f49aSChristoph Hellwig if ((device_info &
46069a28f49aSChristoph Hellwig (MPI_SAS_DEVICE_INFO_SSP_TARGET |
46079a28f49aSChristoph Hellwig MPI_SAS_DEVICE_INFO_STP_TARGET |
46083eb0822cSKashyap, Desai MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
46093eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
46109a28f49aSChristoph Hellwig return;
46113eb0822cSKashyap, Desai }
46123eb0822cSKashyap, Desai
46133eb0822cSKashyap, Desai if (sas_event_data->ReasonCode ==
46143eb0822cSKashyap, Desai MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
46153eb0822cSKashyap, Desai mptbase_sas_persist_operation(ioc,
46163eb0822cSKashyap, Desai MPI_SAS_OP_CLEAR_NOT_PRESENT);
46173eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
46183eb0822cSKashyap, Desai return;
46193eb0822cSKashyap, Desai }
46209a28f49aSChristoph Hellwig
46214b766471SMoore, Eric switch (sas_event_data->ReasonCode) {
46224b766471SMoore, Eric case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
4623df9e062aSEric Moore case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
46243eb0822cSKashyap, Desai memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
46253eb0822cSKashyap, Desai hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
46263eb0822cSKashyap, Desai hot_plug_info.channel = sas_event_data->Bus;
46273eb0822cSKashyap, Desai hot_plug_info.id = sas_event_data->TargetID;
46283eb0822cSKashyap, Desai hot_plug_info.phy_id = sas_event_data->PhyNum;
46294b766471SMoore, Eric memcpy(&sas_address, &sas_event_data->SASAddress,
46303eb0822cSKashyap, Desai sizeof(u64));
46313eb0822cSKashyap, Desai hot_plug_info.sas_address = le64_to_cpu(sas_address);
46323eb0822cSKashyap, Desai hot_plug_info.device_info = device_info;
46334b766471SMoore, Eric if (sas_event_data->ReasonCode &
46344b766471SMoore, Eric MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
46353eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
46369a28f49aSChristoph Hellwig else
46373eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
46383eb0822cSKashyap, Desai mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
46394b766471SMoore, Eric break;
46403eb0822cSKashyap, Desai
46414b766471SMoore, Eric case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
46423eb0822cSKashyap, Desai mptbase_sas_persist_operation(ioc,
46433eb0822cSKashyap, Desai MPI_SAS_OP_CLEAR_NOT_PRESENT);
46443eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
46454b766471SMoore, Eric break;
46463eb0822cSKashyap, Desai
46474b766471SMoore, Eric case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
46483eb0822cSKashyap, Desai /* TODO */
46494b766471SMoore, Eric case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
46503eb0822cSKashyap, Desai /* TODO */
46514b766471SMoore, Eric default:
46523eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
46534b766471SMoore, Eric break;
46544b766471SMoore, Eric }
46559a28f49aSChristoph Hellwig }
46563eb0822cSKashyap, Desai
4657c73787eeSMoore, Eric static void
mptsas_send_raid_event(struct fw_event_work * fw_event)46583eb0822cSKashyap, Desai mptsas_send_raid_event(struct fw_event_work *fw_event)
4659c73787eeSMoore, Eric {
46603eb0822cSKashyap, Desai MPT_ADAPTER *ioc;
46613eb0822cSKashyap, Desai EVENT_DATA_RAID *raid_event_data;
46623eb0822cSKashyap, Desai struct mptsas_hotplug_event hot_plug_info;
46633eb0822cSKashyap, Desai int status;
46643eb0822cSKashyap, Desai int state;
46653eb0822cSKashyap, Desai struct scsi_device *sdev = NULL;
46663eb0822cSKashyap, Desai VirtDevice *vdevice = NULL;
46673eb0822cSKashyap, Desai RaidPhysDiskPage0_t phys_disk;
4668c73787eeSMoore, Eric
46693eb0822cSKashyap, Desai ioc = fw_event->ioc;
46703eb0822cSKashyap, Desai raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
46713eb0822cSKashyap, Desai status = le32_to_cpu(raid_event_data->SettingsStatus);
46723eb0822cSKashyap, Desai state = (status >> 8) & 0xff;
4673c73787eeSMoore, Eric
46743eb0822cSKashyap, Desai memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
46753eb0822cSKashyap, Desai hot_plug_info.id = raid_event_data->VolumeID;
46763eb0822cSKashyap, Desai hot_plug_info.channel = raid_event_data->VolumeBus;
46773eb0822cSKashyap, Desai hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
46783eb0822cSKashyap, Desai
46793eb0822cSKashyap, Desai if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
46803eb0822cSKashyap, Desai raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
46813eb0822cSKashyap, Desai raid_event_data->ReasonCode ==
46823eb0822cSKashyap, Desai MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
46833eb0822cSKashyap, Desai sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
46843eb0822cSKashyap, Desai hot_plug_info.id, 0);
46853eb0822cSKashyap, Desai hot_plug_info.sdev = sdev;
46863eb0822cSKashyap, Desai if (sdev)
46873eb0822cSKashyap, Desai vdevice = sdev->hostdata;
4688c73787eeSMoore, Eric }
4689c73787eeSMoore, Eric
46903eb0822cSKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
46913eb0822cSKashyap, Desai "ReasonCode=%02x\n", ioc->name, __func__,
46923eb0822cSKashyap, Desai raid_event_data->ReasonCode));
4693c73787eeSMoore, Eric
4694c73787eeSMoore, Eric switch (raid_event_data->ReasonCode) {
4695c73787eeSMoore, Eric case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
46963eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
4697c73787eeSMoore, Eric break;
4698c73787eeSMoore, Eric case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
46993eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
4700c73787eeSMoore, Eric break;
4701bd23e94cSMoore, Eric case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4702bd23e94cSMoore, Eric switch (state) {
4703bd23e94cSMoore, Eric case MPI_PD_STATE_ONLINE:
4704b506ade9SEric Moore case MPI_PD_STATE_NOT_COMPATIBLE:
47053eb0822cSKashyap, Desai mpt_raid_phys_disk_pg0(ioc,
47063eb0822cSKashyap, Desai raid_event_data->PhysDiskNum, &phys_disk);
47073eb0822cSKashyap, Desai hot_plug_info.id = phys_disk.PhysDiskID;
47083eb0822cSKashyap, Desai hot_plug_info.channel = phys_disk.PhysDiskBus;
47093eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4710bd23e94cSMoore, Eric break;
47113eb0822cSKashyap, Desai case MPI_PD_STATE_FAILED:
4712bd23e94cSMoore, Eric case MPI_PD_STATE_MISSING:
4713bd23e94cSMoore, Eric case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4714bd23e94cSMoore, Eric case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4715bd23e94cSMoore, Eric case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
47163eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4717bd23e94cSMoore, Eric break;
4718bd23e94cSMoore, Eric default:
4719bd23e94cSMoore, Eric break;
4720bd23e94cSMoore, Eric }
4721bd23e94cSMoore, Eric break;
4722c73787eeSMoore, Eric case MPI_EVENT_RAID_RC_VOLUME_DELETED:
47233eb0822cSKashyap, Desai if (!sdev)
47243eb0822cSKashyap, Desai break;
47253eb0822cSKashyap, Desai vdevice->vtarget->deleted = 1; /* block IO */
47263eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_RAID;
4727c73787eeSMoore, Eric break;
4728c73787eeSMoore, Eric case MPI_EVENT_RAID_RC_VOLUME_CREATED:
47293eb0822cSKashyap, Desai if (sdev) {
47303eb0822cSKashyap, Desai scsi_device_put(sdev);
47313eb0822cSKashyap, Desai break;
47323eb0822cSKashyap, Desai }
47333eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_RAID;
4734c73787eeSMoore, Eric break;
4735c73787eeSMoore, Eric case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
47363eb0822cSKashyap, Desai if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
47373eb0822cSKashyap, Desai if (!sdev)
47383eb0822cSKashyap, Desai break;
47393eb0822cSKashyap, Desai vdevice->vtarget->deleted = 1; /* block IO */
47403eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_RAID;
47413eb0822cSKashyap, Desai break;
47423eb0822cSKashyap, Desai }
4743bd23e94cSMoore, Eric switch (state) {
4744bd23e94cSMoore, Eric case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4745bd23e94cSMoore, Eric case MPI_RAIDVOL0_STATUS_STATE_MISSING:
47463eb0822cSKashyap, Desai if (!sdev)
47473eb0822cSKashyap, Desai break;
47483eb0822cSKashyap, Desai vdevice->vtarget->deleted = 1; /* block IO */
47493eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_RAID;
4750bd23e94cSMoore, Eric break;
4751bd23e94cSMoore, Eric case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4752bd23e94cSMoore, Eric case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
47533eb0822cSKashyap, Desai if (sdev) {
47543eb0822cSKashyap, Desai scsi_device_put(sdev);
47553eb0822cSKashyap, Desai break;
47563eb0822cSKashyap, Desai }
47573eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_RAID;
4758bd23e94cSMoore, Eric break;
4759bd23e94cSMoore, Eric default:
4760bd23e94cSMoore, Eric break;
4761bd23e94cSMoore, Eric }
4762c73787eeSMoore, Eric break;
4763c73787eeSMoore, Eric default:
4764c73787eeSMoore, Eric break;
4765c73787eeSMoore, Eric }
47663eb0822cSKashyap, Desai
47673eb0822cSKashyap, Desai if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
47683eb0822cSKashyap, Desai mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
47693eb0822cSKashyap, Desai else
47703eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
4771c73787eeSMoore, Eric }
4772c73787eeSMoore, Eric
4773db7051b2SKashyap, Desai /**
4774db7051b2SKashyap, Desai * mptsas_issue_tm - send mptsas internal tm request
4775db7051b2SKashyap, Desai * @ioc: Pointer to MPT_ADAPTER structure
4776db7051b2SKashyap, Desai * @type: Task Management type
4777db7051b2SKashyap, Desai * @channel: channel number for task management
4778db7051b2SKashyap, Desai * @id: Logical Target ID for reset (if appropriate)
4779db7051b2SKashyap, Desai * @lun: Logical unit for reset (if appropriate)
4780db7051b2SKashyap, Desai * @task_context: Context for the task to be aborted
4781db7051b2SKashyap, Desai * @timeout: timeout for task management control
4782cdcda465SRandy Dunlap * @issue_reset: set to 1 on return if reset is needed, else 0
4783db7051b2SKashyap, Desai *
4784cdcda465SRandy Dunlap * Return: 0 on success or -1 on failure.
4785db7051b2SKashyap, Desai *
4786db7051b2SKashyap, Desai */
4787db7051b2SKashyap, Desai static int
mptsas_issue_tm(MPT_ADAPTER * ioc,u8 type,u8 channel,u8 id,u64 lun,int task_context,ulong timeout,u8 * issue_reset)4788db7051b2SKashyap, Desai mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4789db7051b2SKashyap, Desai int task_context, ulong timeout, u8 *issue_reset)
4790db7051b2SKashyap, Desai {
4791db7051b2SKashyap, Desai MPT_FRAME_HDR *mf;
4792db7051b2SKashyap, Desai SCSITaskMgmt_t *pScsiTm;
4793db7051b2SKashyap, Desai int retval;
4794db7051b2SKashyap, Desai unsigned long timeleft;
4795db7051b2SKashyap, Desai
4796db7051b2SKashyap, Desai *issue_reset = 0;
4797db7051b2SKashyap, Desai mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4798db7051b2SKashyap, Desai if (mf == NULL) {
4799db7051b2SKashyap, Desai retval = -1; /* return failure */
4800db7051b2SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4801db7051b2SKashyap, Desai "msg frames!!\n", ioc->name));
4802db7051b2SKashyap, Desai goto out;
4803db7051b2SKashyap, Desai }
4804db7051b2SKashyap, Desai
4805db7051b2SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4806db7051b2SKashyap, Desai "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4807db7051b2SKashyap, Desai "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4808db7051b2SKashyap, Desai type, timeout, channel, id, (unsigned long long)lun,
4809db7051b2SKashyap, Desai task_context));
4810db7051b2SKashyap, Desai
4811db7051b2SKashyap, Desai pScsiTm = (SCSITaskMgmt_t *) mf;
4812db7051b2SKashyap, Desai memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4813db7051b2SKashyap, Desai pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4814db7051b2SKashyap, Desai pScsiTm->TaskType = type;
4815db7051b2SKashyap, Desai pScsiTm->MsgFlags = 0;
4816db7051b2SKashyap, Desai pScsiTm->TargetID = id;
4817db7051b2SKashyap, Desai pScsiTm->Bus = channel;
4818db7051b2SKashyap, Desai pScsiTm->ChainOffset = 0;
4819db7051b2SKashyap, Desai pScsiTm->Reserved = 0;
4820db7051b2SKashyap, Desai pScsiTm->Reserved1 = 0;
4821db7051b2SKashyap, Desai pScsiTm->TaskMsgContext = task_context;
4822db7051b2SKashyap, Desai int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4823db7051b2SKashyap, Desai
4824db7051b2SKashyap, Desai INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4825db7051b2SKashyap, Desai CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4826db7051b2SKashyap, Desai retval = 0;
4827db7051b2SKashyap, Desai mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4828db7051b2SKashyap, Desai
4829db7051b2SKashyap, Desai /* Now wait for the command to complete */
4830db7051b2SKashyap, Desai timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4831db7051b2SKashyap, Desai timeout*HZ);
4832db7051b2SKashyap, Desai if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4833db7051b2SKashyap, Desai retval = -1; /* return failure */
4834db7051b2SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4835db7051b2SKashyap, Desai "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4836db7051b2SKashyap, Desai mpt_free_msg_frame(ioc, mf);
4837db7051b2SKashyap, Desai if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4838db7051b2SKashyap, Desai goto out;
4839db7051b2SKashyap, Desai *issue_reset = 1;
4840db7051b2SKashyap, Desai goto out;
4841db7051b2SKashyap, Desai }
4842db7051b2SKashyap, Desai
4843db7051b2SKashyap, Desai if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4844db7051b2SKashyap, Desai retval = -1; /* return failure */
4845db7051b2SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4846db7051b2SKashyap, Desai "TaskMgmt request: failed with no reply\n", ioc->name));
4847db7051b2SKashyap, Desai goto out;
4848db7051b2SKashyap, Desai }
4849db7051b2SKashyap, Desai
4850db7051b2SKashyap, Desai out:
4851db7051b2SKashyap, Desai CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4852db7051b2SKashyap, Desai return retval;
4853db7051b2SKashyap, Desai }
4854db7051b2SKashyap, Desai
4855db7051b2SKashyap, Desai /**
485694e989deSColin Ian King * mptsas_broadcast_primitive_work - Handle broadcast primitives
4857cdcda465SRandy Dunlap * @fw_event: work queue payload containing info describing the event
4858db7051b2SKashyap, Desai *
4859cdcda465SRandy Dunlap * This will be handled in workqueue context.
4860db7051b2SKashyap, Desai */
4861db7051b2SKashyap, Desai static void
mptsas_broadcast_primitive_work(struct fw_event_work * fw_event)486294e989deSColin Ian King mptsas_broadcast_primitive_work(struct fw_event_work *fw_event)
4863db7051b2SKashyap, Desai {
4864db7051b2SKashyap, Desai MPT_ADAPTER *ioc = fw_event->ioc;
4865db7051b2SKashyap, Desai MPT_FRAME_HDR *mf;
4866db7051b2SKashyap, Desai VirtDevice *vdevice;
4867db7051b2SKashyap, Desai int ii;
4868db7051b2SKashyap, Desai struct scsi_cmnd *sc;
4869db7051b2SKashyap, Desai SCSITaskMgmtReply_t *pScsiTmReply;
4870db7051b2SKashyap, Desai u8 issue_reset;
4871db7051b2SKashyap, Desai int task_context;
4872db7051b2SKashyap, Desai u8 channel, id;
4873db7051b2SKashyap, Desai int lun;
4874db7051b2SKashyap, Desai u32 termination_count;
4875db7051b2SKashyap, Desai u32 query_count;
4876db7051b2SKashyap, Desai
4877db7051b2SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4878db7051b2SKashyap, Desai "%s - enter\n", ioc->name, __func__));
4879db7051b2SKashyap, Desai
4880db7051b2SKashyap, Desai mutex_lock(&ioc->taskmgmt_cmds.mutex);
4881db7051b2SKashyap, Desai if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4882db7051b2SKashyap, Desai mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4883db7051b2SKashyap, Desai mptsas_requeue_fw_event(ioc, fw_event, 1000);
4884db7051b2SKashyap, Desai return;
4885db7051b2SKashyap, Desai }
4886db7051b2SKashyap, Desai
4887db7051b2SKashyap, Desai issue_reset = 0;
4888db7051b2SKashyap, Desai termination_count = 0;
4889db7051b2SKashyap, Desai query_count = 0;
4890db7051b2SKashyap, Desai mpt_findImVolumes(ioc);
4891db7051b2SKashyap, Desai pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4892db7051b2SKashyap, Desai
4893db7051b2SKashyap, Desai for (ii = 0; ii < ioc->req_depth; ii++) {
4894db7051b2SKashyap, Desai if (ioc->fw_events_off)
4895db7051b2SKashyap, Desai goto out;
4896db7051b2SKashyap, Desai sc = mptscsih_get_scsi_lookup(ioc, ii);
4897db7051b2SKashyap, Desai if (!sc)
4898db7051b2SKashyap, Desai continue;
4899db7051b2SKashyap, Desai mf = MPT_INDEX_2_MFPTR(ioc, ii);
4900db7051b2SKashyap, Desai if (!mf)
4901db7051b2SKashyap, Desai continue;
4902db7051b2SKashyap, Desai task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4903db7051b2SKashyap, Desai vdevice = sc->device->hostdata;
4904db7051b2SKashyap, Desai if (!vdevice || !vdevice->vtarget)
4905db7051b2SKashyap, Desai continue;
4906db7051b2SKashyap, Desai if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4907db7051b2SKashyap, Desai continue; /* skip hidden raid components */
4908db7051b2SKashyap, Desai if (vdevice->vtarget->raidVolume)
4909db7051b2SKashyap, Desai continue; /* skip hidden raid components */
4910db7051b2SKashyap, Desai channel = vdevice->vtarget->channel;
4911db7051b2SKashyap, Desai id = vdevice->vtarget->id;
4912db7051b2SKashyap, Desai lun = vdevice->lun;
4913db7051b2SKashyap, Desai if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4914db7051b2SKashyap, Desai channel, id, (u64)lun, task_context, 30, &issue_reset))
4915db7051b2SKashyap, Desai goto out;
4916db7051b2SKashyap, Desai query_count++;
4917db7051b2SKashyap, Desai termination_count +=
4918db7051b2SKashyap, Desai le32_to_cpu(pScsiTmReply->TerminationCount);
4919db7051b2SKashyap, Desai if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4920db7051b2SKashyap, Desai (pScsiTmReply->ResponseCode ==
4921db7051b2SKashyap, Desai MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4922db7051b2SKashyap, Desai pScsiTmReply->ResponseCode ==
4923db7051b2SKashyap, Desai MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4924db7051b2SKashyap, Desai continue;
4925db7051b2SKashyap, Desai if (mptsas_issue_tm(ioc,
4926db7051b2SKashyap, Desai MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4927db7051b2SKashyap, Desai channel, id, (u64)lun, 0, 30, &issue_reset))
4928db7051b2SKashyap, Desai goto out;
4929db7051b2SKashyap, Desai termination_count +=
4930db7051b2SKashyap, Desai le32_to_cpu(pScsiTmReply->TerminationCount);
4931db7051b2SKashyap, Desai }
4932db7051b2SKashyap, Desai
4933db7051b2SKashyap, Desai out:
4934db7051b2SKashyap, Desai dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4935db7051b2SKashyap, Desai "%s - exit, query_count = %d termination_count = %d\n",
4936db7051b2SKashyap, Desai ioc->name, __func__, query_count, termination_count));
4937db7051b2SKashyap, Desai
4938db7051b2SKashyap, Desai ioc->broadcast_aen_busy = 0;
4939db7051b2SKashyap, Desai mpt_clear_taskmgmt_in_progress_flag(ioc);
4940db7051b2SKashyap, Desai mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4941db7051b2SKashyap, Desai
4942db7051b2SKashyap, Desai if (issue_reset) {
494397009a29SKei Tokunaga printk(MYIOC_s_WARN_FMT
494497009a29SKei Tokunaga "Issuing Reset from %s!! doorbell=0x%08x\n",
494597009a29SKei Tokunaga ioc->name, __func__, mpt_GetIocState(ioc, 0));
4946d0f698c4SKashyap, Desai mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
4947db7051b2SKashyap, Desai }
4948db7051b2SKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
4949db7051b2SKashyap, Desai }
4950db7051b2SKashyap, Desai
4951b506ade9SEric Moore /*
4952b506ade9SEric Moore * mptsas_send_ir2_event - handle exposing hidden disk when
4953b506ade9SEric Moore * an inactive raid volume is added
4954b506ade9SEric Moore *
4955b506ade9SEric Moore * @ioc: Pointer to MPT_ADAPTER structure
4956b506ade9SEric Moore * @ir2_data
4957b506ade9SEric Moore *
4958b506ade9SEric Moore */
4959b506ade9SEric Moore static void
mptsas_send_ir2_event(struct fw_event_work * fw_event)49603eb0822cSKashyap, Desai mptsas_send_ir2_event(struct fw_event_work *fw_event)
4961b506ade9SEric Moore {
49623eb0822cSKashyap, Desai MPT_ADAPTER *ioc;
49633eb0822cSKashyap, Desai struct mptsas_hotplug_event hot_plug_info;
49643eb0822cSKashyap, Desai MPI_EVENT_DATA_IR2 *ir2_data;
49653eb0822cSKashyap, Desai u8 reasonCode;
4966a7938b0bSKashyap, Desai RaidPhysDiskPage0_t phys_disk;
4967b506ade9SEric Moore
49683eb0822cSKashyap, Desai ioc = fw_event->ioc;
49693eb0822cSKashyap, Desai ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
49703eb0822cSKashyap, Desai reasonCode = ir2_data->ReasonCode;
49713eb0822cSKashyap, Desai
49723eb0822cSKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
49733eb0822cSKashyap, Desai "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
49743eb0822cSKashyap, Desai
49753eb0822cSKashyap, Desai memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
49763eb0822cSKashyap, Desai hot_plug_info.id = ir2_data->TargetID;
49773eb0822cSKashyap, Desai hot_plug_info.channel = ir2_data->Bus;
49783eb0822cSKashyap, Desai switch (reasonCode) {
49793eb0822cSKashyap, Desai case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
49803eb0822cSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
49813eb0822cSKashyap, Desai break;
4982a7938b0bSKashyap, Desai case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4983a7938b0bSKashyap, Desai hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4984a7938b0bSKashyap, Desai hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4985a7938b0bSKashyap, Desai break;
4986a7938b0bSKashyap, Desai case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4987a7938b0bSKashyap, Desai hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4988a7938b0bSKashyap, Desai mpt_raid_phys_disk_pg0(ioc,
4989a7938b0bSKashyap, Desai ir2_data->PhysDiskNum, &phys_disk);
4990a7938b0bSKashyap, Desai hot_plug_info.id = phys_disk.PhysDiskID;
4991a7938b0bSKashyap, Desai hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4992a7938b0bSKashyap, Desai break;
49933eb0822cSKashyap, Desai default:
49943eb0822cSKashyap, Desai mptsas_free_fw_event(ioc, fw_event);
4995b506ade9SEric Moore return;
49963eb0822cSKashyap, Desai }
49973eb0822cSKashyap, Desai mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
49983eb0822cSKashyap, Desai }
4999e6b2d76aSMoore, Eric
50009a28f49aSChristoph Hellwig static int
mptsas_event_process(MPT_ADAPTER * ioc,EventNotificationReply_t * reply)50019a28f49aSChristoph Hellwig mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
50029a28f49aSChristoph Hellwig {
50033eb0822cSKashyap, Desai u32 event = le32_to_cpu(reply->Event);
500432696198SJoe Lawrence int event_data_sz;
50053eb0822cSKashyap, Desai struct fw_event_work *fw_event;
50063eb0822cSKashyap, Desai unsigned long delay;
50079a28f49aSChristoph Hellwig
5008ffb7fef3SKashyap, Desai if (ioc->bus_type != SAS)
5009ffb7fef3SKashyap, Desai return 0;
5010ffb7fef3SKashyap, Desai
50113eb0822cSKashyap, Desai /* events turned off due to host reset or driver unloading */
50123eb0822cSKashyap, Desai if (ioc->fw_events_off)
50133eb0822cSKashyap, Desai return 0;
50149a28f49aSChristoph Hellwig
50153eb0822cSKashyap, Desai delay = msecs_to_jiffies(1);
50169a28f49aSChristoph Hellwig switch (event) {
5017db7051b2SKashyap, Desai case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
5018db7051b2SKashyap, Desai {
5019db7051b2SKashyap, Desai EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
5020db7051b2SKashyap, Desai (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
5021db7051b2SKashyap, Desai if (broadcast_event_data->Primitive !=
5022db7051b2SKashyap, Desai MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
5023db7051b2SKashyap, Desai return 0;
5024db7051b2SKashyap, Desai if (ioc->broadcast_aen_busy)
5025db7051b2SKashyap, Desai return 0;
5026db7051b2SKashyap, Desai ioc->broadcast_aen_busy = 1;
5027db7051b2SKashyap, Desai break;
5028db7051b2SKashyap, Desai }
50299a28f49aSChristoph Hellwig case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
50303eb0822cSKashyap, Desai {
50313eb0822cSKashyap, Desai EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
50323eb0822cSKashyap, Desai (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
5033c9de7dc4SKashyap, Desai u16 ioc_stat;
5034c9de7dc4SKashyap, Desai ioc_stat = le16_to_cpu(reply->IOCStatus);
50353eb0822cSKashyap, Desai
50363eb0822cSKashyap, Desai if (sas_event_data->ReasonCode ==
50373eb0822cSKashyap, Desai MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
50383eb0822cSKashyap, Desai mptsas_target_reset_queue(ioc, sas_event_data);
50393eb0822cSKashyap, Desai return 0;
50403eb0822cSKashyap, Desai }
5041c9de7dc4SKashyap, Desai if (sas_event_data->ReasonCode ==
5042c9de7dc4SKashyap, Desai MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
5043c9de7dc4SKashyap, Desai ioc->device_missing_delay &&
5044c9de7dc4SKashyap, Desai (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
5045c9de7dc4SKashyap, Desai VirtTarget *vtarget = NULL;
5046c9de7dc4SKashyap, Desai u8 id, channel;
5047c9de7dc4SKashyap, Desai
5048c9de7dc4SKashyap, Desai id = sas_event_data->TargetID;
5049c9de7dc4SKashyap, Desai channel = sas_event_data->Bus;
5050c9de7dc4SKashyap, Desai
5051c9de7dc4SKashyap, Desai vtarget = mptsas_find_vtarget(ioc, channel, id);
5052c9de7dc4SKashyap, Desai if (vtarget) {
5053c9de7dc4SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5054c9de7dc4SKashyap, Desai "LogInfo (0x%x) available for "
5055c9de7dc4SKashyap, Desai "INTERNAL_DEVICE_RESET"
5056c9de7dc4SKashyap, Desai "fw_id %d fw_channel %d\n", ioc->name,
505772ef0e57SBorislav Petkov le32_to_cpu(reply->IOCLogInfo),
505872ef0e57SBorislav Petkov id, channel));
5059c9de7dc4SKashyap, Desai if (vtarget->raidVolume) {
5060c9de7dc4SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5061c9de7dc4SKashyap, Desai "Skipping Raid Volume for inDMD\n",
5062c9de7dc4SKashyap, Desai ioc->name));
5063c9de7dc4SKashyap, Desai } else {
5064c9de7dc4SKashyap, Desai devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5065c9de7dc4SKashyap, Desai "Setting device flag inDMD\n",
5066c9de7dc4SKashyap, Desai ioc->name));
5067c9de7dc4SKashyap, Desai vtarget->inDMD = 1;
5068c9de7dc4SKashyap, Desai }
5069c9de7dc4SKashyap, Desai
5070c9de7dc4SKashyap, Desai }
5071c9de7dc4SKashyap, Desai
5072c9de7dc4SKashyap, Desai }
5073c9de7dc4SKashyap, Desai
5074c73787eeSMoore, Eric break;
50753eb0822cSKashyap, Desai }
5076f9c34022SKashyap, Desai case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
5077f9c34022SKashyap, Desai {
5078f9c34022SKashyap, Desai MpiEventDataSasExpanderStatusChange_t *expander_data =
5079f9c34022SKashyap, Desai (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
5080f9c34022SKashyap, Desai
5081eedf92b9SKashyap, Desai if (ioc->old_sas_discovery_protocal)
5082eedf92b9SKashyap, Desai return 0;
5083f9c34022SKashyap, Desai
5084f9c34022SKashyap, Desai if (expander_data->ReasonCode ==
5085f9c34022SKashyap, Desai MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
5086f9c34022SKashyap, Desai ioc->device_missing_delay)
5087f9c34022SKashyap, Desai delay = HZ * ioc->device_missing_delay;
5088e6b2d76aSMoore, Eric break;
5089f9c34022SKashyap, Desai }
5090f9c34022SKashyap, Desai case MPI_EVENT_SAS_DISCOVERY:
5091f9c34022SKashyap, Desai {
5092f9c34022SKashyap, Desai u32 discovery_status;
5093f9c34022SKashyap, Desai EventDataSasDiscovery_t *discovery_data =
5094f9c34022SKashyap, Desai (EventDataSasDiscovery_t *)reply->Data;
5095f9c34022SKashyap, Desai
5096f9c34022SKashyap, Desai discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
5097f9c34022SKashyap, Desai ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
5098eedf92b9SKashyap, Desai if (ioc->old_sas_discovery_protocal && !discovery_status)
5099eedf92b9SKashyap, Desai mptsas_queue_rescan(ioc);
5100f9c34022SKashyap, Desai return 0;
5101f9c34022SKashyap, Desai }
51023eb0822cSKashyap, Desai case MPI_EVENT_INTEGRATED_RAID:
51033eb0822cSKashyap, Desai case MPI_EVENT_PERSISTENT_TABLE_FULL:
5104b506ade9SEric Moore case MPI_EVENT_IR2:
51053eb0822cSKashyap, Desai case MPI_EVENT_SAS_PHY_LINK_STATUS:
51063eb0822cSKashyap, Desai case MPI_EVENT_QUEUE_FULL:
5107b506ade9SEric Moore break;
51089a28f49aSChristoph Hellwig default:
51093eb0822cSKashyap, Desai return 0;
51109a28f49aSChristoph Hellwig }
5111c73787eeSMoore, Eric
51123eb0822cSKashyap, Desai event_data_sz = ((reply->MsgLength * 4) -
51133eb0822cSKashyap, Desai offsetof(EventNotificationReply_t, Data));
511432696198SJoe Lawrence fw_event = kzalloc(sizeof(*fw_event) + event_data_sz, GFP_ATOMIC);
51153eb0822cSKashyap, Desai if (!fw_event) {
51163eb0822cSKashyap, Desai printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
51173eb0822cSKashyap, Desai __func__, __LINE__);
51183eb0822cSKashyap, Desai return 0;
51193eb0822cSKashyap, Desai }
51203eb0822cSKashyap, Desai memcpy(fw_event->event_data, reply->Data, event_data_sz);
51213eb0822cSKashyap, Desai fw_event->event = event;
51223eb0822cSKashyap, Desai fw_event->ioc = ioc;
51233eb0822cSKashyap, Desai mptsas_add_fw_event(ioc, fw_event, delay);
51243eb0822cSKashyap, Desai return 0;
51259a28f49aSChristoph Hellwig }
51269a28f49aSChristoph Hellwig
5127a7938b0bSKashyap, Desai /* Delete a volume when no longer listed in ioc pg2
5128a7938b0bSKashyap, Desai */
mptsas_volume_delete(MPT_ADAPTER * ioc,u8 id)5129a7938b0bSKashyap, Desai static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
5130a7938b0bSKashyap, Desai {
5131a7938b0bSKashyap, Desai struct scsi_device *sdev;
5132a7938b0bSKashyap, Desai int i;
5133a7938b0bSKashyap, Desai
5134a7938b0bSKashyap, Desai sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
5135a7938b0bSKashyap, Desai if (!sdev)
5136a7938b0bSKashyap, Desai return;
5137a7938b0bSKashyap, Desai if (!ioc->raid_data.pIocPg2)
5138a7938b0bSKashyap, Desai goto out;
5139a7938b0bSKashyap, Desai if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
5140a7938b0bSKashyap, Desai goto out;
5141a7938b0bSKashyap, Desai for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
5142a7938b0bSKashyap, Desai if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
5143a7938b0bSKashyap, Desai goto release_sdev;
5144a7938b0bSKashyap, Desai out:
5145a7938b0bSKashyap, Desai printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
5146a7938b0bSKashyap, Desai "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
5147a7938b0bSKashyap, Desai scsi_remove_device(sdev);
5148a7938b0bSKashyap, Desai release_sdev:
5149a7938b0bSKashyap, Desai scsi_device_put(sdev);
5150a7938b0bSKashyap, Desai }
5151a7938b0bSKashyap, Desai
51520c33b27dSChristoph Hellwig static int
mptsas_probe(struct pci_dev * pdev,const struct pci_device_id * id)51530c33b27dSChristoph Hellwig mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
51540c33b27dSChristoph Hellwig {
51550c33b27dSChristoph Hellwig struct Scsi_Host *sh;
51560c33b27dSChristoph Hellwig MPT_SCSI_HOST *hd;
51570c33b27dSChristoph Hellwig MPT_ADAPTER *ioc;
51580c33b27dSChristoph Hellwig unsigned long flags;
51591ca00bb7SChristoph Hellwig int ii;
51600c33b27dSChristoph Hellwig int numSGE = 0;
51610c33b27dSChristoph Hellwig int scale;
51620c33b27dSChristoph Hellwig int ioc_cap;
51630c33b27dSChristoph Hellwig int error=0;
51640c33b27dSChristoph Hellwig int r;
51650c33b27dSChristoph Hellwig
51660c33b27dSChristoph Hellwig r = mpt_attach(pdev,id);
51670c33b27dSChristoph Hellwig if (r)
51680c33b27dSChristoph Hellwig return r;
51690c33b27dSChristoph Hellwig
51700c33b27dSChristoph Hellwig ioc = pci_get_drvdata(pdev);
51713eb0822cSKashyap, Desai mptsas_fw_event_off(ioc);
51720c33b27dSChristoph Hellwig ioc->DoneCtx = mptsasDoneCtx;
51730c33b27dSChristoph Hellwig ioc->TaskCtx = mptsasTaskCtx;
51740c33b27dSChristoph Hellwig ioc->InternalCtx = mptsasInternalCtx;
5175b68bf096SKashyap, Desai ioc->schedule_target_reset = &mptsas_schedule_target_reset;
5176e62cca19Skashyap.desai@lsi.com ioc->schedule_dead_ioc_flush_running_cmds =
5177e62cca19Skashyap.desai@lsi.com &mptscsih_flush_running_cmds;
51780c33b27dSChristoph Hellwig /* Added sanity check on readiness of the MPT adapter.
51790c33b27dSChristoph Hellwig */
51800c33b27dSChristoph Hellwig if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
51810c33b27dSChristoph Hellwig printk(MYIOC_s_WARN_FMT
51820c33b27dSChristoph Hellwig "Skipping because it's not operational!\n",
51830c33b27dSChristoph Hellwig ioc->name);
51847acec1e7SMoore, Eric Dean error = -ENODEV;
51857acec1e7SMoore, Eric Dean goto out_mptsas_probe;
51860c33b27dSChristoph Hellwig }
51870c33b27dSChristoph Hellwig
51880c33b27dSChristoph Hellwig if (!ioc->active) {
51890c33b27dSChristoph Hellwig printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
51900c33b27dSChristoph Hellwig ioc->name);
51917acec1e7SMoore, Eric Dean error = -ENODEV;
51927acec1e7SMoore, Eric Dean goto out_mptsas_probe;
51930c33b27dSChristoph Hellwig }
51940c33b27dSChristoph Hellwig
51950c33b27dSChristoph Hellwig /* Sanity check - ensure at least 1 port is INITIATOR capable
51960c33b27dSChristoph Hellwig */
51970c33b27dSChristoph Hellwig ioc_cap = 0;
51980c33b27dSChristoph Hellwig for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
51990c33b27dSChristoph Hellwig if (ioc->pfacts[ii].ProtocolFlags &
52000c33b27dSChristoph Hellwig MPI_PORTFACTS_PROTOCOL_INITIATOR)
52010c33b27dSChristoph Hellwig ioc_cap++;
52020c33b27dSChristoph Hellwig }
52030c33b27dSChristoph Hellwig
52040c33b27dSChristoph Hellwig if (!ioc_cap) {
52050c33b27dSChristoph Hellwig printk(MYIOC_s_WARN_FMT
52060c33b27dSChristoph Hellwig "Skipping ioc=%p because SCSI Initiator mode "
52070c33b27dSChristoph Hellwig "is NOT enabled!\n", ioc->name, ioc);
5208466544d8SMoore, Eric Dean return 0;
52090c33b27dSChristoph Hellwig }
52100c33b27dSChristoph Hellwig
52110c33b27dSChristoph Hellwig sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
52120c33b27dSChristoph Hellwig if (!sh) {
52130c33b27dSChristoph Hellwig printk(MYIOC_s_WARN_FMT
52140c33b27dSChristoph Hellwig "Unable to register controller with SCSI subsystem\n",
52150c33b27dSChristoph Hellwig ioc->name);
52167acec1e7SMoore, Eric Dean error = -1;
52177acec1e7SMoore, Eric Dean goto out_mptsas_probe;
52180c33b27dSChristoph Hellwig }
52190c33b27dSChristoph Hellwig
52200c33b27dSChristoph Hellwig spin_lock_irqsave(&ioc->FreeQlock, flags);
52210c33b27dSChristoph Hellwig
52220c33b27dSChristoph Hellwig /* Attach the SCSI Host to the IOC structure
52230c33b27dSChristoph Hellwig */
52240c33b27dSChristoph Hellwig ioc->sh = sh;
52250c33b27dSChristoph Hellwig
52260c33b27dSChristoph Hellwig sh->io_port = 0;
52270c33b27dSChristoph Hellwig sh->n_io_port = 0;
52280c33b27dSChristoph Hellwig sh->irq = 0;
52290c33b27dSChristoph Hellwig
52300c33b27dSChristoph Hellwig /* set 16 byte cdb's */
52310c33b27dSChristoph Hellwig sh->max_cmd_len = 16;
523279a3ec1aSKashyap, Desai sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
523379a3ec1aSKashyap, Desai sh->max_id = -1;
5234793955f5SEric Moore sh->max_lun = max_lun;
52350c33b27dSChristoph Hellwig sh->transportt = mptsas_transport_template;
52360c33b27dSChristoph Hellwig
52370c33b27dSChristoph Hellwig /* Required entry.
52380c33b27dSChristoph Hellwig */
52390c33b27dSChristoph Hellwig sh->unique_id = ioc->id;
52400c33b27dSChristoph Hellwig
52410c33b27dSChristoph Hellwig INIT_LIST_HEAD(&ioc->sas_topology);
52429a28f49aSChristoph Hellwig mutex_init(&ioc->sas_topology_mutex);
5243e6b2d76aSMoore, Eric mutex_init(&ioc->sas_discovery_mutex);
5244eeb846ceSChristoph Hellwig mutex_init(&ioc->sas_mgmt.mutex);
5245da4fa655SChristoph Hellwig init_completion(&ioc->sas_mgmt.done);
52460c33b27dSChristoph Hellwig
52470c33b27dSChristoph Hellwig /* Verify that we won't exceed the maximum
52480c33b27dSChristoph Hellwig * number of chain buffers
52490c33b27dSChristoph Hellwig * We can optimize: ZZ = req_sz/sizeof(SGE)
52500c33b27dSChristoph Hellwig * For 32bit SGE's:
52510c33b27dSChristoph Hellwig * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
52520c33b27dSChristoph Hellwig * + (req_sz - 64)/sizeof(SGE)
52530c33b27dSChristoph Hellwig * A slightly different algorithm is required for
52540c33b27dSChristoph Hellwig * 64bit SGEs.
52550c33b27dSChristoph Hellwig */
525614d0f0b0SKashyap, Desai scale = ioc->req_sz/ioc->SGE_size;
525714d0f0b0SKashyap, Desai if (ioc->sg_addr_size == sizeof(u64)) {
52580c33b27dSChristoph Hellwig numSGE = (scale - 1) *
52590c33b27dSChristoph Hellwig (ioc->facts.MaxChainDepth-1) + scale +
526014d0f0b0SKashyap, Desai (ioc->req_sz - 60) / ioc->SGE_size;
52610c33b27dSChristoph Hellwig } else {
52620c33b27dSChristoph Hellwig numSGE = 1 + (scale - 1) *
52630c33b27dSChristoph Hellwig (ioc->facts.MaxChainDepth-1) + scale +
526414d0f0b0SKashyap, Desai (ioc->req_sz - 64) / ioc->SGE_size;
52650c33b27dSChristoph Hellwig }
52660c33b27dSChristoph Hellwig
52670c33b27dSChristoph Hellwig if (numSGE < sh->sg_tablesize) {
52680c33b27dSChristoph Hellwig /* Reset this value */
5269d6ecdd63SPrakash, Sathya dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
52700c33b27dSChristoph Hellwig "Resetting sg_tablesize to %d from %d\n",
52710c33b27dSChristoph Hellwig ioc->name, numSGE, sh->sg_tablesize));
52720c33b27dSChristoph Hellwig sh->sg_tablesize = numSGE;
52730c33b27dSChristoph Hellwig }
52740c33b27dSChristoph Hellwig
52753850b14eSkashyap.desai@lsi.com if (mpt_loadtime_max_sectors) {
52763850b14eSkashyap.desai@lsi.com if (mpt_loadtime_max_sectors < 64 ||
52773850b14eSkashyap.desai@lsi.com mpt_loadtime_max_sectors > 8192) {
52783850b14eSkashyap.desai@lsi.com printk(MYIOC_s_INFO_FMT "Invalid value passed for"
52793850b14eSkashyap.desai@lsi.com "mpt_loadtime_max_sectors %d."
52803850b14eSkashyap.desai@lsi.com "Range from 64 to 8192\n", ioc->name,
52813850b14eSkashyap.desai@lsi.com mpt_loadtime_max_sectors);
52823850b14eSkashyap.desai@lsi.com }
52833850b14eSkashyap.desai@lsi.com mpt_loadtime_max_sectors &= 0xFFFFFFFE;
52843850b14eSkashyap.desai@lsi.com dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
52853850b14eSkashyap.desai@lsi.com "Resetting max sector to %d from %d\n",
52863850b14eSkashyap.desai@lsi.com ioc->name, mpt_loadtime_max_sectors, sh->max_sectors));
52873850b14eSkashyap.desai@lsi.com sh->max_sectors = mpt_loadtime_max_sectors;
52883850b14eSkashyap.desai@lsi.com }
52893850b14eSkashyap.desai@lsi.com
5290e7eae9f6SEric Moore hd = shost_priv(sh);
52910c33b27dSChristoph Hellwig hd->ioc = ioc;
52920c33b27dSChristoph Hellwig
52930c33b27dSChristoph Hellwig /* SCSI needs scsi_cmnd lookup table!
52940c33b27dSChristoph Hellwig * (with size equal to req_depth*PtrSz!)
52950c33b27dSChristoph Hellwig */
5296e8206381SEric Moore ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5297e8206381SEric Moore if (!ioc->ScsiLookup) {
52980c33b27dSChristoph Hellwig error = -ENOMEM;
5299bc6e089aSEric Moore spin_unlock_irqrestore(&ioc->FreeQlock, flags);
53007acec1e7SMoore, Eric Dean goto out_mptsas_probe;
53010c33b27dSChristoph Hellwig }
5302e8206381SEric Moore spin_lock_init(&ioc->scsi_lookup_lock);
53030c33b27dSChristoph Hellwig
5304d6ecdd63SPrakash, Sathya dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
5305e8206381SEric Moore ioc->name, ioc->ScsiLookup));
53060c33b27dSChristoph Hellwig
53070c33b27dSChristoph Hellwig ioc->sas_data.ptClear = mpt_pt_clear;
53080c33b27dSChristoph Hellwig
5309df9e062aSEric Moore hd->last_queue_full = 0;
5310df9e062aSEric Moore INIT_LIST_HEAD(&hd->target_reset_list);
53113eb0822cSKashyap, Desai INIT_LIST_HEAD(&ioc->sas_device_info_list);
53123eb0822cSKashyap, Desai mutex_init(&ioc->sas_device_info_mutex);
53133eb0822cSKashyap, Desai
5314df9e062aSEric Moore spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5315df9e062aSEric Moore
53160c33b27dSChristoph Hellwig if (ioc->sas_data.ptClear==1) {
53170c33b27dSChristoph Hellwig mptbase_sas_persist_operation(
53180c33b27dSChristoph Hellwig ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
53190c33b27dSChristoph Hellwig }
53200c33b27dSChristoph Hellwig
53210c33b27dSChristoph Hellwig error = scsi_add_host(sh, &ioc->pcidev->dev);
53220c33b27dSChristoph Hellwig if (error) {
532329dd3609SEric Moore dprintk(ioc, printk(MYIOC_s_ERR_FMT
532429dd3609SEric Moore "scsi_add_host failed\n", ioc->name));
53257acec1e7SMoore, Eric Dean goto out_mptsas_probe;
53260c33b27dSChristoph Hellwig }
53270c33b27dSChristoph Hellwig
5328eedf92b9SKashyap, Desai /* older firmware doesn't support expander events */
5329eedf92b9SKashyap, Desai if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5330eedf92b9SKashyap, Desai ioc->old_sas_discovery_protocal = 1;
53310c33b27dSChristoph Hellwig mptsas_scan_sas_topology(ioc);
53323eb0822cSKashyap, Desai mptsas_fw_event_on(ioc);
53330c33b27dSChristoph Hellwig return 0;
53340c33b27dSChristoph Hellwig
53357acec1e7SMoore, Eric Dean out_mptsas_probe:
53360c33b27dSChristoph Hellwig
53370c33b27dSChristoph Hellwig mptscsih_remove(pdev);
53380c33b27dSChristoph Hellwig return error;
53390c33b27dSChristoph Hellwig }
53400c33b27dSChristoph Hellwig
53415767d25fSJoe Lawrence static void
mptsas_shutdown(struct pci_dev * pdev)53427b5a65b9SKashyap, Desai mptsas_shutdown(struct pci_dev *pdev)
53437b5a65b9SKashyap, Desai {
53447b5a65b9SKashyap, Desai MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
53457b5a65b9SKashyap, Desai
53463eb0822cSKashyap, Desai mptsas_fw_event_off(ioc);
53473eb0822cSKashyap, Desai mptsas_cleanup_fw_event_q(ioc);
53487b5a65b9SKashyap, Desai }
53497b5a65b9SKashyap, Desai
mptsas_remove(struct pci_dev * pdev)535047b1ea75SGreg Kroah-Hartman static void mptsas_remove(struct pci_dev *pdev)
53510c33b27dSChristoph Hellwig {
53520c33b27dSChristoph Hellwig MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
53530c33b27dSChristoph Hellwig struct mptsas_portinfo *p, *n;
5354547f9a21SEric Moore int i;
53550c33b27dSChristoph Hellwig
535648959f1eSKashyap, Desai if (!ioc->sh) {
535748959f1eSKashyap, Desai printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
535848959f1eSKashyap, Desai mpt_detach(pdev);
535948959f1eSKashyap, Desai return;
536048959f1eSKashyap, Desai }
536148959f1eSKashyap, Desai
53627b5a65b9SKashyap, Desai mptsas_shutdown(pdev);
53637b5a65b9SKashyap, Desai
53643eb0822cSKashyap, Desai mptsas_del_device_components(ioc);
53653eb0822cSKashyap, Desai
5366e6b2d76aSMoore, Eric ioc->sas_discovery_ignore_events = 1;
53670c33b27dSChristoph Hellwig sas_remove_host(ioc->sh);
53680c33b27dSChristoph Hellwig
53699a28f49aSChristoph Hellwig mutex_lock(&ioc->sas_topology_mutex);
53700c33b27dSChristoph Hellwig list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
53710c33b27dSChristoph Hellwig list_del(&p->list);
5372547f9a21SEric Moore for (i = 0 ; i < p->num_phys ; i++)
5373d6ecdd63SPrakash, Sathya mptsas_port_delete(ioc, p->phy_info[i].port_details);
53743eb0822cSKashyap, Desai
5375db9c9174SMoore, Eric kfree(p->phy_info);
53760c33b27dSChristoph Hellwig kfree(p);
53770c33b27dSChristoph Hellwig }
53789a28f49aSChristoph Hellwig mutex_unlock(&ioc->sas_topology_mutex);
5379f9c34022SKashyap, Desai ioc->hba_port_info = NULL;
53800c33b27dSChristoph Hellwig mptscsih_remove(pdev);
53810c33b27dSChristoph Hellwig }
53820c33b27dSChristoph Hellwig
53830c33b27dSChristoph Hellwig static struct pci_device_id mptsas_pci_table[] = {
538487cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
53850c33b27dSChristoph Hellwig PCI_ANY_ID, PCI_ANY_ID },
538687cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
53870c33b27dSChristoph Hellwig PCI_ANY_ID, PCI_ANY_ID },
538887cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
53890c33b27dSChristoph Hellwig PCI_ANY_ID, PCI_ANY_ID },
539087cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
53910c33b27dSChristoph Hellwig PCI_ANY_ID, PCI_ANY_ID },
539287cf8986SEric Moore { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
53930c33b27dSChristoph Hellwig PCI_ANY_ID, PCI_ANY_ID },
539485d37226SChandrakala Chavva { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068_820XELP,
539585d37226SChandrakala Chavva PCI_ANY_ID, PCI_ANY_ID },
53960c33b27dSChristoph Hellwig {0} /* Terminating entry */
53970c33b27dSChristoph Hellwig };
53980c33b27dSChristoph Hellwig MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
53990c33b27dSChristoph Hellwig
54000c33b27dSChristoph Hellwig
54010c33b27dSChristoph Hellwig static struct pci_driver mptsas_driver = {
54020c33b27dSChristoph Hellwig .name = "mptsas",
54030c33b27dSChristoph Hellwig .id_table = mptsas_pci_table,
54040c33b27dSChristoph Hellwig .probe = mptsas_probe,
540547b1ea75SGreg Kroah-Hartman .remove = mptsas_remove,
54067b5a65b9SKashyap, Desai .shutdown = mptsas_shutdown,
54070c33b27dSChristoph Hellwig #ifdef CONFIG_PM
54080c33b27dSChristoph Hellwig .suspend = mptscsih_suspend,
54090c33b27dSChristoph Hellwig .resume = mptscsih_resume,
54100c33b27dSChristoph Hellwig #endif
54110c33b27dSChristoph Hellwig };
54120c33b27dSChristoph Hellwig
54130c33b27dSChristoph Hellwig static int __init
mptsas_init(void)54140c33b27dSChristoph Hellwig mptsas_init(void)
54150c33b27dSChristoph Hellwig {
541657ce21bfSPrakash, Sathya int error;
541757ce21bfSPrakash, Sathya
54180c33b27dSChristoph Hellwig show_mptmod_ver(my_NAME, my_VERSION);
54190c33b27dSChristoph Hellwig
54200c33b27dSChristoph Hellwig mptsas_transport_template =
54210c33b27dSChristoph Hellwig sas_attach_transport(&mptsas_transport_functions);
54220c33b27dSChristoph Hellwig if (!mptsas_transport_template)
54230c33b27dSChristoph Hellwig return -ENODEV;
54240c33b27dSChristoph Hellwig
5425213aaca3SKashyap, Desai mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
5426213aaca3SKashyap, Desai "mptscsih_io_done");
5427213aaca3SKashyap, Desai mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
5428213aaca3SKashyap, Desai "mptscsih_taskmgmt_complete");
54290c33b27dSChristoph Hellwig mptsasInternalCtx =
5430213aaca3SKashyap, Desai mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
5431213aaca3SKashyap, Desai "mptscsih_scandv_complete");
5432213aaca3SKashyap, Desai mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
5433213aaca3SKashyap, Desai "mptsas_mgmt_done");
5434e7deff33SKashyap, Desai mptsasDeviceResetCtx =
5435213aaca3SKashyap, Desai mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
5436213aaca3SKashyap, Desai "mptsas_taskmgmt_complete");
54370c33b27dSChristoph Hellwig
5438d6ecdd63SPrakash, Sathya mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5439d6ecdd63SPrakash, Sathya mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
54400c33b27dSChristoph Hellwig
544157ce21bfSPrakash, Sathya error = pci_register_driver(&mptsas_driver);
544257ce21bfSPrakash, Sathya if (error)
544357ce21bfSPrakash, Sathya sas_release_transport(mptsas_transport_template);
544457ce21bfSPrakash, Sathya
544557ce21bfSPrakash, Sathya return error;
54460c33b27dSChristoph Hellwig }
54470c33b27dSChristoph Hellwig
54480c33b27dSChristoph Hellwig static void __exit
mptsas_exit(void)54490c33b27dSChristoph Hellwig mptsas_exit(void)
54500c33b27dSChristoph Hellwig {
54510c33b27dSChristoph Hellwig pci_unregister_driver(&mptsas_driver);
54520c33b27dSChristoph Hellwig sas_release_transport(mptsas_transport_template);
54530c33b27dSChristoph Hellwig
54540c33b27dSChristoph Hellwig mpt_reset_deregister(mptsasDoneCtx);
54550c33b27dSChristoph Hellwig mpt_event_deregister(mptsasDoneCtx);
54560c33b27dSChristoph Hellwig
5457da4fa655SChristoph Hellwig mpt_deregister(mptsasMgmtCtx);
54580c33b27dSChristoph Hellwig mpt_deregister(mptsasInternalCtx);
54590c33b27dSChristoph Hellwig mpt_deregister(mptsasTaskCtx);
54600c33b27dSChristoph Hellwig mpt_deregister(mptsasDoneCtx);
5461e7deff33SKashyap, Desai mpt_deregister(mptsasDeviceResetCtx);
54620c33b27dSChristoph Hellwig }
54630c33b27dSChristoph Hellwig
54640c33b27dSChristoph Hellwig module_init(mptsas_init);
54650c33b27dSChristoph Hellwig module_exit(mptsas_exit);
5466