blob: 8963f5c44c235b500f55defb32ce9784b6d28456 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
9/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 NO WARRANTY
21 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 solely responsible for determining the appropriateness of using and
26 distributing the Program and assumes all risks associated with its
27 exercise of rights under this Agreement, including but not limited to
28 the risks and costs of program errors, damage to or loss of data,
29 programs or equipment, and unavailability or interruption of operations.
30
31 DISCLAIMER OF LIABILITY
32 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43*/
44/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45
46#include <linux/module.h>
47#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090048#include <linux/slab.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020049#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060060#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020061
62#include "mptbase.h"
63#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053064#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020065
66
67#define my_NAME "Fusion MPT SAS Host driver"
68#define my_VERSION MPT_LINUX_VERSION_COMMON
69#define MYNAM "mptsas"
70
James Bottomleye8bf3942006-07-11 17:49:34 -040071/*
72 * Reserved channel for integrated raid
73 */
74#define MPTSAS_RAID_CHANNEL 1
75
Kashyap, Desai4b976502009-08-05 12:52:03 +053076#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020077MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070080MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081
Christoph Hellwig0c33b272005-09-09 16:27:19 +020082static int mpt_pt_clear;
83module_param(mpt_pt_clear, int, 0);
84MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060085 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020086 "(default=MPTSCSIH_PT_CLEAR=0)");
87
Eric Moore793955f2007-01-29 09:42:20 -070088/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
89#define MPTSAS_MAX_LUN (16895)
90static int max_lun = MPTSAS_MAX_LUN;
91module_param(max_lun, int, 0);
92MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
93
Prakash, Sathyaf606f572007-08-14 16:12:53 +053094static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
97static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053098static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020099
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530100static void mptsas_firmware_event_work(struct work_struct *work);
101static void mptsas_send_sas_event(struct fw_event_work *fw_event);
102static void mptsas_send_raid_event(struct fw_event_work *fw_event);
103static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
104static void mptsas_parse_device_info(struct sas_identify *identify,
105 struct mptsas_devinfo *device_info);
106static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
107 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
108static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
109 (MPT_ADAPTER *ioc, u64 sas_address);
110static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
112static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
113 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
114static int mptsas_add_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
116static void mptsas_del_end_device(MPT_ADAPTER *ioc,
117 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530118static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
119static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
120 (MPT_ADAPTER *ioc, u64 sas_address);
121static void mptsas_expander_delete(MPT_ADAPTER *ioc,
122 struct mptsas_portinfo *port_info, u8 force);
123static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530124static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
125static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530126static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530127static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530128static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200129
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530130static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
131 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200132{
Eric Moore29dd3602007-09-14 18:46:51 -0600133 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
134 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
136 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
138 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
139 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
140 ioc->name, phy_data->Port));
141 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
142 ioc->name, phy_data->PortFlags));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
144 ioc->name, phy_data->PhyFlags));
145 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
146 ioc->name, phy_data->NegotiatedLinkRate));
147 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
148 "Controller PHY Device Info=0x%X\n", ioc->name,
149 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
150 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
151 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200152}
153
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530154static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200155{
156 __le64 sas_address;
157
158 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
159
Eric Moore29dd3602007-09-14 18:46:51 -0600160 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
161 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163 "Attached Device Handle=0x%X\n", ioc->name,
164 le16_to_cpu(pg0->AttachedDevHandle)));
165 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
166 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
167 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
168 "Attached PHY Identifier=0x%X\n", ioc->name,
169 pg0->AttachedPhyIdentifier));
170 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
171 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
172 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
173 ioc->name, pg0->ProgrammedLinkRate));
174 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
175 ioc->name, pg0->ChangeCount));
176 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
177 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200178}
179
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530180static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200181{
Eric Moore29dd3602007-09-14 18:46:51 -0600182 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
183 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
184 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
185 ioc->name, pg1->InvalidDwordCount));
186 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
187 "Running Disparity Error Count=0x%x\n", ioc->name,
188 pg1->RunningDisparityErrorCount));
189 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
190 "Loss Dword Synch Count=0x%x\n", ioc->name,
191 pg1->LossDwordSynchCount));
192 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
193 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
194 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200195}
196
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530197static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200198{
199 __le64 sas_address;
200
201 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
202
Eric Moore29dd3602007-09-14 18:46:51 -0600203 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
204 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
206 ioc->name, le16_to_cpu(pg0->DevHandle)));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
208 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
210 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
212 ioc->name, le16_to_cpu(pg0->Slot)));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
214 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
216 ioc->name, pg0->TargetID));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
218 ioc->name, pg0->Bus));
219 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
220 ioc->name, pg0->PhyNum));
221 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
222 ioc->name, le16_to_cpu(pg0->AccessStatus)));
223 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
224 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
225 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
226 ioc->name, le16_to_cpu(pg0->Flags)));
227 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
228 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200229}
230
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530231static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200232{
Eric Moore29dd3602007-09-14 18:46:51 -0600233 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
234 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
235 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
236 ioc->name, pg1->PhysicalPort));
237 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
238 ioc->name, pg1->PhyIdentifier));
239 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
240 ioc->name, pg1->NegotiatedLinkRate));
241 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
242 ioc->name, pg1->ProgrammedLinkRate));
243 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
244 ioc->name, pg1->HwLinkRate));
245 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
246 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
247 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
248 "Attached Device Handle=0x%X\n\n", ioc->name,
249 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200250}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200251
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530252/* inhibit sas firmware event handling */
253static void
254mptsas_fw_event_off(MPT_ADAPTER *ioc)
255{
256 unsigned long flags;
257
258 spin_lock_irqsave(&ioc->fw_event_lock, flags);
259 ioc->fw_events_off = 1;
260 ioc->sas_discovery_quiesce_io = 0;
261 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
262
263}
264
265/* enable sas firmware event handling */
266static void
267mptsas_fw_event_on(MPT_ADAPTER *ioc)
268{
269 unsigned long flags;
270
271 spin_lock_irqsave(&ioc->fw_event_lock, flags);
272 ioc->fw_events_off = 0;
273 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
274}
275
276/* queue a sas firmware event */
277static void
278mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
279 unsigned long delay)
280{
281 unsigned long flags;
282
283 spin_lock_irqsave(&ioc->fw_event_lock, flags);
284 list_add_tail(&fw_event->list, &ioc->fw_event_list);
285 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
286 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
287 ioc->name, __func__, fw_event));
288 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
289 delay);
290 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
291}
292
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530293/* requeue a sas firmware event */
294static void
295mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
296 unsigned long delay)
297{
298 unsigned long flags;
299 spin_lock_irqsave(&ioc->fw_event_lock, flags);
300 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
301 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
302 fw_event->retries++;
303 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
304 msecs_to_jiffies(delay));
305 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
306}
307
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530308/* free memory assoicated to a sas firmware event */
309static void
310mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
311{
312 unsigned long flags;
313
314 spin_lock_irqsave(&ioc->fw_event_lock, flags);
315 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
316 ioc->name, __func__, fw_event));
317 list_del(&fw_event->list);
318 kfree(fw_event);
319 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
320}
321
322/* walk the firmware event queue, and either stop or wait for
323 * outstanding events to complete */
324static void
325mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
326{
327 struct fw_event_work *fw_event, *next;
328 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530329 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
330
331 /* flush the target_reset_list */
332 if (!list_empty(&hd->target_reset_list)) {
333 list_for_each_entry_safe(target_reset_list, n,
334 &hd->target_reset_list, list) {
335 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
336 "%s: removing target reset for id=%d\n",
337 ioc->name, __func__,
338 target_reset_list->sas_event_data.TargetID));
339 list_del(&target_reset_list->list);
340 kfree(target_reset_list);
341 }
342 }
343
344 if (list_empty(&ioc->fw_event_list) ||
345 !ioc->fw_event_q || in_interrupt())
346 return;
347
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530348 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
349 if (cancel_delayed_work(&fw_event->work))
350 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530351 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530352}
353
354
Christoph Hellwige3094442006-02-16 13:25:36 +0100355static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
356{
357 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
358 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
359}
360
361static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
362{
363 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
364 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
365}
366
Moore, Erice6b2d762006-03-14 09:14:24 -0700367/*
368 * mptsas_find_portinfo_by_handle
369 *
370 * This function should be called with the sas_topology_mutex already held
371 */
372static struct mptsas_portinfo *
373mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
374{
375 struct mptsas_portinfo *port_info, *rc=NULL;
376 int i;
377
378 list_for_each_entry(port_info, &ioc->sas_topology, list)
379 for (i = 0; i < port_info->num_phys; i++)
380 if (port_info->phy_info[i].identify.handle == handle) {
381 rc = port_info;
382 goto out;
383 }
384 out:
385 return rc;
386}
387
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530388/**
389 * mptsas_find_portinfo_by_sas_address -
390 * @ioc: Pointer to MPT_ADAPTER structure
391 * @handle:
392 *
393 * This function should be called with the sas_topology_mutex already held
394 *
395 **/
396static struct mptsas_portinfo *
397mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
398{
399 struct mptsas_portinfo *port_info, *rc = NULL;
400 int i;
401
402 if (sas_address >= ioc->hba_port_sas_addr &&
403 sas_address < (ioc->hba_port_sas_addr +
404 ioc->hba_port_num_phy))
405 return ioc->hba_port_info;
406
407 mutex_lock(&ioc->sas_topology_mutex);
408 list_for_each_entry(port_info, &ioc->sas_topology, list)
409 for (i = 0; i < port_info->num_phys; i++)
410 if (port_info->phy_info[i].identify.sas_address ==
411 sas_address) {
412 rc = port_info;
413 goto out;
414 }
415 out:
416 mutex_unlock(&ioc->sas_topology_mutex);
417 return rc;
418}
419
Moore, Ericbd23e942006-04-17 12:43:04 -0600420/*
421 * Returns true if there is a scsi end device
422 */
423static inline int
424mptsas_is_end_device(struct mptsas_devinfo * attached)
425{
Eric Moore547f9a22006-06-27 14:42:12 -0600426 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600427 (attached->device_info &
428 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
429 ((attached->device_info &
430 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
431 (attached->device_info &
432 MPI_SAS_DEVICE_INFO_STP_TARGET) |
433 (attached->device_info &
434 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
435 return 1;
436 else
437 return 0;
438}
439
Eric Moore547f9a22006-06-27 14:42:12 -0600440/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600441static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530442mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600443{
444 struct mptsas_portinfo *port_info;
445 struct mptsas_phyinfo *phy_info;
446 u8 i;
447
448 if (!port_details)
449 return;
450
451 port_info = port_details->port_info;
452 phy_info = port_info->phy_info;
453
Eric Moore29dd3602007-09-14 18:46:51 -0600454 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700455 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700456 port_details->num_phys, (unsigned long long)
457 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600458
459 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
460 if(phy_info->port_details != port_details)
461 continue;
462 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530463 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600464 phy_info->port_details = NULL;
465 }
466 kfree(port_details);
467}
468
469static inline struct sas_rphy *
470mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
471{
472 if (phy_info->port_details)
473 return phy_info->port_details->rphy;
474 else
475 return NULL;
476}
477
478static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530479mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600480{
481 if (phy_info->port_details) {
482 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600483 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
484 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600485 }
486
Eric Moore547f9a22006-06-27 14:42:12 -0600487 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600488 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
489 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600490 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
491 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600492 }
Eric Moore547f9a22006-06-27 14:42:12 -0600493}
494
495static inline struct sas_port *
496mptsas_get_port(struct mptsas_phyinfo *phy_info)
497{
498 if (phy_info->port_details)
499 return phy_info->port_details->port;
500 else
501 return NULL;
502}
503
504static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530505mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600506{
507 if (phy_info->port_details)
508 phy_info->port_details->port = port;
509
Eric Moore547f9a22006-06-27 14:42:12 -0600510 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600511 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
512 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600513 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
514 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600515 }
Eric Moore547f9a22006-06-27 14:42:12 -0600516}
517
518static inline struct scsi_target *
519mptsas_get_starget(struct mptsas_phyinfo *phy_info)
520{
521 if (phy_info->port_details)
522 return phy_info->port_details->starget;
523 else
524 return NULL;
525}
526
527static inline void
528mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
529starget)
530{
531 if (phy_info->port_details)
532 phy_info->port_details->starget = starget;
533}
534
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530535/**
536 * mptsas_add_device_component -
537 * @ioc: Pointer to MPT_ADAPTER structure
538 * @channel: fw mapped id's
539 * @id:
540 * @sas_address:
541 * @device_info:
542 *
543 **/
544static void
545mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
546 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
547{
548 struct mptsas_device_info *sas_info, *next;
549 struct scsi_device *sdev;
550 struct scsi_target *starget;
551 struct sas_rphy *rphy;
552
553 /*
554 * Delete all matching devices out of the list
555 */
556 mutex_lock(&ioc->sas_device_info_mutex);
557 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
558 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530559 if (!sas_info->is_logical_volume &&
560 (sas_info->sas_address == sas_address ||
561 (sas_info->fw.channel == channel &&
562 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530563 list_del(&sas_info->list);
564 kfree(sas_info);
565 }
566 }
567
568 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
569 if (!sas_info)
570 goto out;
571
572 /*
573 * Set Firmware mapping
574 */
575 sas_info->fw.id = id;
576 sas_info->fw.channel = channel;
577
578 sas_info->sas_address = sas_address;
579 sas_info->device_info = device_info;
580 sas_info->slot = slot;
581 sas_info->enclosure_logical_id = enclosure_logical_id;
582 INIT_LIST_HEAD(&sas_info->list);
583 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
584
585 /*
586 * Set OS mapping
587 */
588 shost_for_each_device(sdev, ioc->sh) {
589 starget = scsi_target(sdev);
590 rphy = dev_to_rphy(starget->dev.parent);
591 if (rphy->identify.sas_address == sas_address) {
592 sas_info->os.id = starget->id;
593 sas_info->os.channel = starget->channel;
594 }
595 }
596
597 out:
598 mutex_unlock(&ioc->sas_device_info_mutex);
599 return;
600}
601
602/**
603 * mptsas_add_device_component_by_fw -
604 * @ioc: Pointer to MPT_ADAPTER structure
605 * @channel: fw mapped id's
606 * @id:
607 *
608 **/
609static void
610mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
611{
612 struct mptsas_devinfo sas_device;
613 struct mptsas_enclosure enclosure_info;
614 int rc;
615
616 rc = mptsas_sas_device_pg0(ioc, &sas_device,
617 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
618 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
619 (channel << 8) + id);
620 if (rc)
621 return;
622
623 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
624 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
625 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
626 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
627 sas_device.handle_enclosure);
628
629 mptsas_add_device_component(ioc, sas_device.channel,
630 sas_device.id, sas_device.sas_address, sas_device.device_info,
631 sas_device.slot, enclosure_info.enclosure_logical_id);
632}
633
634/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000635 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530636 * @ioc: Pointer to MPT_ADAPTER structure
637 * @channel: fw mapped id's
638 * @id:
639 *
640 **/
641static void
642mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
643 struct scsi_target *starget)
644{
645 CONFIGPARMS cfg;
646 ConfigPageHeader_t hdr;
647 dma_addr_t dma_handle;
648 pRaidVolumePage0_t buffer = NULL;
649 int i;
650 RaidPhysDiskPage0_t phys_disk;
651 struct mptsas_device_info *sas_info, *next;
652
653 memset(&cfg, 0 , sizeof(CONFIGPARMS));
654 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
655 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
656 /* assumption that all volumes on channel = 0 */
657 cfg.pageAddr = starget->id;
658 cfg.cfghdr.hdr = &hdr;
659 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530660 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530661
662 if (mpt_config(ioc, &cfg) != 0)
663 goto out;
664
665 if (!hdr.PageLength)
666 goto out;
667
668 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
669 &dma_handle);
670
671 if (!buffer)
672 goto out;
673
674 cfg.physAddr = dma_handle;
675 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
676
677 if (mpt_config(ioc, &cfg) != 0)
678 goto out;
679
680 if (!buffer->NumPhysDisks)
681 goto out;
682
683 /*
684 * Adding entry for hidden components
685 */
686 for (i = 0; i < buffer->NumPhysDisks; i++) {
687
688 if (mpt_raid_phys_disk_pg0(ioc,
689 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
690 continue;
691
692 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
693 phys_disk.PhysDiskID);
694
Kashyap, Desai57e98512009-05-29 16:55:09 +0530695 mutex_lock(&ioc->sas_device_info_mutex);
696 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
697 list) {
698 if (!sas_info->is_logical_volume &&
699 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
700 sas_info->fw.id == phys_disk.PhysDiskID)) {
701 sas_info->is_hidden_raid_component = 1;
702 sas_info->volume_id = starget->id;
703 }
704 }
705 mutex_unlock(&ioc->sas_device_info_mutex);
706
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530707 }
708
709 /*
710 * Delete all matching devices out of the list
711 */
712 mutex_lock(&ioc->sas_device_info_mutex);
713 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
714 list) {
715 if (sas_info->is_logical_volume && sas_info->fw.id ==
716 starget->id) {
717 list_del(&sas_info->list);
718 kfree(sas_info);
719 }
720 }
721
722 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
723 if (sas_info) {
724 sas_info->fw.id = starget->id;
725 sas_info->os.id = starget->id;
726 sas_info->os.channel = starget->channel;
727 sas_info->is_logical_volume = 1;
728 INIT_LIST_HEAD(&sas_info->list);
729 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
730 }
731 mutex_unlock(&ioc->sas_device_info_mutex);
732
733 out:
734 if (buffer)
735 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
736 dma_handle);
737}
738
739/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530740 * mptsas_add_device_component_starget -
741 * @ioc: Pointer to MPT_ADAPTER structure
742 * @starget:
743 *
744 **/
745static void
746mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
747 struct scsi_target *starget)
748{
749 VirtTarget *vtarget;
750 struct sas_rphy *rphy;
751 struct mptsas_phyinfo *phy_info = NULL;
752 struct mptsas_enclosure enclosure_info;
753
754 rphy = dev_to_rphy(starget->dev.parent);
755 vtarget = starget->hostdata;
756 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
757 rphy->identify.sas_address);
758 if (!phy_info)
759 return;
760
761 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
762 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
763 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
764 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
765 phy_info->attached.handle_enclosure);
766
767 mptsas_add_device_component(ioc, phy_info->attached.channel,
768 phy_info->attached.id, phy_info->attached.sas_address,
769 phy_info->attached.device_info,
770 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
771}
772
773/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000774 * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
Kashyap, Desai57e98512009-05-29 16:55:09 +0530775 * @ioc: Pointer to MPT_ADAPTER structure
776 * @channel: os mapped id's
777 * @id:
778 *
779 **/
780static void
781mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
782{
783 struct mptsas_device_info *sas_info, *next;
784
785 /*
786 * Set is_cached flag
787 */
788 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
789 list) {
790 if (sas_info->os.channel == channel && sas_info->os.id == id)
791 sas_info->is_cached = 1;
792 }
793}
794
795/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530796 * mptsas_del_device_components - Cleaning the list
797 * @ioc: Pointer to MPT_ADAPTER structure
798 *
799 **/
800static void
801mptsas_del_device_components(MPT_ADAPTER *ioc)
802{
803 struct mptsas_device_info *sas_info, *next;
804
805 mutex_lock(&ioc->sas_device_info_mutex);
806 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
807 list) {
808 list_del(&sas_info->list);
809 kfree(sas_info);
810 }
811 mutex_unlock(&ioc->sas_device_info_mutex);
812}
813
Eric Moore547f9a22006-06-27 14:42:12 -0600814
815/*
816 * mptsas_setup_wide_ports
817 *
818 * Updates for new and existing narrow/wide port configuration
819 * in the sas_topology
820 */
Eric Moore376ac832006-06-29 17:36:26 -0600821static void
Eric Moore547f9a22006-06-27 14:42:12 -0600822mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
823{
824 struct mptsas_portinfo_details * port_details;
825 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
826 u64 sas_address;
827 int i, j;
828
829 mutex_lock(&ioc->sas_topology_mutex);
830
831 phy_info = port_info->phy_info;
832 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
833 if (phy_info->attached.handle)
834 continue;
835 port_details = phy_info->port_details;
836 if (!port_details)
837 continue;
838 if (port_details->num_phys < 2)
839 continue;
840 /*
841 * Removing a phy from a port, letting the last
842 * phy be removed by firmware events.
843 */
Eric Moore29dd3602007-09-14 18:46:51 -0600844 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
845 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700846 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600847 port_details->num_phys--;
848 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
849 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530850 if (phy_info->phy) {
851 devtprintk(ioc, dev_printk(KERN_DEBUG,
852 &phy_info->phy->dev, MYIOC_s_FMT
853 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
854 phy_info->phy_id, phy_info->phy));
855 sas_port_delete_phy(port_details->port, phy_info->phy);
856 }
Eric Moore547f9a22006-06-27 14:42:12 -0600857 phy_info->port_details = NULL;
858 }
859
860 /*
861 * Populate and refresh the tree
862 */
863 phy_info = port_info->phy_info;
864 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
865 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600866 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
867 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600868 if (!sas_address)
869 continue;
870 port_details = phy_info->port_details;
871 /*
872 * Forming a port
873 */
874 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530875 port_details = kzalloc(sizeof(struct
876 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600877 if (!port_details)
878 goto out;
879 port_details->num_phys = 1;
880 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600881 if (phy_info->phy_id < 64 )
882 port_details->phy_bitmask |=
883 (1 << phy_info->phy_id);
884 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600885 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700886 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600887 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600888 phy_info->port_details = port_details;
889 }
890
891 if (i == port_info->num_phys - 1)
892 continue;
893 phy_info_cmp = &port_info->phy_info[i + 1];
894 for (j = i + 1 ; j < port_info->num_phys ; j++,
895 phy_info_cmp++) {
896 if (!phy_info_cmp->attached.sas_address)
897 continue;
898 if (sas_address != phy_info_cmp->attached.sas_address)
899 continue;
900 if (phy_info_cmp->port_details == port_details )
901 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600902 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700903 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600904 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700905 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600906 if (phy_info_cmp->port_details) {
907 port_details->rphy =
908 mptsas_get_rphy(phy_info_cmp);
909 port_details->port =
910 mptsas_get_port(phy_info_cmp);
911 port_details->starget =
912 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600913 port_details->num_phys =
914 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600915 if (!phy_info_cmp->port_details->num_phys)
916 kfree(phy_info_cmp->port_details);
917 } else
918 phy_info_cmp->sas_port_add_phy=1;
919 /*
920 * Adding a phy to a port
921 */
922 phy_info_cmp->port_details = port_details;
923 if (phy_info_cmp->phy_id < 64 )
924 port_details->phy_bitmask |=
925 (1 << phy_info_cmp->phy_id);
926 port_details->num_phys++;
927 }
928 }
929
930 out:
931
Eric Moore547f9a22006-06-27 14:42:12 -0600932 for (i = 0; i < port_info->num_phys; i++) {
933 port_details = port_info->phy_info[i].port_details;
934 if (!port_details)
935 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600936 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700937 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700938 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700939 port_details, i, port_details->num_phys,
940 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600941 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
942 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600943 }
Eric Moore29dd3602007-09-14 18:46:51 -0600944 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600945 mutex_unlock(&ioc->sas_topology_mutex);
946}
947
Eric Mooredf9e0622007-01-29 09:46:21 -0700948/**
949 * csmisas_find_vtarget
950 *
951 * @ioc
952 * @volume_id
953 * @volume_bus
954 *
955 **/
956static VirtTarget *
957mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600958{
Eric Mooredf9e0622007-01-29 09:46:21 -0700959 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600960 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700961 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600962
Eric Mooredf9e0622007-01-29 09:46:21 -0700963 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530964 vdevice = sdev->hostdata;
965 if ((vdevice == NULL) ||
966 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700967 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530968 if ((vdevice->vtarget->tflags &
969 MPT_TARGET_FLAGS_RAID_COMPONENT ||
970 vdevice->vtarget->raidVolume))
971 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600972 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530973 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600974 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600975 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700976 return vtarget;
977}
978
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530979static void
980mptsas_queue_device_delete(MPT_ADAPTER *ioc,
981 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
982{
983 struct fw_event_work *fw_event;
984 int sz;
985
986 sz = offsetof(struct fw_event_work, event_data) +
987 sizeof(MpiEventDataSasDeviceStatusChange_t);
988 fw_event = kzalloc(sz, GFP_ATOMIC);
989 if (!fw_event) {
990 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
991 ioc->name, __func__, __LINE__);
992 return;
993 }
994 memcpy(fw_event->event_data, sas_event_data,
995 sizeof(MpiEventDataSasDeviceStatusChange_t));
996 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
997 fw_event->ioc = ioc;
998 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
999}
1000
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301001static void
1002mptsas_queue_rescan(MPT_ADAPTER *ioc)
1003{
1004 struct fw_event_work *fw_event;
1005 int sz;
1006
1007 sz = offsetof(struct fw_event_work, event_data);
1008 fw_event = kzalloc(sz, GFP_ATOMIC);
1009 if (!fw_event) {
1010 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1011 ioc->name, __func__, __LINE__);
1012 return;
1013 }
1014 fw_event->event = -1;
1015 fw_event->ioc = ioc;
1016 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1017}
1018
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301019
Eric Mooredf9e0622007-01-29 09:46:21 -07001020/**
1021 * mptsas_target_reset
1022 *
1023 * Issues TARGET_RESET to end device using handshaking method
1024 *
1025 * @ioc
1026 * @channel
1027 * @id
1028 *
1029 * Returns (1) success
1030 * (0) failure
1031 *
1032 **/
1033static int
1034mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1035{
1036 MPT_FRAME_HDR *mf;
1037 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301038 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1039 return 0;
1040
Eric Mooredf9e0622007-01-29 09:46:21 -07001041
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301042 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1043 if (mf == NULL) {
1044 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301045 "%s, no msg frames @%d!!\n", ioc->name,
1046 __func__, __LINE__));
1047 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001048 }
1049
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301050 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1051 ioc->name, mf));
1052
Eric Mooredf9e0622007-01-29 09:46:21 -07001053 /* Format the Request
1054 */
1055 pScsiTm = (SCSITaskMgmt_t *) mf;
1056 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1057 pScsiTm->TargetID = id;
1058 pScsiTm->Bus = channel;
1059 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1060 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1061 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1062
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301063 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001064
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301065 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1066 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1067 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1068
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301069 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001070
1071 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301072
1073 out_fail:
1074
1075 mpt_clear_taskmgmt_in_progress_flag(ioc);
1076 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001077}
1078
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301079static void
1080mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1081{
1082 scsi_device_set_state(sdev, SDEV_BLOCK);
1083}
1084
1085static void
1086mptsas_block_io_starget(struct scsi_target *starget)
1087{
1088 if (starget)
1089 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1090}
1091
Eric Mooredf9e0622007-01-29 09:46:21 -07001092/**
1093 * mptsas_target_reset_queue
1094 *
1095 * Receive request for TARGET_RESET after recieving an firmware
1096 * event NOT_RESPONDING_EVENT, then put command in link list
1097 * and queue if task_queue already in use.
1098 *
1099 * @ioc
1100 * @sas_event_data
1101 *
1102 **/
1103static void
1104mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1105 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1106{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001107 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001108 VirtTarget *vtarget = NULL;
1109 struct mptsas_target_reset_event *target_reset_list;
1110 u8 id, channel;
1111
1112 id = sas_event_data->TargetID;
1113 channel = sas_event_data->Bus;
1114
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301115 vtarget = mptsas_find_vtarget(ioc, channel, id);
1116 if (vtarget) {
1117 mptsas_block_io_starget(vtarget->starget);
1118 vtarget->deleted = 1; /* block IO */
1119 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001120
Kashyap, Desai2f187862009-05-29 16:52:37 +05301121 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001122 GFP_ATOMIC);
1123 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301124 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1125 "%s, failed to allocate mem @%d..!!\n",
1126 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001127 return;
1128 }
1129
1130 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1131 sizeof(*sas_event_data));
1132 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1133
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301134 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001135
1136 if (mptsas_target_reset(ioc, channel, id)) {
1137 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001138 }
1139}
1140
1141/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001142 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301143 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001144 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001145 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1146 * queue to finish off removing device from upper layers. then send next
1147 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001148 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301149static int
1150mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001151{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001152 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001153 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001154 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301155 struct mptsas_target_reset_event *target_reset_list;
1156 SCSITaskMgmtReply_t *pScsiTmReply;
1157
1158 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1159 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1160
1161 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1162 if (pScsiTmReply) {
1163 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1164 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1165 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1166 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1167 "term_cmnds = %d\n", ioc->name,
1168 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1169 pScsiTmReply->TaskType,
1170 le16_to_cpu(pScsiTmReply->IOCStatus),
1171 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1172 pScsiTmReply->ResponseCode,
1173 le32_to_cpu(pScsiTmReply->TerminationCount)));
1174
1175 if (pScsiTmReply->ResponseCode)
1176 mptscsih_taskmgmt_response_code(ioc,
1177 pScsiTmReply->ResponseCode);
1178 }
1179
1180 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1181 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1182 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1183 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1184 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1185 memcpy(ioc->taskmgmt_cmds.reply, mr,
1186 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1187 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1188 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1189 complete(&ioc->taskmgmt_cmds.done);
1190 return 1;
1191 }
1192 return 0;
1193 }
1194
1195 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001196
1197 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301198 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001199
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301200 target_reset_list = list_entry(head->next,
1201 struct mptsas_target_reset_event, list);
1202
1203 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1204 "TaskMgmt: completed (%d seconds)\n",
1205 ioc->name, jiffies_to_msecs(jiffies -
1206 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001207
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301208 id = pScsiTmReply->TargetID;
1209 channel = pScsiTmReply->Bus;
1210 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001211
1212 /*
1213 * retry target reset
1214 */
1215 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301216 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001217 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301218 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001219 }
1220
1221 /*
1222 * enable work queue to remove device from upper layers
1223 */
1224 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301225 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1226 mptsas_queue_device_delete(ioc,
1227 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301228
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301229
Eric Mooredf9e0622007-01-29 09:46:21 -07001230 /*
1231 * issue target reset to next device in the queue
1232 */
1233
1234 head = &hd->target_reset_list;
1235 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301236 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001237
1238 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1239 list);
1240
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301241 id = target_reset_list->sas_event_data.TargetID;
1242 channel = target_reset_list->sas_event_data.Bus;
1243 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001244
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301245 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001246 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001247
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301248 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001249}
1250
1251/**
1252 * mptscsih_ioc_reset
1253 *
1254 * @ioc
1255 * @reset_phase
1256 *
1257 **/
1258static int
1259mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1260{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001261 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001262 int rc;
1263
1264 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301265 if ((ioc->bus_type != SAS) || (!rc))
1266 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001267
Eric Mooree7eae9f2007-09-29 10:15:59 -06001268 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001269 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001270 goto out;
1271
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301272 switch (reset_phase) {
1273 case MPT_IOC_SETUP_RESET:
1274 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1275 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1276 mptsas_fw_event_off(ioc);
1277 break;
1278 case MPT_IOC_PRE_RESET:
1279 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1280 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1281 break;
1282 case MPT_IOC_POST_RESET:
1283 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1284 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1285 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1286 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1287 complete(&ioc->sas_mgmt.done);
1288 }
1289 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301290 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301291 break;
1292 default:
1293 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001294 }
1295
1296 out:
1297 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001298}
1299
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301300
1301/**
1302 * enum device_state -
1303 * @DEVICE_RETRY: need to retry the TUR
1304 * @DEVICE_ERROR: TUR return error, don't add device
1305 * @DEVICE_READY: device can be added
1306 *
1307 */
1308enum device_state{
1309 DEVICE_RETRY,
1310 DEVICE_ERROR,
1311 DEVICE_READY,
1312};
1313
Christoph Hellwige3094442006-02-16 13:25:36 +01001314static int
Moore, Eric52435432006-03-14 09:14:15 -07001315mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001316 u32 form, u32 form_specific)
1317{
1318 ConfigExtendedPageHeader_t hdr;
1319 CONFIGPARMS cfg;
1320 SasEnclosurePage0_t *buffer;
1321 dma_addr_t dma_handle;
1322 int error;
1323 __le64 le_identifier;
1324
1325 memset(&hdr, 0, sizeof(hdr));
1326 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1327 hdr.PageNumber = 0;
1328 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1329 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1330
1331 cfg.cfghdr.ehdr = &hdr;
1332 cfg.physAddr = -1;
1333 cfg.pageAddr = form + form_specific;
1334 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1335 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301336 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001337
1338 error = mpt_config(ioc, &cfg);
1339 if (error)
1340 goto out;
1341 if (!hdr.ExtPageLength) {
1342 error = -ENXIO;
1343 goto out;
1344 }
1345
1346 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1347 &dma_handle);
1348 if (!buffer) {
1349 error = -ENOMEM;
1350 goto out;
1351 }
1352
1353 cfg.physAddr = dma_handle;
1354 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1355
1356 error = mpt_config(ioc, &cfg);
1357 if (error)
1358 goto out_free_consistent;
1359
1360 /* save config data */
1361 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1362 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1363 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1364 enclosure->flags = le16_to_cpu(buffer->Flags);
1365 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1366 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1367 enclosure->start_id = buffer->StartTargetID;
1368 enclosure->start_channel = buffer->StartBus;
1369 enclosure->sep_id = buffer->SEPTargetID;
1370 enclosure->sep_channel = buffer->SEPBus;
1371
1372 out_free_consistent:
1373 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1374 buffer, dma_handle);
1375 out:
1376 return error;
1377}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001378
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301379/**
1380 * mptsas_add_end_device - report a new end device to sas transport layer
1381 * @ioc: Pointer to MPT_ADAPTER structure
1382 * @phy_info: decribes attached device
1383 *
1384 * return (0) success (1) failure
1385 *
1386 **/
1387static int
1388mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1389{
1390 struct sas_rphy *rphy;
1391 struct sas_port *port;
1392 struct sas_identify identify;
1393 char *ds = NULL;
1394 u8 fw_id;
1395
1396 if (!phy_info) {
1397 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1398 "%s: exit at line=%d\n", ioc->name,
1399 __func__, __LINE__));
1400 return 1;
1401 }
1402
1403 fw_id = phy_info->attached.id;
1404
1405 if (mptsas_get_rphy(phy_info)) {
1406 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1407 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1408 __func__, fw_id, __LINE__));
1409 return 2;
1410 }
1411
1412 port = mptsas_get_port(phy_info);
1413 if (!port) {
1414 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1415 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1416 __func__, fw_id, __LINE__));
1417 return 3;
1418 }
1419
1420 if (phy_info->attached.device_info &
1421 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1422 ds = "ssp";
1423 if (phy_info->attached.device_info &
1424 MPI_SAS_DEVICE_INFO_STP_TARGET)
1425 ds = "stp";
1426 if (phy_info->attached.device_info &
1427 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1428 ds = "sata";
1429
1430 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1431 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1432 phy_info->attached.channel, phy_info->attached.id,
1433 phy_info->attached.phy_id, (unsigned long long)
1434 phy_info->attached.sas_address);
1435
1436 mptsas_parse_device_info(&identify, &phy_info->attached);
1437 rphy = sas_end_device_alloc(port);
1438 if (!rphy) {
1439 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1440 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1441 __func__, fw_id, __LINE__));
1442 return 5; /* non-fatal: an rphy can be added later */
1443 }
1444
1445 rphy->identify = identify;
1446 if (sas_rphy_add(rphy)) {
1447 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1448 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1449 __func__, fw_id, __LINE__));
1450 sas_rphy_free(rphy);
1451 return 6;
1452 }
1453 mptsas_set_rphy(ioc, phy_info, rphy);
1454 return 0;
1455}
1456
1457/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001458 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301459 * @ioc: Pointer to MPT_ADAPTER structure
1460 * @phy_info: decribes attached device
1461 *
1462 **/
1463static void
1464mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1465{
1466 struct sas_rphy *rphy;
1467 struct sas_port *port;
1468 struct mptsas_portinfo *port_info;
1469 struct mptsas_phyinfo *phy_info_parent;
1470 int i;
1471 char *ds = NULL;
1472 u8 fw_id;
1473 u64 sas_address;
1474
1475 if (!phy_info)
1476 return;
1477
1478 fw_id = phy_info->attached.id;
1479 sas_address = phy_info->attached.sas_address;
1480
1481 if (!phy_info->port_details) {
1482 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1483 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1484 __func__, fw_id, __LINE__));
1485 return;
1486 }
1487 rphy = mptsas_get_rphy(phy_info);
1488 if (!rphy) {
1489 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1490 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1491 __func__, fw_id, __LINE__));
1492 return;
1493 }
1494
1495 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1496 || phy_info->attached.device_info
1497 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1498 || phy_info->attached.device_info
1499 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1500 ds = "initiator";
1501 if (phy_info->attached.device_info &
1502 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1503 ds = "ssp";
1504 if (phy_info->attached.device_info &
1505 MPI_SAS_DEVICE_INFO_STP_TARGET)
1506 ds = "stp";
1507 if (phy_info->attached.device_info &
1508 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1509 ds = "sata";
1510
1511 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1512 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1513 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1514 phy_info->attached.id, phy_info->attached.phy_id,
1515 (unsigned long long) sas_address);
1516
1517 port = mptsas_get_port(phy_info);
1518 if (!port) {
1519 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1520 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1521 __func__, fw_id, __LINE__));
1522 return;
1523 }
1524 port_info = phy_info->portinfo;
1525 phy_info_parent = port_info->phy_info;
1526 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1527 if (!phy_info_parent->phy)
1528 continue;
1529 if (phy_info_parent->attached.sas_address !=
1530 sas_address)
1531 continue;
1532 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1533 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1534 ioc->name, phy_info_parent->phy_id,
1535 phy_info_parent->phy);
1536 sas_port_delete_phy(port, phy_info_parent->phy);
1537 }
1538
1539 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1540 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1541 port->port_identifier, (unsigned long long)sas_address);
1542 sas_port_delete(port);
1543 mptsas_set_port(ioc, phy_info, NULL);
1544 mptsas_port_delete(ioc, phy_info->port_details);
1545}
1546
1547struct mptsas_phyinfo *
1548mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1549 struct mptsas_devinfo *sas_device)
1550{
1551 struct mptsas_phyinfo *phy_info;
1552 struct mptsas_portinfo *port_info;
1553 int i;
1554
1555 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1556 sas_device->sas_address);
1557 if (!phy_info)
1558 goto out;
1559 port_info = phy_info->portinfo;
1560 if (!port_info)
1561 goto out;
1562 mutex_lock(&ioc->sas_topology_mutex);
1563 for (i = 0; i < port_info->num_phys; i++) {
1564 if (port_info->phy_info[i].attached.sas_address !=
1565 sas_device->sas_address)
1566 continue;
1567 port_info->phy_info[i].attached.channel = sas_device->channel;
1568 port_info->phy_info[i].attached.id = sas_device->id;
1569 port_info->phy_info[i].attached.sas_address =
1570 sas_device->sas_address;
1571 port_info->phy_info[i].attached.handle = sas_device->handle;
1572 port_info->phy_info[i].attached.handle_parent =
1573 sas_device->handle_parent;
1574 port_info->phy_info[i].attached.handle_enclosure =
1575 sas_device->handle_enclosure;
1576 }
1577 mutex_unlock(&ioc->sas_topology_mutex);
1578 out:
1579 return phy_info;
1580}
1581
1582/**
1583 * mptsas_firmware_event_work - work thread for processing fw events
1584 * @work: work queue payload containing info describing the event
1585 * Context: user
1586 *
1587 */
1588static void
1589mptsas_firmware_event_work(struct work_struct *work)
1590{
1591 struct fw_event_work *fw_event =
1592 container_of(work, struct fw_event_work, work.work);
1593 MPT_ADAPTER *ioc = fw_event->ioc;
1594
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301595 /* special rescan topology handling */
1596 if (fw_event->event == -1) {
1597 if (ioc->in_rescan) {
1598 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1599 "%s: rescan ignored as it is in progress\n",
1600 ioc->name, __func__));
1601 return;
1602 }
1603 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1604 "reset\n", ioc->name, __func__));
1605 ioc->in_rescan = 1;
1606 mptsas_not_responding_devices(ioc);
1607 mptsas_scan_sas_topology(ioc);
1608 ioc->in_rescan = 0;
1609 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301610 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301611 return;
1612 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301613
1614 /* events handling turned off during host reset */
1615 if (ioc->fw_events_off) {
1616 mptsas_free_fw_event(ioc, fw_event);
1617 return;
1618 }
1619
1620 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1621 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1622 (fw_event->event & 0xFF)));
1623
1624 switch (fw_event->event) {
1625 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1626 mptsas_send_sas_event(fw_event);
1627 break;
1628 case MPI_EVENT_INTEGRATED_RAID:
1629 mptsas_send_raid_event(fw_event);
1630 break;
1631 case MPI_EVENT_IR2:
1632 mptsas_send_ir2_event(fw_event);
1633 break;
1634 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1635 mptbase_sas_persist_operation(ioc,
1636 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1637 mptsas_free_fw_event(ioc, fw_event);
1638 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301639 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1640 mptsas_broadcast_primative_work(fw_event);
1641 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301642 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1643 mptsas_send_expander_event(fw_event);
1644 break;
1645 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1646 mptsas_send_link_status_event(fw_event);
1647 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301648 case MPI_EVENT_QUEUE_FULL:
1649 mptsas_handle_queue_full_event(fw_event);
1650 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301651 }
1652}
1653
1654
1655
James Bottomleyf013db32006-03-18 14:54:36 -06001656static int
1657mptsas_slave_configure(struct scsi_device *sdev)
1658{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301659 struct Scsi_Host *host = sdev->host;
1660 MPT_SCSI_HOST *hd = shost_priv(host);
1661 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301662 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001663
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301664 if (vdevice->vtarget->deleted) {
1665 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1666 vdevice->vtarget->deleted = 0;
1667 }
1668
1669 /*
1670 * RAID volumes placed beyond the last expected port.
1671 * Ignore sending sas mode pages in that case..
1672 */
1673 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1674 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001675 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301676 }
James Bottomleyf013db32006-03-18 14:54:36 -06001677
James Bottomleye8bf3942006-07-11 17:49:34 -04001678 sas_read_port_mode_page(sdev);
1679
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301680 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1681
James Bottomleye8bf3942006-07-11 17:49:34 -04001682 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001683 return mptscsih_slave_configure(sdev);
1684}
1685
Eric Moore547f9a22006-06-27 14:42:12 -06001686static int
1687mptsas_target_alloc(struct scsi_target *starget)
1688{
1689 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001690 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001691 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001692 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001693 struct sas_rphy *rphy;
1694 struct mptsas_portinfo *p;
1695 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001696 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001697
1698 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1699 if (!vtarget)
1700 return -ENOMEM;
1701
1702 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001703 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001704 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1705 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001706 channel = 0;
1707
Eric Moore793955f2007-01-29 09:42:20 -07001708 /*
1709 * RAID volumes placed beyond the last expected port.
1710 */
1711 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301712 if (!ioc->raid_data.pIocPg2) {
1713 kfree(vtarget);
1714 return -ENXIO;
1715 }
1716 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1717 if (id == ioc->raid_data.pIocPg2->
1718 RaidVolume[i].VolumeID) {
1719 channel = ioc->raid_data.pIocPg2->
1720 RaidVolume[i].VolumeBus;
1721 }
1722 }
1723 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001724 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001725 }
Eric Moore547f9a22006-06-27 14:42:12 -06001726
1727 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001728 mutex_lock(&ioc->sas_topology_mutex);
1729 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001730 for (i = 0; i < p->num_phys; i++) {
1731 if (p->phy_info[i].attached.sas_address !=
1732 rphy->identify.sas_address)
1733 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001734 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001735 channel = p->phy_info[i].attached.channel;
1736 mptsas_set_starget(&p->phy_info[i], starget);
1737
1738 /*
1739 * Exposing hidden raid components
1740 */
Eric Mooree80b0022007-09-14 18:49:03 -06001741 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1742 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001743 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001744 vtarget->tflags |=
1745 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001746 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001747 }
Eric Mooree80b0022007-09-14 18:49:03 -06001748 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001749 goto out;
1750 }
1751 }
Eric Mooree80b0022007-09-14 18:49:03 -06001752 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001753
1754 kfree(vtarget);
1755 return -ENXIO;
1756
1757 out:
Eric Moore793955f2007-01-29 09:42:20 -07001758 vtarget->id = id;
1759 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001760 starget->hostdata = vtarget;
1761 return 0;
1762}
1763
1764static void
1765mptsas_target_destroy(struct scsi_target *starget)
1766{
1767 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001768 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001769 struct sas_rphy *rphy;
1770 struct mptsas_portinfo *p;
1771 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301772 MPT_ADAPTER *ioc = hd->ioc;
1773 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001774
1775 if (!starget->hostdata)
1776 return;
1777
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301778 vtarget = starget->hostdata;
1779
Kashyap, Desai57e98512009-05-29 16:55:09 +05301780 mptsas_del_device_component_by_os(ioc, starget->channel,
1781 starget->id);
1782
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301783
James Bottomleye8bf3942006-07-11 17:49:34 -04001784 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001785 goto out;
1786
1787 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001788 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001789 for (i = 0; i < p->num_phys; i++) {
1790 if (p->phy_info[i].attached.sas_address !=
1791 rphy->identify.sas_address)
1792 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301793
1794 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1795 "delete device: fw_channel %d, fw_id %d, phy %d, "
1796 "sas_addr 0x%llx\n", ioc->name,
1797 p->phy_info[i].attached.channel,
1798 p->phy_info[i].attached.id,
1799 p->phy_info[i].attached.phy_id, (unsigned long long)
1800 p->phy_info[i].attached.sas_address);
1801
Eric Moore547f9a22006-06-27 14:42:12 -06001802 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001803 }
1804 }
1805
1806 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301807 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001808 kfree(starget->hostdata);
1809 starget->hostdata = NULL;
1810}
1811
1812
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001813static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001814mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001815{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001816 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001817 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001818 struct sas_rphy *rphy;
1819 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001820 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001821 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001822 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001823 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
Eric Moorea69de502007-09-14 18:48:19 -06001825 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1826 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001827 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001828 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001829 return -ENOMEM;
1830 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001831 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001832 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001833
James Bottomleye8bf3942006-07-11 17:49:34 -04001834 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001835 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001836
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001837 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001838 mutex_lock(&ioc->sas_topology_mutex);
1839 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001841 if (p->phy_info[i].attached.sas_address !=
1842 rphy->identify.sas_address)
1843 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001844 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001845 /*
1846 * Exposing hidden raid components
1847 */
Eric Mooree80b0022007-09-14 18:49:03 -06001848 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001849 p->phy_info[i].attached.channel,
1850 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001851 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001852 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001853 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001854 }
1855 }
Eric Mooree80b0022007-09-14 18:49:03 -06001856 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001857
Eric Moorea69de502007-09-14 18:48:19 -06001858 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001859 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001860
1861 out:
Eric Moorea69de502007-09-14 18:48:19 -06001862 vdevice->vtarget->num_luns++;
1863 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001864 return 0;
1865}
1866
Eric Moore547f9a22006-06-27 14:42:12 -06001867static int
1868mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001869{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301870 MPT_SCSI_HOST *hd;
1871 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001872 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001873
Eric Moorea69de502007-09-14 18:48:19 -06001874 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001875 SCpnt->result = DID_NO_CONNECT << 16;
1876 done(SCpnt);
1877 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001878 }
Eric Moore547f9a22006-06-27 14:42:12 -06001879
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301880 hd = shost_priv(SCpnt->device->host);
1881 ioc = hd->ioc;
1882
1883 if (ioc->sas_discovery_quiesce_io)
1884 return SCSI_MLQUEUE_HOST_BUSY;
1885
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301886 if (ioc->debug_level & MPT_DEBUG_SCSI)
1887 scsi_print_command(SCpnt);
Eric Moore793955f2007-01-29 09:42:20 -07001888
Eric Moore547f9a22006-06-27 14:42:12 -06001889 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001890}
1891
Eric Moore547f9a22006-06-27 14:42:12 -06001892
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001893static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001894 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001895 .proc_name = "mptsas",
1896 .proc_info = mptscsih_proc_info,
Kashyap, Desai568da762010-03-18 19:23:50 +05301897 .name = "MPT SAS Host",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001898 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001899 .queuecommand = mptsas_qcmd,
1900 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001901 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001902 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001903 .target_destroy = mptsas_target_destroy,
1904 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001905 .change_queue_depth = mptscsih_change_queue_depth,
1906 .eh_abort_handler = mptscsih_abort,
1907 .eh_device_reset_handler = mptscsih_dev_reset,
1908 .eh_bus_reset_handler = mptscsih_bus_reset,
1909 .eh_host_reset_handler = mptscsih_host_reset,
1910 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301911 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001912 .this_id = -1,
1913 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1914 .max_sectors = 8192,
1915 .cmd_per_lun = 7,
1916 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301917 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001918};
1919
Christoph Hellwigb5141122005-10-28 22:07:41 +02001920static int mptsas_get_linkerrors(struct sas_phy *phy)
1921{
1922 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1923 ConfigExtendedPageHeader_t hdr;
1924 CONFIGPARMS cfg;
1925 SasPhyPage1_t *buffer;
1926 dma_addr_t dma_handle;
1927 int error;
1928
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001929 /* FIXME: only have link errors on local phys */
1930 if (!scsi_is_sas_phy_local(phy))
1931 return -EINVAL;
1932
Christoph Hellwigb5141122005-10-28 22:07:41 +02001933 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1934 hdr.ExtPageLength = 0;
1935 hdr.PageNumber = 1 /* page number 1*/;
1936 hdr.Reserved1 = 0;
1937 hdr.Reserved2 = 0;
1938 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1939 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1940
1941 cfg.cfghdr.ehdr = &hdr;
1942 cfg.physAddr = -1;
1943 cfg.pageAddr = phy->identify.phy_identifier;
1944 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1945 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301946 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02001947
1948 error = mpt_config(ioc, &cfg);
1949 if (error)
1950 return error;
1951 if (!hdr.ExtPageLength)
1952 return -ENXIO;
1953
1954 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1955 &dma_handle);
1956 if (!buffer)
1957 return -ENOMEM;
1958
1959 cfg.physAddr = dma_handle;
1960 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1961
1962 error = mpt_config(ioc, &cfg);
1963 if (error)
1964 goto out_free_consistent;
1965
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301966 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001967
1968 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1969 phy->running_disparity_error_count =
1970 le32_to_cpu(buffer->RunningDisparityErrorCount);
1971 phy->loss_of_dword_sync_count =
1972 le32_to_cpu(buffer->LossDwordSynchCount);
1973 phy->phy_reset_problem_count =
1974 le32_to_cpu(buffer->PhyResetProblemCount);
1975
1976 out_free_consistent:
1977 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1978 buffer, dma_handle);
1979 return error;
1980}
1981
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001982static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1983 MPT_FRAME_HDR *reply)
1984{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301985 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001986 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301987 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001988 memcpy(ioc->sas_mgmt.reply, reply,
1989 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1990 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301991
1992 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1993 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1994 complete(&ioc->sas_mgmt.done);
1995 return 1;
1996 }
1997 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001998}
1999
2000static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2001{
2002 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2003 SasIoUnitControlRequest_t *req;
2004 SasIoUnitControlReply_t *reply;
2005 MPT_FRAME_HDR *mf;
2006 MPIHeader_t *hdr;
2007 unsigned long timeleft;
2008 int error = -ERESTARTSYS;
2009
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002010 /* FIXME: fusion doesn't allow non-local phy reset */
2011 if (!scsi_is_sas_phy_local(phy))
2012 return -EINVAL;
2013
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002014 /* not implemented for expanders */
2015 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2016 return -ENXIO;
2017
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002018 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002019 goto out;
2020
2021 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2022 if (!mf) {
2023 error = -ENOMEM;
2024 goto out_unlock;
2025 }
2026
2027 hdr = (MPIHeader_t *) mf;
2028 req = (SasIoUnitControlRequest_t *)mf;
2029 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2030 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2031 req->MsgContext = hdr->MsgContext;
2032 req->Operation = hard_reset ?
2033 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2034 req->PhyNum = phy->identify.phy_identifier;
2035
Kashyap, Desai2f187862009-05-29 16:52:37 +05302036 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002037 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2038
2039 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2040 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302041 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2042 error = -ETIME;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002043 mpt_free_msg_frame(ioc, mf);
Kashyap, Desai568da762010-03-18 19:23:50 +05302044 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2045 goto out_unlock;
2046 if (!timeleft)
2047 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002048 goto out_unlock;
2049 }
2050
2051 /* a reply frame is expected */
2052 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302053 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002054 error = -ENXIO;
2055 goto out_unlock;
2056 }
2057
2058 /* process the completed Reply Message Frame */
2059 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2060 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002061 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002062 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002063 error = -ENXIO;
2064 goto out_unlock;
2065 }
2066
2067 error = 0;
2068
2069 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302070 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002071 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002072 out:
2073 return error;
2074}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002075
Christoph Hellwige3094442006-02-16 13:25:36 +01002076static int
2077mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2078{
2079 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2080 int i, error;
2081 struct mptsas_portinfo *p;
2082 struct mptsas_enclosure enclosure_info;
2083 u64 enclosure_handle;
2084
2085 mutex_lock(&ioc->sas_topology_mutex);
2086 list_for_each_entry(p, &ioc->sas_topology, list) {
2087 for (i = 0; i < p->num_phys; i++) {
2088 if (p->phy_info[i].attached.sas_address ==
2089 rphy->identify.sas_address) {
2090 enclosure_handle = p->phy_info[i].
2091 attached.handle_enclosure;
2092 goto found_info;
2093 }
2094 }
2095 }
2096 mutex_unlock(&ioc->sas_topology_mutex);
2097 return -ENXIO;
2098
2099 found_info:
2100 mutex_unlock(&ioc->sas_topology_mutex);
2101 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002102 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002103 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2104 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2105 if (!error)
2106 *identifier = enclosure_info.enclosure_logical_id;
2107 return error;
2108}
2109
2110static int
2111mptsas_get_bay_identifier(struct sas_rphy *rphy)
2112{
2113 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2114 struct mptsas_portinfo *p;
2115 int i, rc;
2116
2117 mutex_lock(&ioc->sas_topology_mutex);
2118 list_for_each_entry(p, &ioc->sas_topology, list) {
2119 for (i = 0; i < p->num_phys; i++) {
2120 if (p->phy_info[i].attached.sas_address ==
2121 rphy->identify.sas_address) {
2122 rc = p->phy_info[i].attached.slot;
2123 goto out;
2124 }
2125 }
2126 }
2127 rc = -ENXIO;
2128 out:
2129 mutex_unlock(&ioc->sas_topology_mutex);
2130 return rc;
2131}
2132
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002133static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2134 struct request *req)
2135{
2136 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2137 MPT_FRAME_HDR *mf;
2138 SmpPassthroughRequest_t *smpreq;
2139 struct request *rsp = req->next_rq;
2140 int ret;
2141 int flagsLength;
2142 unsigned long timeleft;
2143 char *psge;
2144 dma_addr_t dma_addr_in = 0;
2145 dma_addr_t dma_addr_out = 0;
2146 u64 sas_address = 0;
2147
2148 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002149 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002150 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002151 return -EINVAL;
2152 }
2153
2154 /* do we need to support multiple segments? */
2155 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002156 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002157 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2158 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002159 return -EINVAL;
2160 }
2161
2162 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2163 if (ret)
2164 goto out;
2165
2166 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2167 if (!mf) {
2168 ret = -ENOMEM;
2169 goto out_unlock;
2170 }
2171
2172 smpreq = (SmpPassthroughRequest_t *)mf;
2173 memset(smpreq, 0, sizeof(*smpreq));
2174
Tejun Heob0790412009-05-07 22:24:42 +09002175 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002176 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2177
2178 if (rphy)
2179 sas_address = rphy->identify.sas_address;
2180 else {
2181 struct mptsas_portinfo *port_info;
2182
2183 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302184 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002185 if (port_info && port_info->phy_info)
2186 sas_address =
2187 port_info->phy_info[0].phy->identify.sas_address;
2188 mutex_unlock(&ioc->sas_topology_mutex);
2189 }
2190
2191 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2192
2193 psge = (char *)
2194 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2195
2196 /* request */
2197 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2198 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302199 MPI_SGE_FLAGS_DIRECTION)
2200 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002201 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002202
2203 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002204 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002205 if (!dma_addr_out)
2206 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302207 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302208 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002209
2210 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302211 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2212 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2213 MPI_SGE_FLAGS_IOC_TO_HOST |
2214 MPI_SGE_FLAGS_END_OF_BUFFER;
2215
2216 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002217 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002218 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002219 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002220 if (!dma_addr_in)
2221 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302222 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002223
Kashyap, Desai2f187862009-05-29 16:52:37 +05302224 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002225 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2226
2227 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302228 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2229 ret = -ETIME;
2230 mpt_free_msg_frame(ioc, mf);
2231 mf = NULL;
2232 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2233 goto unmap;
2234 if (!timeleft)
2235 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002236 goto unmap;
2237 }
2238 mf = NULL;
2239
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302240 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002241 SmpPassthroughReply_t *smprep;
2242
2243 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2244 memcpy(req->sense, smprep, sizeof(*smprep));
2245 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002246 req->resid_len = 0;
2247 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002248 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302249 printk(MYIOC_s_ERR_FMT
2250 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002251 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002252 ret = -ENXIO;
2253 }
2254unmap:
2255 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002256 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002257 PCI_DMA_BIDIRECTIONAL);
2258 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002259 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002260 PCI_DMA_BIDIRECTIONAL);
2261put_mf:
2262 if (mf)
2263 mpt_free_msg_frame(ioc, mf);
2264out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302265 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002266 mutex_unlock(&ioc->sas_mgmt.mutex);
2267out:
2268 return ret;
2269}
2270
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002271static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002272 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002273 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2274 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002275 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002276 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002277};
2278
2279static struct scsi_transport_template *mptsas_transport_template;
2280
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002281static int
2282mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2283{
2284 ConfigExtendedPageHeader_t hdr;
2285 CONFIGPARMS cfg;
2286 SasIOUnitPage0_t *buffer;
2287 dma_addr_t dma_handle;
2288 int error, i;
2289
2290 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2291 hdr.ExtPageLength = 0;
2292 hdr.PageNumber = 0;
2293 hdr.Reserved1 = 0;
2294 hdr.Reserved2 = 0;
2295 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2296 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2297
2298 cfg.cfghdr.ehdr = &hdr;
2299 cfg.physAddr = -1;
2300 cfg.pageAddr = 0;
2301 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2302 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302303 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002304
2305 error = mpt_config(ioc, &cfg);
2306 if (error)
2307 goto out;
2308 if (!hdr.ExtPageLength) {
2309 error = -ENXIO;
2310 goto out;
2311 }
2312
2313 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2314 &dma_handle);
2315 if (!buffer) {
2316 error = -ENOMEM;
2317 goto out;
2318 }
2319
2320 cfg.physAddr = dma_handle;
2321 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2322
2323 error = mpt_config(ioc, &cfg);
2324 if (error)
2325 goto out_free_consistent;
2326
2327 port_info->num_phys = buffer->NumPhys;
2328 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302329 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002330 if (!port_info->phy_info) {
2331 error = -ENOMEM;
2332 goto out_free_consistent;
2333 }
2334
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302335 ioc->nvdata_version_persistent =
2336 le16_to_cpu(buffer->NvdataVersionPersistent);
2337 ioc->nvdata_version_default =
2338 le16_to_cpu(buffer->NvdataVersionDefault);
2339
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002340 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302341 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002342 port_info->phy_info[i].phy_id = i;
2343 port_info->phy_info[i].port_id =
2344 buffer->PhyData[i].Port;
2345 port_info->phy_info[i].negotiated_link_rate =
2346 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002347 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002348 port_info->phy_info[i].handle =
2349 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002350 }
2351
2352 out_free_consistent:
2353 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2354 buffer, dma_handle);
2355 out:
2356 return error;
2357}
2358
2359static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302360mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2361{
2362 ConfigExtendedPageHeader_t hdr;
2363 CONFIGPARMS cfg;
2364 SasIOUnitPage1_t *buffer;
2365 dma_addr_t dma_handle;
2366 int error;
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302367 u8 device_missing_delay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302368
2369 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2370 memset(&cfg, 0, sizeof(CONFIGPARMS));
2371
2372 cfg.cfghdr.ehdr = &hdr;
2373 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302374 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302375 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2376 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2377 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2378 cfg.cfghdr.ehdr->PageNumber = 1;
2379
2380 error = mpt_config(ioc, &cfg);
2381 if (error)
2382 goto out;
2383 if (!hdr.ExtPageLength) {
2384 error = -ENXIO;
2385 goto out;
2386 }
2387
2388 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2389 &dma_handle);
2390 if (!buffer) {
2391 error = -ENOMEM;
2392 goto out;
2393 }
2394
2395 cfg.physAddr = dma_handle;
2396 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2397
2398 error = mpt_config(ioc, &cfg);
2399 if (error)
2400 goto out_free_consistent;
2401
2402 ioc->io_missing_delay =
2403 le16_to_cpu(buffer->IODeviceMissingDelay);
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302404 device_missing_delay = buffer->ReportDeviceMissingDelay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302405 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2406 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2407 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2408
2409 out_free_consistent:
2410 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2411 buffer, dma_handle);
2412 out:
2413 return error;
2414}
2415
2416static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002417mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2418 u32 form, u32 form_specific)
2419{
2420 ConfigExtendedPageHeader_t hdr;
2421 CONFIGPARMS cfg;
2422 SasPhyPage0_t *buffer;
2423 dma_addr_t dma_handle;
2424 int error;
2425
2426 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2427 hdr.ExtPageLength = 0;
2428 hdr.PageNumber = 0;
2429 hdr.Reserved1 = 0;
2430 hdr.Reserved2 = 0;
2431 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2432 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2433
2434 cfg.cfghdr.ehdr = &hdr;
2435 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302436 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002437
2438 /* Get Phy Pg 0 for each Phy. */
2439 cfg.physAddr = -1;
2440 cfg.pageAddr = form + form_specific;
2441 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2442
2443 error = mpt_config(ioc, &cfg);
2444 if (error)
2445 goto out;
2446
2447 if (!hdr.ExtPageLength) {
2448 error = -ENXIO;
2449 goto out;
2450 }
2451
2452 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2453 &dma_handle);
2454 if (!buffer) {
2455 error = -ENOMEM;
2456 goto out;
2457 }
2458
2459 cfg.physAddr = dma_handle;
2460 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2461
2462 error = mpt_config(ioc, &cfg);
2463 if (error)
2464 goto out_free_consistent;
2465
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302466 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002467
2468 phy_info->hw_link_rate = buffer->HwLinkRate;
2469 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2470 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2471 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2472
2473 out_free_consistent:
2474 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2475 buffer, dma_handle);
2476 out:
2477 return error;
2478}
2479
2480static int
2481mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2482 u32 form, u32 form_specific)
2483{
2484 ConfigExtendedPageHeader_t hdr;
2485 CONFIGPARMS cfg;
2486 SasDevicePage0_t *buffer;
2487 dma_addr_t dma_handle;
2488 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002489 int error=0;
2490
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002491 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2492 hdr.ExtPageLength = 0;
2493 hdr.PageNumber = 0;
2494 hdr.Reserved1 = 0;
2495 hdr.Reserved2 = 0;
2496 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2497 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2498
2499 cfg.cfghdr.ehdr = &hdr;
2500 cfg.pageAddr = form + form_specific;
2501 cfg.physAddr = -1;
2502 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2503 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302504 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002505
Moore, Ericdb9c9172006-03-14 09:14:18 -07002506 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002507 error = mpt_config(ioc, &cfg);
2508 if (error)
2509 goto out;
2510 if (!hdr.ExtPageLength) {
2511 error = -ENXIO;
2512 goto out;
2513 }
2514
2515 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2516 &dma_handle);
2517 if (!buffer) {
2518 error = -ENOMEM;
2519 goto out;
2520 }
2521
2522 cfg.physAddr = dma_handle;
2523 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2524
2525 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302526
2527 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2528 error = -ENODEV;
2529 goto out_free_consistent;
2530 }
2531
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002532 if (error)
2533 goto out_free_consistent;
2534
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302535 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002536
Kashyap, Desai2f187862009-05-29 16:52:37 +05302537 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002538 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -07002539 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002540 device_info->handle_enclosure =
2541 le16_to_cpu(buffer->EnclosureHandle);
2542 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002543 device_info->phy_id = buffer->PhyNum;
2544 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002545 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002546 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002547 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002548 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2549 device_info->sas_address = le64_to_cpu(sas_address);
2550 device_info->device_info =
2551 le32_to_cpu(buffer->DeviceInfo);
Kashyap, Desai51106ab2010-06-17 14:40:10 +05302552 device_info->flags = le16_to_cpu(buffer->Flags);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002553
2554 out_free_consistent:
2555 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2556 buffer, dma_handle);
2557 out:
2558 return error;
2559}
2560
2561static int
2562mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2563 u32 form, u32 form_specific)
2564{
2565 ConfigExtendedPageHeader_t hdr;
2566 CONFIGPARMS cfg;
2567 SasExpanderPage0_t *buffer;
2568 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002569 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302570 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002571
Kashyap, Desai2f187862009-05-29 16:52:37 +05302572 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002573 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2574 hdr.ExtPageLength = 0;
2575 hdr.PageNumber = 0;
2576 hdr.Reserved1 = 0;
2577 hdr.Reserved2 = 0;
2578 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2579 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2580
2581 cfg.cfghdr.ehdr = &hdr;
2582 cfg.physAddr = -1;
2583 cfg.pageAddr = form + form_specific;
2584 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2585 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302586 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002587
Moore, Ericdb9c9172006-03-14 09:14:18 -07002588 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002589 error = mpt_config(ioc, &cfg);
2590 if (error)
2591 goto out;
2592
2593 if (!hdr.ExtPageLength) {
2594 error = -ENXIO;
2595 goto out;
2596 }
2597
2598 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2599 &dma_handle);
2600 if (!buffer) {
2601 error = -ENOMEM;
2602 goto out;
2603 }
2604
2605 cfg.physAddr = dma_handle;
2606 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2607
2608 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302609 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002610 error = -ENODEV;
2611 goto out_free_consistent;
2612 }
2613
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302614 if (error)
2615 goto out_free_consistent;
2616
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002617 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302618 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002619 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302620 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002621 if (!port_info->phy_info) {
2622 error = -ENOMEM;
2623 goto out_free_consistent;
2624 }
2625
Kashyap, Desai2f187862009-05-29 16:52:37 +05302626 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002627 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002628 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002629 port_info->phy_info[i].handle =
2630 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302631 port_info->phy_info[i].identify.sas_address =
2632 le64_to_cpu(sas_address);
2633 port_info->phy_info[i].identify.handle_parent =
2634 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002635 }
Eric Moore547f9a22006-06-27 14:42:12 -06002636
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002637 out_free_consistent:
2638 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2639 buffer, dma_handle);
2640 out:
2641 return error;
2642}
2643
2644static int
2645mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2646 u32 form, u32 form_specific)
2647{
2648 ConfigExtendedPageHeader_t hdr;
2649 CONFIGPARMS cfg;
2650 SasExpanderPage1_t *buffer;
2651 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002652 int error=0;
2653
Kashyap, Desai2f187862009-05-29 16:52:37 +05302654 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002655 hdr.ExtPageLength = 0;
2656 hdr.PageNumber = 1;
2657 hdr.Reserved1 = 0;
2658 hdr.Reserved2 = 0;
2659 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2660 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2661
2662 cfg.cfghdr.ehdr = &hdr;
2663 cfg.physAddr = -1;
2664 cfg.pageAddr = form + form_specific;
2665 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2666 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302667 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002668
2669 error = mpt_config(ioc, &cfg);
2670 if (error)
2671 goto out;
2672
2673 if (!hdr.ExtPageLength) {
2674 error = -ENXIO;
2675 goto out;
2676 }
2677
2678 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2679 &dma_handle);
2680 if (!buffer) {
2681 error = -ENOMEM;
2682 goto out;
2683 }
2684
2685 cfg.physAddr = dma_handle;
2686 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2687
2688 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302689
2690 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2691 error = -ENODEV;
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302692 goto out_free_consistent;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302693 }
2694
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002695 if (error)
2696 goto out_free_consistent;
2697
2698
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302699 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002700
2701 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002702 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002703 phy_info->port_id = buffer->PhysicalPort;
2704 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2705 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2706 phy_info->hw_link_rate = buffer->HwLinkRate;
2707 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2708 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2709
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002710 out_free_consistent:
2711 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2712 buffer, dma_handle);
2713 out:
2714 return error;
2715}
2716
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302717struct rep_manu_request{
2718 u8 smp_frame_type;
2719 u8 function;
2720 u8 reserved;
2721 u8 request_length;
2722};
2723
2724struct rep_manu_reply{
2725 u8 smp_frame_type; /* 0x41 */
2726 u8 function; /* 0x01 */
2727 u8 function_result;
2728 u8 response_length;
2729 u16 expander_change_count;
2730 u8 reserved0[2];
2731 u8 sas_format:1;
2732 u8 reserved1:7;
2733 u8 reserved2[3];
2734 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2735 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2736 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2737 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2738 u16 component_id;
2739 u8 component_revision_id;
2740 u8 reserved3;
2741 u8 vendor_specific[8];
2742};
2743
2744/**
2745 * mptsas_exp_repmanufacture_info -
2746 * @ioc: per adapter object
2747 * @sas_address: expander sas address
2748 * @edev: the sas_expander_device object
2749 *
2750 * Fills in the sas_expander_device object when SMP port is created.
2751 *
2752 * Returns 0 for success, non-zero for failure.
2753 */
2754static int
2755mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2756 u64 sas_address, struct sas_expander_device *edev)
2757{
2758 MPT_FRAME_HDR *mf;
2759 SmpPassthroughRequest_t *smpreq;
2760 SmpPassthroughReply_t *smprep;
2761 struct rep_manu_reply *manufacture_reply;
2762 struct rep_manu_request *manufacture_request;
2763 int ret;
2764 int flagsLength;
2765 unsigned long timeleft;
2766 char *psge;
2767 unsigned long flags;
2768 void *data_out = NULL;
2769 dma_addr_t data_out_dma = 0;
2770 u32 sz;
2771
2772 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2773 if (ioc->ioc_reset_in_progress) {
2774 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2775 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2776 __func__, ioc->name);
2777 return -EFAULT;
2778 }
2779 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2780
2781 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2782 if (ret)
2783 goto out;
2784
2785 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2786 if (!mf) {
2787 ret = -ENOMEM;
2788 goto out_unlock;
2789 }
2790
2791 smpreq = (SmpPassthroughRequest_t *)mf;
2792 memset(smpreq, 0, sizeof(*smpreq));
2793
2794 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2795
2796 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2797 if (!data_out) {
2798 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2799 __FILE__, __LINE__, __func__);
2800 ret = -ENOMEM;
2801 goto put_mf;
2802 }
2803
2804 manufacture_request = data_out;
2805 manufacture_request->smp_frame_type = 0x40;
2806 manufacture_request->function = 1;
2807 manufacture_request->reserved = 0;
2808 manufacture_request->request_length = 0;
2809
2810 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2811 smpreq->PhysicalPort = 0xFF;
2812 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2813 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2814
2815 psge = (char *)
2816 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2817
2818 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2819 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2820 MPI_SGE_FLAGS_HOST_TO_IOC |
2821 MPI_SGE_FLAGS_END_OF_BUFFER;
2822 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2823 flagsLength |= sizeof(struct rep_manu_request);
2824
2825 ioc->add_sge(psge, flagsLength, data_out_dma);
2826 psge += ioc->SGE_size;
2827
2828 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2829 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2830 MPI_SGE_FLAGS_IOC_TO_HOST |
2831 MPI_SGE_FLAGS_END_OF_BUFFER;
2832 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2833 flagsLength |= sizeof(struct rep_manu_reply);
2834 ioc->add_sge(psge, flagsLength, data_out_dma +
2835 sizeof(struct rep_manu_request));
2836
2837 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2838 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2839
2840 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2841 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2842 ret = -ETIME;
2843 mpt_free_msg_frame(ioc, mf);
2844 mf = NULL;
2845 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2846 goto out_free;
2847 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302848 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302849 goto out_free;
2850 }
2851
2852 mf = NULL;
2853
2854 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2855 u8 *tmp;
2856
2857 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2858 if (le16_to_cpu(smprep->ResponseDataLength) !=
2859 sizeof(struct rep_manu_reply))
2860 goto out_free;
2861
2862 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2863 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2864 SAS_EXPANDER_VENDOR_ID_LEN);
2865 strncpy(edev->product_id, manufacture_reply->product_id,
2866 SAS_EXPANDER_PRODUCT_ID_LEN);
2867 strncpy(edev->product_rev, manufacture_reply->product_rev,
2868 SAS_EXPANDER_PRODUCT_REV_LEN);
2869 edev->level = manufacture_reply->sas_format;
2870 if (manufacture_reply->sas_format) {
2871 strncpy(edev->component_vendor_id,
2872 manufacture_reply->component_vendor_id,
2873 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2874 tmp = (u8 *)&manufacture_reply->component_id;
2875 edev->component_id = tmp[0] << 8 | tmp[1];
2876 edev->component_revision_id =
2877 manufacture_reply->component_revision_id;
2878 }
2879 } else {
2880 printk(MYIOC_s_ERR_FMT
2881 "%s: smp passthru reply failed to be returned\n",
2882 ioc->name, __func__);
2883 ret = -ENXIO;
2884 }
2885out_free:
2886 if (data_out_dma)
2887 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2888put_mf:
2889 if (mf)
2890 mpt_free_msg_frame(ioc, mf);
2891out_unlock:
2892 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2893 mutex_unlock(&ioc->sas_mgmt.mutex);
2894out:
2895 return ret;
2896 }
2897
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002898static void
2899mptsas_parse_device_info(struct sas_identify *identify,
2900 struct mptsas_devinfo *device_info)
2901{
2902 u16 protocols;
2903
2904 identify->sas_address = device_info->sas_address;
2905 identify->phy_identifier = device_info->phy_id;
2906
2907 /*
2908 * Fill in Phy Initiator Port Protocol.
2909 * Bits 6:3, more than one bit can be set, fall through cases.
2910 */
2911 protocols = device_info->device_info & 0x78;
2912 identify->initiator_port_protocols = 0;
2913 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2914 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2915 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2916 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2917 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2918 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2919 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2920 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2921
2922 /*
2923 * Fill in Phy Target Port Protocol.
2924 * Bits 10:7, more than one bit can be set, fall through cases.
2925 */
2926 protocols = device_info->device_info & 0x780;
2927 identify->target_port_protocols = 0;
2928 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2929 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2930 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2931 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2932 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2933 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2934 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2935 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2936
2937 /*
2938 * Fill in Attached device type.
2939 */
2940 switch (device_info->device_info &
2941 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2942 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2943 identify->device_type = SAS_PHY_UNUSED;
2944 break;
2945 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2946 identify->device_type = SAS_END_DEVICE;
2947 break;
2948 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2949 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2950 break;
2951 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2952 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2953 break;
2954 }
2955}
2956
2957static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002958 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002959{
Moore, Erice6b2d762006-03-14 09:14:24 -07002960 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002961 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002962 struct sas_port *port;
2963 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002964
Eric Moore547f9a22006-06-27 14:42:12 -06002965 if (!dev) {
2966 error = -ENODEV;
2967 goto out;
2968 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002969
2970 if (!phy_info->phy) {
2971 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002972 if (!phy) {
2973 error = -ENOMEM;
2974 goto out;
2975 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002976 } else
2977 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002978
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002979 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002980
2981 /*
2982 * Set Negotiated link rate.
2983 */
2984 switch (phy_info->negotiated_link_rate) {
2985 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002986 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002987 break;
2988 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002989 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002990 break;
2991 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002992 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002993 break;
2994 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002995 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002996 break;
2997 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2998 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2999 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003000 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003001 break;
3002 }
3003
3004 /*
3005 * Set Max hardware link rate.
3006 */
3007 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3008 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003009 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003010 break;
3011 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003012 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003013 break;
3014 default:
3015 break;
3016 }
3017
3018 /*
3019 * Set Max programmed link rate.
3020 */
3021 switch (phy_info->programmed_link_rate &
3022 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3023 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003024 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003025 break;
3026 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003027 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003028 break;
3029 default:
3030 break;
3031 }
3032
3033 /*
3034 * Set Min hardware link rate.
3035 */
3036 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3037 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003038 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003039 break;
3040 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003041 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003042 break;
3043 default:
3044 break;
3045 }
3046
3047 /*
3048 * Set Min programmed link rate.
3049 */
3050 switch (phy_info->programmed_link_rate &
3051 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3052 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003053 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003054 break;
3055 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003056 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003057 break;
3058 default:
3059 break;
3060 }
3061
Moore, Erice6b2d762006-03-14 09:14:24 -07003062 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003063
Moore, Erice6b2d762006-03-14 09:14:24 -07003064 error = sas_phy_add(phy);
3065 if (error) {
3066 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003067 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003068 }
3069 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003070 }
3071
Eric Moore547f9a22006-06-27 14:42:12 -06003072 if (!phy_info->attached.handle ||
3073 !phy_info->port_details)
3074 goto out;
3075
3076 port = mptsas_get_port(phy_info);
3077 ioc = phy_to_ioc(phy_info->phy);
3078
3079 if (phy_info->sas_port_add_phy) {
3080
3081 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003082 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003083 if (!port) {
3084 error = -ENOMEM;
3085 goto out;
3086 }
3087 error = sas_port_add(port);
3088 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303089 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003090 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003091 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003092 goto out;
3093 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303094 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303095 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3096 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3097 ioc->name, port->port_identifier,
3098 (unsigned long long)phy_info->
3099 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003100 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303101 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3102 "sas_port_add_phy: phy_id=%d\n",
3103 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003104 sas_port_add_phy(port, phy_info->phy);
3105 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303106 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3107 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3108 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003109 }
Eric Moore547f9a22006-06-27 14:42:12 -06003110 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003111
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003112 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003113 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003114 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003115
James Bottomley2686de22006-06-30 12:54:02 -05003116 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003117 /*
3118 * Let the hotplug_work thread handle processing
3119 * the adding/removing of devices that occur
3120 * after start of day.
3121 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303122 if (mptsas_is_end_device(&phy_info->attached) &&
3123 phy_info->attached.handle_parent) {
3124 goto out;
3125 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003126
James Bottomleyf013db32006-03-18 14:54:36 -06003127 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003128 if (scsi_is_host_device(parent)) {
3129 struct mptsas_portinfo *port_info;
3130 int i;
3131
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303132 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003133
3134 for (i = 0; i < port_info->num_phys; i++)
3135 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003136 identify.sas_address) {
3137 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003138 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003139 }
James Bottomley2686de22006-06-30 12:54:02 -05003140
3141 } else if (scsi_is_sas_rphy(parent)) {
3142 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3143 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003144 parent_rphy->identify.sas_address) {
3145 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003146 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003147 }
James Bottomley2686de22006-06-30 12:54:02 -05003148 }
3149
James Bottomleyf013db32006-03-18 14:54:36 -06003150 switch (identify.device_type) {
3151 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003152 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003153 break;
3154 case SAS_EDGE_EXPANDER_DEVICE:
3155 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003156 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003157 break;
3158 default:
3159 rphy = NULL;
3160 break;
3161 }
Eric Moore547f9a22006-06-27 14:42:12 -06003162 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303163 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003164 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003165 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003166 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003167 }
3168
Eric Moore547f9a22006-06-27 14:42:12 -06003169 rphy->identify = identify;
3170 error = sas_rphy_add(rphy);
3171 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303172 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003173 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003174 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003175 sas_rphy_free(rphy);
3176 goto out;
3177 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303178 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303179 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3180 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3181 mptsas_exp_repmanufacture_info(ioc,
3182 identify.sas_address,
3183 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003184 }
3185
Eric Moore547f9a22006-06-27 14:42:12 -06003186 out:
3187 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003188}
3189
3190static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003191mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003192{
Moore, Erice6b2d762006-03-14 09:14:24 -07003193 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003194 int error = -ENOMEM, i;
3195
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303196 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003197 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003198 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003199
Moore, Erice6b2d762006-03-14 09:14:24 -07003200 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003201 if (error)
3202 goto out_free_port_info;
3203
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303204 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003205 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303206 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003207 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303208 ioc->hba_port_info = port_info = hba;
3209 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003210 list_add_tail(&port_info->list, &ioc->sas_topology);
3211 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003212 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003213 port_info->phy_info[i].negotiated_link_rate =
3214 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003215 port_info->phy_info[i].handle =
3216 hba->phy_info[i].handle;
3217 port_info->phy_info[i].port_id =
3218 hba->phy_info[i].port_id;
3219 }
Eric Moore547f9a22006-06-27 14:42:12 -06003220 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003221 kfree(hba);
3222 hba = NULL;
3223 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003224 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303225#if defined(CPQ_CIM)
3226 ioc->num_ports = port_info->num_phys;
3227#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003228 for (i = 0; i < port_info->num_phys; i++) {
3229 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3230 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3231 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303232 port_info->phy_info[i].identify.handle =
3233 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003235 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3236 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303237 port_info->phy_info[i].identify.handle);
3238 if (!ioc->hba_port_sas_addr)
3239 ioc->hba_port_sas_addr =
3240 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003241 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003242 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003243 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003244 mptsas_sas_device_pg0(ioc,
3245 &port_info->phy_info[i].attached,
3246 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3247 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3248 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003249 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003250
Eric Moore547f9a22006-06-27 14:42:12 -06003251 mptsas_setup_wide_ports(ioc, port_info);
3252
3253 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003254 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003255 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003256
3257 return 0;
3258
3259 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003260 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261 out:
3262 return error;
3263}
3264
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303265static void
3266mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003267{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303268 struct mptsas_portinfo *parent;
3269 struct device *parent_dev;
3270 struct sas_rphy *rphy;
3271 int i;
3272 u64 sas_address; /* expander sas address */
3273 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003274
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303275 handle = port_info->phy_info[0].handle;
3276 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003277 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303279 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3280 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003281
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303282 mptsas_sas_device_pg0(ioc,
3283 &port_info->phy_info[i].identify,
3284 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3285 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3286 port_info->phy_info[i].identify.handle);
3287 port_info->phy_info[i].identify.phy_id =
3288 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003289
3290 if (port_info->phy_info[i].attached.handle) {
3291 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303292 &port_info->phy_info[i].attached,
3293 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3294 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3295 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003296 port_info->phy_info[i].attached.phy_id =
3297 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003298 }
Eric Moore547f9a22006-06-27 14:42:12 -06003299 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003300
Moore, Erice6b2d762006-03-14 09:14:24 -07003301 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303302 parent = mptsas_find_portinfo_by_handle(ioc,
3303 port_info->phy_info[0].identify.handle_parent);
3304 if (!parent) {
3305 mutex_unlock(&ioc->sas_topology_mutex);
3306 return;
3307 }
3308 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3309 i++) {
3310 if (parent->phy_info[i].attached.sas_address == sas_address) {
3311 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3312 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003313 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003314 }
3315 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303316
3317 mptsas_setup_wide_ports(ioc, port_info);
3318 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3319 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3320 ioc->sas_index, 0);
3321}
3322
3323static void
3324mptsas_expander_event_add(MPT_ADAPTER *ioc,
3325 MpiEventDataSasExpanderStatusChange_t *expander_data)
3326{
3327 struct mptsas_portinfo *port_info;
3328 int i;
3329 __le64 sas_address;
3330
3331 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3332 if (!port_info)
3333 BUG();
3334 port_info->num_phys = (expander_data->NumPhys) ?
3335 expander_data->NumPhys : 1;
3336 port_info->phy_info = kcalloc(port_info->num_phys,
3337 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3338 if (!port_info->phy_info)
3339 BUG();
3340 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3341 for (i = 0; i < port_info->num_phys; i++) {
3342 port_info->phy_info[i].portinfo = port_info;
3343 port_info->phy_info[i].handle =
3344 le16_to_cpu(expander_data->DevHandle);
3345 port_info->phy_info[i].identify.sas_address =
3346 le64_to_cpu(sas_address);
3347 port_info->phy_info[i].identify.handle_parent =
3348 le16_to_cpu(expander_data->ParentDevHandle);
3349 }
3350
3351 mutex_lock(&ioc->sas_topology_mutex);
3352 list_add_tail(&port_info->list, &ioc->sas_topology);
3353 mutex_unlock(&ioc->sas_topology_mutex);
3354
3355 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3356 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3357 (unsigned long long)sas_address);
3358
3359 mptsas_expander_refresh(ioc, port_info);
3360}
3361
3362/**
3363 * mptsas_delete_expander_siblings - remove siblings attached to expander
3364 * @ioc: Pointer to MPT_ADAPTER structure
3365 * @parent: the parent port_info object
3366 * @expander: the expander port_info object
3367 **/
3368static void
3369mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3370 *parent, struct mptsas_portinfo *expander)
3371{
3372 struct mptsas_phyinfo *phy_info;
3373 struct mptsas_portinfo *port_info;
3374 struct sas_rphy *rphy;
3375 int i;
3376
3377 phy_info = expander->phy_info;
3378 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3379 rphy = mptsas_get_rphy(phy_info);
3380 if (!rphy)
3381 continue;
3382 if (rphy->identify.device_type == SAS_END_DEVICE)
3383 mptsas_del_end_device(ioc, phy_info);
3384 }
3385
3386 phy_info = expander->phy_info;
3387 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3388 rphy = mptsas_get_rphy(phy_info);
3389 if (!rphy)
3390 continue;
3391 if (rphy->identify.device_type ==
3392 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3393 rphy->identify.device_type ==
3394 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3395 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3396 rphy->identify.sas_address);
3397 if (!port_info)
3398 continue;
3399 if (port_info == parent) /* backlink rphy */
3400 continue;
3401 /*
3402 Delete this expander even if the expdevpage is exists
3403 because the parent expander is already deleted
3404 */
3405 mptsas_expander_delete(ioc, port_info, 1);
3406 }
3407 }
3408}
3409
3410
3411/**
3412 * mptsas_expander_delete - remove this expander
3413 * @ioc: Pointer to MPT_ADAPTER structure
3414 * @port_info: expander port_info struct
3415 * @force: Flag to forcefully delete the expander
3416 *
3417 **/
3418
3419static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3420 struct mptsas_portinfo *port_info, u8 force)
3421{
3422
3423 struct mptsas_portinfo *parent;
3424 int i;
3425 u64 expander_sas_address;
3426 struct mptsas_phyinfo *phy_info;
3427 struct mptsas_portinfo buffer;
3428 struct mptsas_portinfo_details *port_details;
3429 struct sas_port *port;
3430
3431 if (!port_info)
3432 return;
3433
3434 /* see if expander is still there before deleting */
3435 mptsas_sas_expander_pg0(ioc, &buffer,
3436 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3437 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3438 port_info->phy_info[0].identify.handle);
3439
3440 if (buffer.num_phys) {
3441 kfree(buffer.phy_info);
3442 if (!force)
3443 return;
3444 }
3445
3446
3447 /*
3448 * Obtain the port_info instance to the parent port
3449 */
3450 port_details = NULL;
3451 expander_sas_address =
3452 port_info->phy_info[0].identify.sas_address;
3453 parent = mptsas_find_portinfo_by_handle(ioc,
3454 port_info->phy_info[0].identify.handle_parent);
3455 mptsas_delete_expander_siblings(ioc, parent, port_info);
3456 if (!parent)
3457 goto out;
3458
3459 /*
3460 * Delete rphys in the parent that point
3461 * to this expander.
3462 */
3463 phy_info = parent->phy_info;
3464 port = NULL;
3465 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3466 if (!phy_info->phy)
3467 continue;
3468 if (phy_info->attached.sas_address !=
3469 expander_sas_address)
3470 continue;
3471 if (!port) {
3472 port = mptsas_get_port(phy_info);
3473 port_details = phy_info->port_details;
3474 }
3475 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3476 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3477 phy_info->phy_id, phy_info->phy);
3478 sas_port_delete_phy(port, phy_info->phy);
3479 }
3480 if (port) {
3481 dev_printk(KERN_DEBUG, &port->dev,
3482 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3483 ioc->name, port->port_identifier,
3484 (unsigned long long)expander_sas_address);
3485 sas_port_delete(port);
3486 mptsas_port_delete(ioc, port_details);
3487 }
3488 out:
3489
3490 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3491 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3492 (unsigned long long)expander_sas_address);
3493
3494 /*
3495 * free link
3496 */
3497 list_del(&port_info->list);
3498 kfree(port_info->phy_info);
3499 kfree(port_info);
3500}
3501
3502
3503/**
3504 * mptsas_send_expander_event - expanders events
3505 * @ioc: Pointer to MPT_ADAPTER structure
3506 * @expander_data: event data
3507 *
3508 *
3509 * This function handles adding, removing, and refreshing
3510 * device handles within the expander objects.
3511 */
3512static void
3513mptsas_send_expander_event(struct fw_event_work *fw_event)
3514{
3515 MPT_ADAPTER *ioc;
3516 MpiEventDataSasExpanderStatusChange_t *expander_data;
3517 struct mptsas_portinfo *port_info;
3518 __le64 sas_address;
3519 int i;
3520
3521 ioc = fw_event->ioc;
3522 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3523 fw_event->event_data;
3524 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303525 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303526 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3527
3528 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3529 if (port_info) {
3530 for (i = 0; i < port_info->num_phys; i++) {
3531 port_info->phy_info[i].portinfo = port_info;
3532 port_info->phy_info[i].handle =
3533 le16_to_cpu(expander_data->DevHandle);
3534 port_info->phy_info[i].identify.sas_address =
3535 le64_to_cpu(sas_address);
3536 port_info->phy_info[i].identify.handle_parent =
3537 le16_to_cpu(expander_data->ParentDevHandle);
3538 }
3539 mptsas_expander_refresh(ioc, port_info);
3540 } else if (!port_info && expander_data->NumPhys)
3541 mptsas_expander_event_add(ioc, expander_data);
3542 } else if (expander_data->ReasonCode ==
3543 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3544 mptsas_expander_delete(ioc, port_info, 0);
3545
3546 mptsas_free_fw_event(ioc, fw_event);
3547}
3548
3549
3550/**
3551 * mptsas_expander_add -
3552 * @ioc: Pointer to MPT_ADAPTER structure
3553 * @handle:
3554 *
3555 */
3556struct mptsas_portinfo *
3557mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3558{
3559 struct mptsas_portinfo buffer, *port_info;
3560 int i;
3561
3562 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3563 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3564 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3565 return NULL;
3566
3567 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3568 if (!port_info) {
3569 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3570 "%s: exit at line=%d\n", ioc->name,
3571 __func__, __LINE__));
3572 return NULL;
3573 }
3574 port_info->num_phys = buffer.num_phys;
3575 port_info->phy_info = buffer.phy_info;
3576 for (i = 0; i < port_info->num_phys; i++)
3577 port_info->phy_info[i].portinfo = port_info;
3578 mutex_lock(&ioc->sas_topology_mutex);
3579 list_add_tail(&port_info->list, &ioc->sas_topology);
3580 mutex_unlock(&ioc->sas_topology_mutex);
3581 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3582 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3583 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3584 mptsas_expander_refresh(ioc, port_info);
3585 return port_info;
3586}
3587
3588static void
3589mptsas_send_link_status_event(struct fw_event_work *fw_event)
3590{
3591 MPT_ADAPTER *ioc;
3592 MpiEventDataSasPhyLinkStatus_t *link_data;
3593 struct mptsas_portinfo *port_info;
3594 struct mptsas_phyinfo *phy_info = NULL;
3595 __le64 sas_address;
3596 u8 phy_num;
3597 u8 link_rate;
3598
3599 ioc = fw_event->ioc;
3600 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3601
3602 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3603 sas_address = le64_to_cpu(sas_address);
3604 link_rate = link_data->LinkRates >> 4;
3605 phy_num = link_data->PhyNum;
3606
3607 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3608 if (port_info) {
3609 phy_info = &port_info->phy_info[phy_num];
3610 if (phy_info)
3611 phy_info->negotiated_link_rate = link_rate;
3612 }
3613
3614 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3615 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3616
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303617 if (!port_info) {
3618 if (ioc->old_sas_discovery_protocal) {
3619 port_info = mptsas_expander_add(ioc,
3620 le16_to_cpu(link_data->DevHandle));
3621 if (port_info)
3622 goto out;
3623 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303624 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303625 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303626
3627 if (port_info == ioc->hba_port_info)
3628 mptsas_probe_hba_phys(ioc);
3629 else
3630 mptsas_expander_refresh(ioc, port_info);
3631 } else if (phy_info && phy_info->phy) {
3632 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3633 phy_info->phy->negotiated_linkrate =
3634 SAS_PHY_DISABLED;
3635 else if (link_rate ==
3636 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3637 phy_info->phy->negotiated_linkrate =
3638 SAS_LINK_RATE_FAILED;
3639 else
3640 phy_info->phy->negotiated_linkrate =
3641 SAS_LINK_RATE_UNKNOWN;
3642 }
3643 out:
3644 mptsas_free_fw_event(ioc, fw_event);
3645}
3646
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303647static void
3648mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3649{
3650 struct mptsas_portinfo buffer, *port_info;
3651 struct mptsas_device_info *sas_info;
3652 struct mptsas_devinfo sas_device;
3653 u32 handle;
3654 VirtTarget *vtarget = NULL;
3655 struct mptsas_phyinfo *phy_info;
3656 u8 found_expander;
3657 int retval, retry_count;
3658 unsigned long flags;
3659
3660 mpt_findImVolumes(ioc);
3661
3662 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3663 if (ioc->ioc_reset_in_progress) {
3664 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3665 "%s: exiting due to a parallel reset \n", ioc->name,
3666 __func__));
3667 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3668 return;
3669 }
3670 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3671
3672 /* devices, logical volumes */
3673 mutex_lock(&ioc->sas_device_info_mutex);
3674 redo_device_scan:
3675 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303676 if (sas_info->is_cached)
3677 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303678 if (!sas_info->is_logical_volume) {
3679 sas_device.handle = 0;
3680 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303681retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303682 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303683 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3684 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3685 (sas_info->fw.channel << 8) +
3686 sas_info->fw.id);
3687
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303688 if (sas_device.handle)
3689 continue;
3690 if (retval == -EBUSY) {
3691 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3692 if (ioc->ioc_reset_in_progress) {
3693 dfailprintk(ioc,
3694 printk(MYIOC_s_DEBUG_FMT
3695 "%s: exiting due to reset\n",
3696 ioc->name, __func__));
3697 spin_unlock_irqrestore
3698 (&ioc->taskmgmt_lock, flags);
3699 mutex_unlock(&ioc->
3700 sas_device_info_mutex);
3701 return;
3702 }
3703 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3704 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303705 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303706
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303707 if (retval && (retval != -ENODEV)) {
3708 if (retry_count < 10) {
3709 retry_count++;
3710 goto retry_page;
3711 } else {
3712 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3713 "%s: Config page retry exceeded retry "
3714 "count deleting device 0x%llx\n",
3715 ioc->name, __func__,
3716 sas_info->sas_address));
3717 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303718 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303719
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303720 /* delete device */
3721 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303722 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303723
3724 if (vtarget)
3725 vtarget->deleted = 1;
3726
3727 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3728 sas_info->sas_address);
3729
3730 if (phy_info) {
3731 mptsas_del_end_device(ioc, phy_info);
3732 goto redo_device_scan;
3733 }
3734 } else
3735 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303736 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003737 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303738
3739 /* expanders */
3740 mutex_lock(&ioc->sas_topology_mutex);
3741 redo_expander_scan:
3742 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3743
3744 if (port_info->phy_info &&
3745 (!(port_info->phy_info[0].identify.device_info &
3746 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3747 continue;
3748 found_expander = 0;
3749 handle = 0xFFFF;
3750 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3751 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3752 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3753 !found_expander) {
3754
3755 handle = buffer.phy_info[0].handle;
3756 if (buffer.phy_info[0].identify.sas_address ==
3757 port_info->phy_info[0].identify.sas_address) {
3758 found_expander = 1;
3759 }
3760 kfree(buffer.phy_info);
3761 }
3762
3763 if (!found_expander) {
3764 mptsas_expander_delete(ioc, port_info, 0);
3765 goto redo_expander_scan;
3766 }
3767 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003768 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303769}
3770
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303771/**
3772 * mptsas_probe_expanders - adding expanders
3773 * @ioc: Pointer to MPT_ADAPTER structure
3774 *
3775 **/
3776static void
3777mptsas_probe_expanders(MPT_ADAPTER *ioc)
3778{
3779 struct mptsas_portinfo buffer, *port_info;
3780 u32 handle;
3781 int i;
3782
3783 handle = 0xFFFF;
3784 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3785 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3786 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3787
3788 handle = buffer.phy_info[0].handle;
3789 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3790 buffer.phy_info[0].identify.sas_address);
3791
3792 if (port_info) {
3793 /* refreshing handles */
3794 for (i = 0; i < buffer.num_phys; i++) {
3795 port_info->phy_info[i].handle = handle;
3796 port_info->phy_info[i].identify.handle_parent =
3797 buffer.phy_info[0].identify.handle_parent;
3798 }
3799 mptsas_expander_refresh(ioc, port_info);
3800 kfree(buffer.phy_info);
3801 continue;
3802 }
3803
3804 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3805 if (!port_info) {
3806 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3807 "%s: exit at line=%d\n", ioc->name,
3808 __func__, __LINE__));
3809 return;
3810 }
3811 port_info->num_phys = buffer.num_phys;
3812 port_info->phy_info = buffer.phy_info;
3813 for (i = 0; i < port_info->num_phys; i++)
3814 port_info->phy_info[i].portinfo = port_info;
3815 mutex_lock(&ioc->sas_topology_mutex);
3816 list_add_tail(&port_info->list, &ioc->sas_topology);
3817 mutex_unlock(&ioc->sas_topology_mutex);
3818 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3819 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3820 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3821 mptsas_expander_refresh(ioc, port_info);
3822 }
3823}
3824
3825static void
3826mptsas_probe_devices(MPT_ADAPTER *ioc)
3827{
3828 u16 handle;
3829 struct mptsas_devinfo sas_device;
3830 struct mptsas_phyinfo *phy_info;
3831
3832 handle = 0xFFFF;
3833 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3834 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3835
3836 handle = sas_device.handle;
3837
3838 if ((sas_device.device_info &
3839 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3840 MPI_SAS_DEVICE_INFO_STP_TARGET |
3841 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3842 continue;
3843
Kashyap, Desai51106ab2010-06-17 14:40:10 +05303844 /* If there is no FW B_T mapping for this device then continue
3845 * */
3846 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
3847 || !(sas_device.flags &
3848 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
3849 continue;
3850
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303851 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3852 if (!phy_info)
3853 continue;
3854
3855 if (mptsas_get_rphy(phy_info))
3856 continue;
3857
3858 mptsas_add_end_device(ioc, phy_info);
3859 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003860}
3861
Kashyap, Desai2f187862009-05-29 16:52:37 +05303862/**
3863 * mptsas_scan_sas_topology -
3864 * @ioc: Pointer to MPT_ADAPTER structure
3865 * @sas_address:
3866 *
3867 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003868static void
3869mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3870{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303871 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003872 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003873
Moore, Erice6b2d762006-03-14 09:14:24 -07003874 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303875 mptsas_probe_expanders(ioc);
3876 mptsas_probe_devices(ioc);
3877
Moore, Ericf44e5462006-03-14 09:14:21 -07003878 /*
3879 Reporting RAID volumes.
3880 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303881 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3882 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3883 return;
Eric Moore793955f2007-01-29 09:42:20 -07003884 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303885 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3886 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3887 if (sdev) {
3888 scsi_device_put(sdev);
3889 continue;
3890 }
3891 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3892 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3893 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003894 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003895 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3896 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003897}
3898
Kashyap, Desai57e98512009-05-29 16:55:09 +05303899
3900static void
3901mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3902{
3903 MPT_ADAPTER *ioc;
3904 EventDataQueueFull_t *qfull_data;
3905 struct mptsas_device_info *sas_info;
3906 struct scsi_device *sdev;
3907 int depth;
3908 int id = -1;
3909 int channel = -1;
3910 int fw_id, fw_channel;
3911 u16 current_depth;
3912
3913
3914 ioc = fw_event->ioc;
3915 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3916 fw_id = qfull_data->TargetID;
3917 fw_channel = qfull_data->Bus;
3918 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3919
3920 /* if hidden raid component, look for the volume id */
3921 mutex_lock(&ioc->sas_device_info_mutex);
3922 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3923 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3924 list) {
3925 if (sas_info->is_cached ||
3926 sas_info->is_logical_volume)
3927 continue;
3928 if (sas_info->is_hidden_raid_component &&
3929 (sas_info->fw.channel == fw_channel &&
3930 sas_info->fw.id == fw_id)) {
3931 id = sas_info->volume_id;
3932 channel = MPTSAS_RAID_CHANNEL;
3933 goto out;
3934 }
3935 }
3936 } else {
3937 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3938 list) {
3939 if (sas_info->is_cached ||
3940 sas_info->is_hidden_raid_component ||
3941 sas_info->is_logical_volume)
3942 continue;
3943 if (sas_info->fw.channel == fw_channel &&
3944 sas_info->fw.id == fw_id) {
3945 id = sas_info->os.id;
3946 channel = sas_info->os.channel;
3947 goto out;
3948 }
3949 }
3950
3951 }
3952
3953 out:
3954 mutex_unlock(&ioc->sas_device_info_mutex);
3955
3956 if (id != -1) {
3957 shost_for_each_device(sdev, ioc->sh) {
3958 if (sdev->id == id && sdev->channel == channel) {
3959 if (current_depth > sdev->queue_depth) {
3960 sdev_printk(KERN_INFO, sdev,
3961 "strange observation, the queue "
3962 "depth is (%d) meanwhile fw queue "
3963 "depth (%d)\n", sdev->queue_depth,
3964 current_depth);
3965 continue;
3966 }
3967 depth = scsi_track_queue_full(sdev,
3968 current_depth - 1);
3969 if (depth > 0)
3970 sdev_printk(KERN_INFO, sdev,
3971 "Queue depth reduced to (%d)\n",
3972 depth);
3973 else if (depth < 0)
3974 sdev_printk(KERN_INFO, sdev,
3975 "Tagged Command Queueing is being "
3976 "disabled\n");
3977 else if (depth == 0)
3978 sdev_printk(KERN_INFO, sdev,
3979 "Queue depth not changed yet\n");
3980 }
3981 }
3982 }
3983
3984 mptsas_free_fw_event(ioc, fw_event);
3985}
3986
3987
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003988static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003989mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003990{
3991 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003992 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003993 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003994
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003995 mutex_lock(&ioc->sas_topology_mutex);
3996 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3997 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003998 if (!mptsas_is_end_device(
3999 &port_info->phy_info[i].attached))
4000 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004001 if (port_info->phy_info[i].attached.sas_address
4002 != sas_address)
4003 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06004004 phy_info = &port_info->phy_info[i];
4005 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004006 }
4007 }
4008 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004009 return phy_info;
4010}
4011
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304012/**
4013 * mptsas_find_phyinfo_by_phys_disk_num -
4014 * @ioc: Pointer to MPT_ADAPTER structure
4015 * @phys_disk_num:
4016 * @channel:
4017 * @id:
4018 *
4019 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004020static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304021mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4022 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004023{
Eric Mooreb506ade2007-01-29 09:45:37 -07004024 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304025 struct mptsas_portinfo *port_info;
4026 RaidPhysDiskPage1_t *phys_disk = NULL;
4027 int num_paths;
4028 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004029 int i;
4030
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304031 phy_info = NULL;
4032 if (!ioc->raid_data.pIocPg3)
4033 return NULL;
4034 /* dual port support */
4035 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4036 if (!num_paths)
4037 goto out;
4038 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4039 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4040 if (!phys_disk)
4041 goto out;
4042 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4043 for (i = 0; i < num_paths; i++) {
4044 if ((phys_disk->Path[i].Flags & 1) != 0)
4045 /* entry no longer valid */
4046 continue;
4047 if ((id == phys_disk->Path[i].PhysDiskID) &&
4048 (channel == phys_disk->Path[i].PhysDiskBus)) {
4049 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4050 sizeof(u64));
4051 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4052 sas_address);
4053 goto out;
4054 }
4055 }
4056
4057 out:
4058 kfree(phys_disk);
4059 if (phy_info)
4060 return phy_info;
4061
4062 /*
4063 * Extra code to handle RAID0 case, where the sas_address is not updated
4064 * in phys_disk_page_1 when hotswapped
4065 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004066 mutex_lock(&ioc->sas_topology_mutex);
4067 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304068 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004069 if (!mptsas_is_end_device(
4070 &port_info->phy_info[i].attached))
4071 continue;
4072 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4073 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304074 if ((port_info->phy_info[i].attached.phys_disk_num ==
4075 phys_disk_num) &&
4076 (port_info->phy_info[i].attached.id == id) &&
4077 (port_info->phy_info[i].attached.channel ==
4078 channel))
4079 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004080 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004081 }
4082 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004083 return phy_info;
4084}
4085
4086static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004087mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4088{
Eric Mooref99be432007-01-04 20:46:54 -07004089 int rc;
4090
Moore, Ericf44e5462006-03-14 09:14:21 -07004091 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004092 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004093}
4094
4095static void
4096mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4097{
4098 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4099 mptsas_reprobe_lun);
4100}
4101
Eric Mooreb506ade2007-01-29 09:45:37 -07004102static void
4103mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4104{
4105 CONFIGPARMS cfg;
4106 ConfigPageHeader_t hdr;
4107 dma_addr_t dma_handle;
4108 pRaidVolumePage0_t buffer = NULL;
4109 RaidPhysDiskPage0_t phys_disk;
4110 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304111 struct mptsas_phyinfo *phy_info;
4112 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004113
4114 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4115 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4116 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4117 cfg.pageAddr = (channel << 8) + id;
4118 cfg.cfghdr.hdr = &hdr;
4119 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai568da762010-03-18 19:23:50 +05304120 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Eric Mooreb506ade2007-01-29 09:45:37 -07004121
4122 if (mpt_config(ioc, &cfg) != 0)
4123 goto out;
4124
4125 if (!hdr.PageLength)
4126 goto out;
4127
4128 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4129 &dma_handle);
4130
4131 if (!buffer)
4132 goto out;
4133
4134 cfg.physAddr = dma_handle;
4135 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4136
4137 if (mpt_config(ioc, &cfg) != 0)
4138 goto out;
4139
4140 if (!(buffer->VolumeStatus.Flags &
4141 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4142 goto out;
4143
4144 if (!buffer->NumPhysDisks)
4145 goto out;
4146
4147 for (i = 0; i < buffer->NumPhysDisks; i++) {
4148
4149 if (mpt_raid_phys_disk_pg0(ioc,
4150 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4151 continue;
4152
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304153 if (mptsas_sas_device_pg0(ioc, &sas_device,
4154 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4155 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4156 (phys_disk.PhysDiskBus << 8) +
4157 phys_disk.PhysDiskID))
4158 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004159
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304160 /* If there is no FW B_T mapping for this device then continue
4161 * */
4162 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4163 || !(sas_device.flags &
4164 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4165 continue;
4166
4167
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304168 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4169 sas_device.sas_address);
4170 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004171 }
4172
4173 out:
4174 if (buffer)
4175 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4176 dma_handle);
4177}
Moore, Erice6b2d762006-03-14 09:14:24 -07004178/*
4179 * Work queue thread to handle SAS hotplug events
4180 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004181static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304182mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4183 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004184{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004185 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004186 struct scsi_target * starget;
Moore, Ericc73787e2006-01-26 16:20:06 -07004187 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004188 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304189 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06004190
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304191 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004192
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304193 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004194
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304195 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004196 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004197
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304198 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4199 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4200 hot_plug_info->id) {
4201 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4202 "to add hidden disk - target_id matchs "
4203 "volume_id\n", ioc->name);
4204 mptsas_free_fw_event(ioc, fw_event);
4205 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004206 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004207 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304208 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004209
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004210 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304211 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4212 mptsas_sas_device_pg0(ioc, &sas_device,
4213 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4214 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4215 (hot_plug_info->channel << 8) +
4216 hot_plug_info->id);
Moore, Ericc73787e2006-01-26 16:20:06 -07004217
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304218 /* If there is no FW B_T mapping for this device then break
4219 * */
4220 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4221 || !(sas_device.flags &
4222 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4223 break;
4224
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304225 if (!sas_device.handle)
4226 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004227
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304228 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4229 if (!phy_info)
4230 break;
4231
4232 if (mptsas_get_rphy(phy_info))
4233 break;
4234
4235 mptsas_add_end_device(ioc, phy_info);
4236 break;
4237
4238 case MPTSAS_DEL_DEVICE:
4239 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4240 hot_plug_info->sas_address);
4241 mptsas_del_end_device(ioc, phy_info);
4242 break;
4243
4244 case MPTSAS_DEL_PHYSDISK:
4245
4246 mpt_findImVolumes(ioc);
4247
4248 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304249 ioc, hot_plug_info->phys_disk_num,
4250 hot_plug_info->channel,
4251 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304252 mptsas_del_end_device(ioc, phy_info);
4253 break;
4254
4255 case MPTSAS_ADD_PHYSDISK_REPROBE:
4256
Christoph Hellwige3094442006-02-16 13:25:36 +01004257 if (mptsas_sas_device_pg0(ioc, &sas_device,
4258 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004259 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304260 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4261 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4262 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4263 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004264 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004265 }
4266
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304267 /* If there is no FW B_T mapping for this device then break
4268 * */
4269 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4270 || !(sas_device.flags &
4271 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4272 break;
4273
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304274 phy_info = mptsas_find_phyinfo_by_sas_address(
4275 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004276
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304277 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304278 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304279 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4280 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004281 break;
4282 }
4283
4284 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304285 if (!starget) {
4286 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4287 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4288 __func__, hot_plug_info->id, __LINE__));
4289 break;
4290 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004291
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304292 vtarget = starget->hostdata;
4293 if (!vtarget) {
4294 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4295 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4296 __func__, hot_plug_info->id, __LINE__));
4297 break;
4298 }
Eric Moore547f9a22006-06-27 14:42:12 -06004299
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304300 mpt_findImVolumes(ioc);
4301
4302 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4303 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4304 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4305 hot_plug_info->phys_disk_num, (unsigned long long)
4306 sas_device.sas_address);
4307
4308 vtarget->id = hot_plug_info->phys_disk_num;
4309 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4310 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4311 mptsas_reprobe_target(starget, 1);
4312 break;
4313
4314 case MPTSAS_DEL_PHYSDISK_REPROBE:
4315
4316 if (mptsas_sas_device_pg0(ioc, &sas_device,
4317 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4318 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4319 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304320 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304321 "%s: fw_id=%d exit at line=%d\n",
4322 ioc->name, __func__,
4323 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004324 break;
4325 }
4326
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304327 /* If there is no FW B_T mapping for this device then break
4328 * */
4329 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4330 || !(sas_device.flags &
4331 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4332 break;
4333
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304334 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4335 sas_device.sas_address);
4336 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304337 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304338 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4339 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004340 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004341 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004342
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304343 starget = mptsas_get_starget(phy_info);
4344 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304345 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304346 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4347 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004348 break;
4349 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004350
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304351 vtarget = starget->hostdata;
4352 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304353 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304354 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4355 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004356 break;
4357 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304358
4359 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4360 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4361 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4362 __func__, hot_plug_info->id, __LINE__));
4363 break;
4364 }
4365
4366 mpt_findImVolumes(ioc);
4367
4368 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4369 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4370 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4371 hot_plug_info->phys_disk_num, (unsigned long long)
4372 sas_device.sas_address);
4373
4374 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4375 vtarget->id = hot_plug_info->id;
4376 phy_info->attached.phys_disk_num = ~0;
4377 mptsas_reprobe_target(starget, 0);
4378 mptsas_add_device_component_by_fw(ioc,
4379 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004380 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304381
Moore, Ericc73787e2006-01-26 16:20:06 -07004382 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304383
Moore, Ericc73787e2006-01-26 16:20:06 -07004384 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304385 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4386 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4387 hot_plug_info->id);
4388 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4389 hot_plug_info->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07004390 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304391
Moore, Ericc73787e2006-01-26 16:20:06 -07004392 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304393
Moore, Ericc73787e2006-01-26 16:20:06 -07004394 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304395 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4396 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4397 hot_plug_info->id);
4398 scsi_remove_device(hot_plug_info->sdev);
4399 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787e2006-01-26 16:20:06 -07004400 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304401
Eric Mooreb506ade2007-01-29 09:45:37 -07004402 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304403
4404 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004405 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304406 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004407 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304408
Moore, Ericbd23e942006-04-17 12:43:04 -06004409 default:
4410 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004411 }
4412
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304413 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004414}
4415
4416static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304417mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004418{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304419 MPT_ADAPTER *ioc;
4420 struct mptsas_hotplug_event hot_plug_info;
4421 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4422 u32 device_info;
4423 u64 sas_address;
4424
4425 ioc = fw_event->ioc;
4426 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4427 fw_event->event_data;
4428 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004429
4430 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304431 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4432 MPI_SAS_DEVICE_INFO_STP_TARGET |
4433 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4434 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004435 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304436 }
4437
4438 if (sas_event_data->ReasonCode ==
4439 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4440 mptbase_sas_persist_operation(ioc,
4441 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4442 mptsas_free_fw_event(ioc, fw_event);
4443 return;
4444 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004445
Moore, Eric4b766472006-03-14 09:14:12 -07004446 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004447 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004448 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304449 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4450 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4451 hot_plug_info.channel = sas_event_data->Bus;
4452 hot_plug_info.id = sas_event_data->TargetID;
4453 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004454 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304455 sizeof(u64));
4456 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4457 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004458 if (sas_event_data->ReasonCode &
4459 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304460 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004461 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304462 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4463 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004464 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304465
Moore, Eric4b766472006-03-14 09:14:12 -07004466 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304467 mptbase_sas_persist_operation(ioc,
4468 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4469 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004470 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304471
Moore, Eric4b766472006-03-14 09:14:12 -07004472 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304473 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004474 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304475 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004476 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304477 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004478 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004479 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004480}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304481
Moore, Ericc73787e2006-01-26 16:20:06 -07004482static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304483mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787e2006-01-26 16:20:06 -07004484{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304485 MPT_ADAPTER *ioc;
4486 EVENT_DATA_RAID *raid_event_data;
4487 struct mptsas_hotplug_event hot_plug_info;
4488 int status;
4489 int state;
4490 struct scsi_device *sdev = NULL;
4491 VirtDevice *vdevice = NULL;
4492 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787e2006-01-26 16:20:06 -07004493
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304494 ioc = fw_event->ioc;
4495 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4496 status = le32_to_cpu(raid_event_data->SettingsStatus);
4497 state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07004498
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304499 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4500 hot_plug_info.id = raid_event_data->VolumeID;
4501 hot_plug_info.channel = raid_event_data->VolumeBus;
4502 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4503
4504 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4505 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4506 raid_event_data->ReasonCode ==
4507 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4508 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4509 hot_plug_info.id, 0);
4510 hot_plug_info.sdev = sdev;
4511 if (sdev)
4512 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07004513 }
4514
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304515 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4516 "ReasonCode=%02x\n", ioc->name, __func__,
4517 raid_event_data->ReasonCode));
Moore, Ericc73787e2006-01-26 16:20:06 -07004518
4519 switch (raid_event_data->ReasonCode) {
4520 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304521 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004522 break;
4523 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304524 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004525 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004526 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4527 switch (state) {
4528 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004529 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304530 mpt_raid_phys_disk_pg0(ioc,
4531 raid_event_data->PhysDiskNum, &phys_disk);
4532 hot_plug_info.id = phys_disk.PhysDiskID;
4533 hot_plug_info.channel = phys_disk.PhysDiskBus;
4534 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004535 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304536 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004537 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004538 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4539 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4540 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304541 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004542 break;
4543 default:
4544 break;
4545 }
4546 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07004547 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304548 if (!sdev)
4549 break;
4550 vdevice->vtarget->deleted = 1; /* block IO */
4551 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004552 break;
4553 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304554 if (sdev) {
4555 scsi_device_put(sdev);
4556 break;
4557 }
4558 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004559 break;
4560 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304561 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4562 if (!sdev)
4563 break;
4564 vdevice->vtarget->deleted = 1; /* block IO */
4565 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4566 break;
4567 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004568 switch (state) {
4569 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4570 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304571 if (!sdev)
4572 break;
4573 vdevice->vtarget->deleted = 1; /* block IO */
4574 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004575 break;
4576 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4577 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304578 if (sdev) {
4579 scsi_device_put(sdev);
4580 break;
4581 }
4582 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004583 break;
4584 default:
4585 break;
4586 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004587 break;
4588 default:
4589 break;
4590 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304591
4592 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4593 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4594 else
4595 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787e2006-01-26 16:20:06 -07004596}
4597
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304598/**
4599 * mptsas_issue_tm - send mptsas internal tm request
4600 * @ioc: Pointer to MPT_ADAPTER structure
4601 * @type: Task Management type
4602 * @channel: channel number for task management
4603 * @id: Logical Target ID for reset (if appropriate)
4604 * @lun: Logical unit for reset (if appropriate)
4605 * @task_context: Context for the task to be aborted
4606 * @timeout: timeout for task management control
4607 *
4608 * return 0 on success and -1 on failure:
4609 *
4610 */
4611static int
4612mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4613 int task_context, ulong timeout, u8 *issue_reset)
4614{
4615 MPT_FRAME_HDR *mf;
4616 SCSITaskMgmt_t *pScsiTm;
4617 int retval;
4618 unsigned long timeleft;
4619
4620 *issue_reset = 0;
4621 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4622 if (mf == NULL) {
4623 retval = -1; /* return failure */
4624 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4625 "msg frames!!\n", ioc->name));
4626 goto out;
4627 }
4628
4629 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4630 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4631 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4632 type, timeout, channel, id, (unsigned long long)lun,
4633 task_context));
4634
4635 pScsiTm = (SCSITaskMgmt_t *) mf;
4636 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4637 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4638 pScsiTm->TaskType = type;
4639 pScsiTm->MsgFlags = 0;
4640 pScsiTm->TargetID = id;
4641 pScsiTm->Bus = channel;
4642 pScsiTm->ChainOffset = 0;
4643 pScsiTm->Reserved = 0;
4644 pScsiTm->Reserved1 = 0;
4645 pScsiTm->TaskMsgContext = task_context;
4646 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4647
4648 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4649 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4650 retval = 0;
4651 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4652
4653 /* Now wait for the command to complete */
4654 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4655 timeout*HZ);
4656 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4657 retval = -1; /* return failure */
4658 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4659 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4660 mpt_free_msg_frame(ioc, mf);
4661 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4662 goto out;
4663 *issue_reset = 1;
4664 goto out;
4665 }
4666
4667 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4668 retval = -1; /* return failure */
4669 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4670 "TaskMgmt request: failed with no reply\n", ioc->name));
4671 goto out;
4672 }
4673
4674 out:
4675 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4676 return retval;
4677}
4678
4679/**
4680 * mptsas_broadcast_primative_work - Handle broadcast primitives
4681 * @work: work queue payload containing info describing the event
4682 *
4683 * this will be handled in workqueue context.
4684 */
4685static void
4686mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4687{
4688 MPT_ADAPTER *ioc = fw_event->ioc;
4689 MPT_FRAME_HDR *mf;
4690 VirtDevice *vdevice;
4691 int ii;
4692 struct scsi_cmnd *sc;
4693 SCSITaskMgmtReply_t *pScsiTmReply;
4694 u8 issue_reset;
4695 int task_context;
4696 u8 channel, id;
4697 int lun;
4698 u32 termination_count;
4699 u32 query_count;
4700
4701 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4702 "%s - enter\n", ioc->name, __func__));
4703
4704 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4705 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4706 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4707 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4708 return;
4709 }
4710
4711 issue_reset = 0;
4712 termination_count = 0;
4713 query_count = 0;
4714 mpt_findImVolumes(ioc);
4715 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4716
4717 for (ii = 0; ii < ioc->req_depth; ii++) {
4718 if (ioc->fw_events_off)
4719 goto out;
4720 sc = mptscsih_get_scsi_lookup(ioc, ii);
4721 if (!sc)
4722 continue;
4723 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4724 if (!mf)
4725 continue;
4726 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4727 vdevice = sc->device->hostdata;
4728 if (!vdevice || !vdevice->vtarget)
4729 continue;
4730 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4731 continue; /* skip hidden raid components */
4732 if (vdevice->vtarget->raidVolume)
4733 continue; /* skip hidden raid components */
4734 channel = vdevice->vtarget->channel;
4735 id = vdevice->vtarget->id;
4736 lun = vdevice->lun;
4737 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4738 channel, id, (u64)lun, task_context, 30, &issue_reset))
4739 goto out;
4740 query_count++;
4741 termination_count +=
4742 le32_to_cpu(pScsiTmReply->TerminationCount);
4743 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4744 (pScsiTmReply->ResponseCode ==
4745 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4746 pScsiTmReply->ResponseCode ==
4747 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4748 continue;
4749 if (mptsas_issue_tm(ioc,
4750 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4751 channel, id, (u64)lun, 0, 30, &issue_reset))
4752 goto out;
4753 termination_count +=
4754 le32_to_cpu(pScsiTmReply->TerminationCount);
4755 }
4756
4757 out:
4758 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4759 "%s - exit, query_count = %d termination_count = %d\n",
4760 ioc->name, __func__, query_count, termination_count));
4761
4762 ioc->broadcast_aen_busy = 0;
4763 mpt_clear_taskmgmt_in_progress_flag(ioc);
4764 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4765
4766 if (issue_reset) {
4767 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4768 ioc->name, __func__);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304769 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304770 }
4771 mptsas_free_fw_event(ioc, fw_event);
4772}
4773
Eric Mooreb506ade2007-01-29 09:45:37 -07004774/*
4775 * mptsas_send_ir2_event - handle exposing hidden disk when
4776 * an inactive raid volume is added
4777 *
4778 * @ioc: Pointer to MPT_ADAPTER structure
4779 * @ir2_data
4780 *
4781 */
4782static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304783mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004784{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304785 MPT_ADAPTER *ioc;
4786 struct mptsas_hotplug_event hot_plug_info;
4787 MPI_EVENT_DATA_IR2 *ir2_data;
4788 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304789 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004790
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304791 ioc = fw_event->ioc;
4792 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4793 reasonCode = ir2_data->ReasonCode;
4794
4795 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4796 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4797
4798 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4799 hot_plug_info.id = ir2_data->TargetID;
4800 hot_plug_info.channel = ir2_data->Bus;
4801 switch (reasonCode) {
4802 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4803 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4804 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304805 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4806 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4807 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4808 break;
4809 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4810 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4811 mpt_raid_phys_disk_pg0(ioc,
4812 ir2_data->PhysDiskNum, &phys_disk);
4813 hot_plug_info.id = phys_disk.PhysDiskID;
4814 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4815 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304816 default:
4817 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004818 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304819 }
4820 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4821}
Moore, Erice6b2d762006-03-14 09:14:24 -07004822
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004823static int
4824mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4825{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304826 u32 event = le32_to_cpu(reply->Event);
4827 int sz, event_data_sz;
4828 struct fw_event_work *fw_event;
4829 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004830
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304831 if (ioc->bus_type != SAS)
4832 return 0;
4833
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304834 /* events turned off due to host reset or driver unloading */
4835 if (ioc->fw_events_off)
4836 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004837
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304838 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004839 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304840 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4841 {
4842 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4843 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4844 if (broadcast_event_data->Primitive !=
4845 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4846 return 0;
4847 if (ioc->broadcast_aen_busy)
4848 return 0;
4849 ioc->broadcast_aen_busy = 1;
4850 break;
4851 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004852 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304853 {
4854 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4855 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4856
4857 if (sas_event_data->ReasonCode ==
4858 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4859 mptsas_target_reset_queue(ioc, sas_event_data);
4860 return 0;
4861 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004862 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304863 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304864 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4865 {
4866 MpiEventDataSasExpanderStatusChange_t *expander_data =
4867 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4868
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304869 if (ioc->old_sas_discovery_protocal)
4870 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304871
4872 if (expander_data->ReasonCode ==
4873 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4874 ioc->device_missing_delay)
4875 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004876 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304877 }
4878 case MPI_EVENT_SAS_DISCOVERY:
4879 {
4880 u32 discovery_status;
4881 EventDataSasDiscovery_t *discovery_data =
4882 (EventDataSasDiscovery_t *)reply->Data;
4883
4884 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4885 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304886 if (ioc->old_sas_discovery_protocal && !discovery_status)
4887 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304888 return 0;
4889 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304890 case MPI_EVENT_INTEGRATED_RAID:
4891 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004892 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304893 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4894 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004895 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004896 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304897 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004898 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004899
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304900 event_data_sz = ((reply->MsgLength * 4) -
4901 offsetof(EventNotificationReply_t, Data));
4902 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4903 fw_event = kzalloc(sz, GFP_ATOMIC);
4904 if (!fw_event) {
4905 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4906 __func__, __LINE__);
4907 return 0;
4908 }
4909 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4910 fw_event->event = event;
4911 fw_event->ioc = ioc;
4912 mptsas_add_fw_event(ioc, fw_event, delay);
4913 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004914}
4915
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304916/* Delete a volume when no longer listed in ioc pg2
4917 */
4918static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4919{
4920 struct scsi_device *sdev;
4921 int i;
4922
4923 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4924 if (!sdev)
4925 return;
4926 if (!ioc->raid_data.pIocPg2)
4927 goto out;
4928 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4929 goto out;
4930 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4931 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4932 goto release_sdev;
4933 out:
4934 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4935 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4936 scsi_remove_device(sdev);
4937 release_sdev:
4938 scsi_device_put(sdev);
4939}
4940
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004941static int
4942mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4943{
4944 struct Scsi_Host *sh;
4945 MPT_SCSI_HOST *hd;
4946 MPT_ADAPTER *ioc;
4947 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004948 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004949 int numSGE = 0;
4950 int scale;
4951 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004952 int error=0;
4953 int r;
4954
4955 r = mpt_attach(pdev,id);
4956 if (r)
4957 return r;
4958
4959 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304960 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004961 ioc->DoneCtx = mptsasDoneCtx;
4962 ioc->TaskCtx = mptsasTaskCtx;
4963 ioc->InternalCtx = mptsasInternalCtx;
4964
4965 /* Added sanity check on readiness of the MPT adapter.
4966 */
4967 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4968 printk(MYIOC_s_WARN_FMT
4969 "Skipping because it's not operational!\n",
4970 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004971 error = -ENODEV;
4972 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004973 }
4974
4975 if (!ioc->active) {
4976 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4977 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004978 error = -ENODEV;
4979 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004980 }
4981
4982 /* Sanity check - ensure at least 1 port is INITIATOR capable
4983 */
4984 ioc_cap = 0;
4985 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4986 if (ioc->pfacts[ii].ProtocolFlags &
4987 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4988 ioc_cap++;
4989 }
4990
4991 if (!ioc_cap) {
4992 printk(MYIOC_s_WARN_FMT
4993 "Skipping ioc=%p because SCSI Initiator mode "
4994 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004995 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004996 }
4997
4998 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4999 if (!sh) {
5000 printk(MYIOC_s_WARN_FMT
5001 "Unable to register controller with SCSI subsystem\n",
5002 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005003 error = -1;
5004 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005005 }
5006
5007 spin_lock_irqsave(&ioc->FreeQlock, flags);
5008
5009 /* Attach the SCSI Host to the IOC structure
5010 */
5011 ioc->sh = sh;
5012
5013 sh->io_port = 0;
5014 sh->n_io_port = 0;
5015 sh->irq = 0;
5016
5017 /* set 16 byte cdb's */
5018 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05305019 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5020 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07005021 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005022 sh->transportt = mptsas_transport_template;
5023
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005024 /* Required entry.
5025 */
5026 sh->unique_id = ioc->id;
5027
5028 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005029 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07005030 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01005031 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005032 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005033
5034 /* Verify that we won't exceed the maximum
5035 * number of chain buffers
5036 * We can optimize: ZZ = req_sz/sizeof(SGE)
5037 * For 32bit SGE's:
5038 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5039 * + (req_sz - 64)/sizeof(SGE)
5040 * A slightly different algorithm is required for
5041 * 64bit SGEs.
5042 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305043 scale = ioc->req_sz/ioc->SGE_size;
5044 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005045 numSGE = (scale - 1) *
5046 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305047 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005048 } else {
5049 numSGE = 1 + (scale - 1) *
5050 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305051 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005052 }
5053
5054 if (numSGE < sh->sg_tablesize) {
5055 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305056 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005057 "Resetting sg_tablesize to %d from %d\n",
5058 ioc->name, numSGE, sh->sg_tablesize));
5059 sh->sg_tablesize = numSGE;
5060 }
5061
Eric Mooree7eae9f2007-09-29 10:15:59 -06005062 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005063 hd->ioc = ioc;
5064
5065 /* SCSI needs scsi_cmnd lookup table!
5066 * (with size equal to req_depth*PtrSz!)
5067 */
Eric Mooree8206382007-09-29 10:16:53 -06005068 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5069 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005070 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005071 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005072 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005073 }
Eric Mooree8206382007-09-29 10:16:53 -06005074 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005075
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305076 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005077 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005078
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005079 ioc->sas_data.ptClear = mpt_pt_clear;
5080
Eric Mooredf9e0622007-01-29 09:46:21 -07005081 hd->last_queue_full = 0;
5082 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305083 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5084 mutex_init(&ioc->sas_device_info_mutex);
5085
Eric Mooredf9e0622007-01-29 09:46:21 -07005086 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5087
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005088 if (ioc->sas_data.ptClear==1) {
5089 mptbase_sas_persist_operation(
5090 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5091 }
5092
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005093 error = scsi_add_host(sh, &ioc->pcidev->dev);
5094 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005095 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5096 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005097 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005098 }
5099
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305100 /* older firmware doesn't support expander events */
5101 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5102 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005103 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305104 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005105 return 0;
5106
Eric Moore547f9a22006-06-27 14:42:12 -06005107 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005108
5109 mptscsih_remove(pdev);
5110 return error;
5111}
5112
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305113void
5114mptsas_shutdown(struct pci_dev *pdev)
5115{
5116 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5117
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305118 mptsas_fw_event_off(ioc);
5119 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305120}
5121
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005122static void __devexit mptsas_remove(struct pci_dev *pdev)
5123{
5124 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5125 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005126 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005127
Kashyap, Desai48959f12010-03-18 19:18:30 +05305128 if (!ioc->sh) {
5129 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5130 mpt_detach(pdev);
5131 return;
5132 }
5133
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305134 mptsas_shutdown(pdev);
5135
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305136 mptsas_del_device_components(ioc);
5137
Eric Mooreb506ade2007-01-29 09:45:37 -07005138 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005139 sas_remove_host(ioc->sh);
5140
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005141 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005142 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5143 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005144 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305145 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305146
Eric Moore547f9a22006-06-27 14:42:12 -06005147 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005148 kfree(p);
5149 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005150 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305151 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005152 mptscsih_remove(pdev);
5153}
5154
5155static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005156 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005157 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005158 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005159 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005160 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005161 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005162 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005163 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005164 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005165 PCI_ANY_ID, PCI_ANY_ID },
5166 {0} /* Terminating entry */
5167};
5168MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5169
5170
5171static struct pci_driver mptsas_driver = {
5172 .name = "mptsas",
5173 .id_table = mptsas_pci_table,
5174 .probe = mptsas_probe,
5175 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305176 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005177#ifdef CONFIG_PM
5178 .suspend = mptscsih_suspend,
5179 .resume = mptscsih_resume,
5180#endif
5181};
5182
5183static int __init
5184mptsas_init(void)
5185{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305186 int error;
5187
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005188 show_mptmod_ver(my_NAME, my_VERSION);
5189
5190 mptsas_transport_template =
5191 sas_attach_transport(&mptsas_transport_functions);
5192 if (!mptsas_transport_template)
5193 return -ENODEV;
5194
5195 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305196 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005197 mptsasInternalCtx =
5198 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005199 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305200 mptsasDeviceResetCtx =
5201 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005202
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305203 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5204 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005205
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305206 error = pci_register_driver(&mptsas_driver);
5207 if (error)
5208 sas_release_transport(mptsas_transport_template);
5209
5210 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005211}
5212
5213static void __exit
5214mptsas_exit(void)
5215{
5216 pci_unregister_driver(&mptsas_driver);
5217 sas_release_transport(mptsas_transport_template);
5218
5219 mpt_reset_deregister(mptsasDoneCtx);
5220 mpt_event_deregister(mptsasDoneCtx);
5221
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005222 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005223 mpt_deregister(mptsasInternalCtx);
5224 mpt_deregister(mptsasTaskCtx);
5225 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305226 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005227}
5228
5229module_init(mptsas_init);
5230module_exit(mptsas_exit);