blob: 7f217445cd93a2c6810098c5deb2dbddb0995f34 [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,
1897 .name = "MPT SPI Host",
1898 .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);
2041 if (!timeleft) {
2042 /* On timeout reset the board */
2043 mpt_free_msg_frame(ioc, mf);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302044 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002045 error = -ETIMEDOUT;
2046 goto out_unlock;
2047 }
2048
2049 /* a reply frame is expected */
2050 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302051 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002052 error = -ENXIO;
2053 goto out_unlock;
2054 }
2055
2056 /* process the completed Reply Message Frame */
2057 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2058 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002059 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002060 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002061 error = -ENXIO;
2062 goto out_unlock;
2063 }
2064
2065 error = 0;
2066
2067 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302068 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002069 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002070 out:
2071 return error;
2072}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002073
Christoph Hellwige3094442006-02-16 13:25:36 +01002074static int
2075mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2076{
2077 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2078 int i, error;
2079 struct mptsas_portinfo *p;
2080 struct mptsas_enclosure enclosure_info;
2081 u64 enclosure_handle;
2082
2083 mutex_lock(&ioc->sas_topology_mutex);
2084 list_for_each_entry(p, &ioc->sas_topology, list) {
2085 for (i = 0; i < p->num_phys; i++) {
2086 if (p->phy_info[i].attached.sas_address ==
2087 rphy->identify.sas_address) {
2088 enclosure_handle = p->phy_info[i].
2089 attached.handle_enclosure;
2090 goto found_info;
2091 }
2092 }
2093 }
2094 mutex_unlock(&ioc->sas_topology_mutex);
2095 return -ENXIO;
2096
2097 found_info:
2098 mutex_unlock(&ioc->sas_topology_mutex);
2099 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002100 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002101 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2102 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2103 if (!error)
2104 *identifier = enclosure_info.enclosure_logical_id;
2105 return error;
2106}
2107
2108static int
2109mptsas_get_bay_identifier(struct sas_rphy *rphy)
2110{
2111 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2112 struct mptsas_portinfo *p;
2113 int i, rc;
2114
2115 mutex_lock(&ioc->sas_topology_mutex);
2116 list_for_each_entry(p, &ioc->sas_topology, list) {
2117 for (i = 0; i < p->num_phys; i++) {
2118 if (p->phy_info[i].attached.sas_address ==
2119 rphy->identify.sas_address) {
2120 rc = p->phy_info[i].attached.slot;
2121 goto out;
2122 }
2123 }
2124 }
2125 rc = -ENXIO;
2126 out:
2127 mutex_unlock(&ioc->sas_topology_mutex);
2128 return rc;
2129}
2130
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002131static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2132 struct request *req)
2133{
2134 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2135 MPT_FRAME_HDR *mf;
2136 SmpPassthroughRequest_t *smpreq;
2137 struct request *rsp = req->next_rq;
2138 int ret;
2139 int flagsLength;
2140 unsigned long timeleft;
2141 char *psge;
2142 dma_addr_t dma_addr_in = 0;
2143 dma_addr_t dma_addr_out = 0;
2144 u64 sas_address = 0;
2145
2146 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002147 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002148 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002149 return -EINVAL;
2150 }
2151
2152 /* do we need to support multiple segments? */
2153 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002154 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002155 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2156 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002157 return -EINVAL;
2158 }
2159
2160 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2161 if (ret)
2162 goto out;
2163
2164 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2165 if (!mf) {
2166 ret = -ENOMEM;
2167 goto out_unlock;
2168 }
2169
2170 smpreq = (SmpPassthroughRequest_t *)mf;
2171 memset(smpreq, 0, sizeof(*smpreq));
2172
Tejun Heob0790412009-05-07 22:24:42 +09002173 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002174 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2175
2176 if (rphy)
2177 sas_address = rphy->identify.sas_address;
2178 else {
2179 struct mptsas_portinfo *port_info;
2180
2181 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302182 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002183 if (port_info && port_info->phy_info)
2184 sas_address =
2185 port_info->phy_info[0].phy->identify.sas_address;
2186 mutex_unlock(&ioc->sas_topology_mutex);
2187 }
2188
2189 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2190
2191 psge = (char *)
2192 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2193
2194 /* request */
2195 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2196 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302197 MPI_SGE_FLAGS_DIRECTION)
2198 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002199 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002200
2201 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002202 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002203 if (!dma_addr_out)
2204 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302205 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302206 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002207
2208 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302209 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2210 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2211 MPI_SGE_FLAGS_IOC_TO_HOST |
2212 MPI_SGE_FLAGS_END_OF_BUFFER;
2213
2214 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002215 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002216 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002217 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002218 if (!dma_addr_in)
2219 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302220 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002221
Kashyap, Desai2f187862009-05-29 16:52:37 +05302222 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002223 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2224
2225 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2226 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002227 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002228 /* On timeout reset the board */
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302229 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002230 ret = -ETIMEDOUT;
2231 goto unmap;
2232 }
2233 mf = NULL;
2234
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302235 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002236 SmpPassthroughReply_t *smprep;
2237
2238 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2239 memcpy(req->sense, smprep, sizeof(*smprep));
2240 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002241 req->resid_len = 0;
2242 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002243 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302244 printk(MYIOC_s_ERR_FMT
2245 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002246 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002247 ret = -ENXIO;
2248 }
2249unmap:
2250 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002251 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002252 PCI_DMA_BIDIRECTIONAL);
2253 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002254 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002255 PCI_DMA_BIDIRECTIONAL);
2256put_mf:
2257 if (mf)
2258 mpt_free_msg_frame(ioc, mf);
2259out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302260 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002261 mutex_unlock(&ioc->sas_mgmt.mutex);
2262out:
2263 return ret;
2264}
2265
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002266static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002267 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002268 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2269 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002270 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002271 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002272};
2273
2274static struct scsi_transport_template *mptsas_transport_template;
2275
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002276static int
2277mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2278{
2279 ConfigExtendedPageHeader_t hdr;
2280 CONFIGPARMS cfg;
2281 SasIOUnitPage0_t *buffer;
2282 dma_addr_t dma_handle;
2283 int error, i;
2284
2285 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2286 hdr.ExtPageLength = 0;
2287 hdr.PageNumber = 0;
2288 hdr.Reserved1 = 0;
2289 hdr.Reserved2 = 0;
2290 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2291 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2292
2293 cfg.cfghdr.ehdr = &hdr;
2294 cfg.physAddr = -1;
2295 cfg.pageAddr = 0;
2296 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2297 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302298 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002299
2300 error = mpt_config(ioc, &cfg);
2301 if (error)
2302 goto out;
2303 if (!hdr.ExtPageLength) {
2304 error = -ENXIO;
2305 goto out;
2306 }
2307
2308 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2309 &dma_handle);
2310 if (!buffer) {
2311 error = -ENOMEM;
2312 goto out;
2313 }
2314
2315 cfg.physAddr = dma_handle;
2316 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2317
2318 error = mpt_config(ioc, &cfg);
2319 if (error)
2320 goto out_free_consistent;
2321
2322 port_info->num_phys = buffer->NumPhys;
2323 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302324 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002325 if (!port_info->phy_info) {
2326 error = -ENOMEM;
2327 goto out_free_consistent;
2328 }
2329
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302330 ioc->nvdata_version_persistent =
2331 le16_to_cpu(buffer->NvdataVersionPersistent);
2332 ioc->nvdata_version_default =
2333 le16_to_cpu(buffer->NvdataVersionDefault);
2334
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002335 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302336 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002337 port_info->phy_info[i].phy_id = i;
2338 port_info->phy_info[i].port_id =
2339 buffer->PhyData[i].Port;
2340 port_info->phy_info[i].negotiated_link_rate =
2341 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002342 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002343 port_info->phy_info[i].handle =
2344 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002345 }
2346
2347 out_free_consistent:
2348 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2349 buffer, dma_handle);
2350 out:
2351 return error;
2352}
2353
2354static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302355mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2356{
2357 ConfigExtendedPageHeader_t hdr;
2358 CONFIGPARMS cfg;
2359 SasIOUnitPage1_t *buffer;
2360 dma_addr_t dma_handle;
2361 int error;
2362 u16 device_missing_delay;
2363
2364 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2365 memset(&cfg, 0, sizeof(CONFIGPARMS));
2366
2367 cfg.cfghdr.ehdr = &hdr;
2368 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302369 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302370 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2371 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2372 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2373 cfg.cfghdr.ehdr->PageNumber = 1;
2374
2375 error = mpt_config(ioc, &cfg);
2376 if (error)
2377 goto out;
2378 if (!hdr.ExtPageLength) {
2379 error = -ENXIO;
2380 goto out;
2381 }
2382
2383 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2384 &dma_handle);
2385 if (!buffer) {
2386 error = -ENOMEM;
2387 goto out;
2388 }
2389
2390 cfg.physAddr = dma_handle;
2391 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2392
2393 error = mpt_config(ioc, &cfg);
2394 if (error)
2395 goto out_free_consistent;
2396
2397 ioc->io_missing_delay =
2398 le16_to_cpu(buffer->IODeviceMissingDelay);
2399 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2400 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2401 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2402 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2403
2404 out_free_consistent:
2405 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2406 buffer, dma_handle);
2407 out:
2408 return error;
2409}
2410
2411static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002412mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2413 u32 form, u32 form_specific)
2414{
2415 ConfigExtendedPageHeader_t hdr;
2416 CONFIGPARMS cfg;
2417 SasPhyPage0_t *buffer;
2418 dma_addr_t dma_handle;
2419 int error;
2420
2421 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2422 hdr.ExtPageLength = 0;
2423 hdr.PageNumber = 0;
2424 hdr.Reserved1 = 0;
2425 hdr.Reserved2 = 0;
2426 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2427 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2428
2429 cfg.cfghdr.ehdr = &hdr;
2430 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302431 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002432
2433 /* Get Phy Pg 0 for each Phy. */
2434 cfg.physAddr = -1;
2435 cfg.pageAddr = form + form_specific;
2436 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2437
2438 error = mpt_config(ioc, &cfg);
2439 if (error)
2440 goto out;
2441
2442 if (!hdr.ExtPageLength) {
2443 error = -ENXIO;
2444 goto out;
2445 }
2446
2447 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2448 &dma_handle);
2449 if (!buffer) {
2450 error = -ENOMEM;
2451 goto out;
2452 }
2453
2454 cfg.physAddr = dma_handle;
2455 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2456
2457 error = mpt_config(ioc, &cfg);
2458 if (error)
2459 goto out_free_consistent;
2460
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302461 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002462
2463 phy_info->hw_link_rate = buffer->HwLinkRate;
2464 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2465 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2466 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2467
2468 out_free_consistent:
2469 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2470 buffer, dma_handle);
2471 out:
2472 return error;
2473}
2474
2475static int
2476mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2477 u32 form, u32 form_specific)
2478{
2479 ConfigExtendedPageHeader_t hdr;
2480 CONFIGPARMS cfg;
2481 SasDevicePage0_t *buffer;
2482 dma_addr_t dma_handle;
2483 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002484 int error=0;
2485
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002486 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2487 hdr.ExtPageLength = 0;
2488 hdr.PageNumber = 0;
2489 hdr.Reserved1 = 0;
2490 hdr.Reserved2 = 0;
2491 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2492 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2493
2494 cfg.cfghdr.ehdr = &hdr;
2495 cfg.pageAddr = form + form_specific;
2496 cfg.physAddr = -1;
2497 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2498 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302499 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002500
Moore, Ericdb9c9172006-03-14 09:14:18 -07002501 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002502 error = mpt_config(ioc, &cfg);
2503 if (error)
2504 goto out;
2505 if (!hdr.ExtPageLength) {
2506 error = -ENXIO;
2507 goto out;
2508 }
2509
2510 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2511 &dma_handle);
2512 if (!buffer) {
2513 error = -ENOMEM;
2514 goto out;
2515 }
2516
2517 cfg.physAddr = dma_handle;
2518 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2519
2520 error = mpt_config(ioc, &cfg);
2521 if (error)
2522 goto out_free_consistent;
2523
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302524 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002525
Kashyap, Desai2f187862009-05-29 16:52:37 +05302526 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002527 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002528 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002529 device_info->handle_enclosure =
2530 le16_to_cpu(buffer->EnclosureHandle);
2531 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002532 device_info->phy_id = buffer->PhyNum;
2533 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002534 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002535 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002536 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002537 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2538 device_info->sas_address = le64_to_cpu(sas_address);
2539 device_info->device_info =
2540 le32_to_cpu(buffer->DeviceInfo);
2541
2542 out_free_consistent:
2543 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2544 buffer, dma_handle);
2545 out:
2546 return error;
2547}
2548
2549static int
2550mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2551 u32 form, u32 form_specific)
2552{
2553 ConfigExtendedPageHeader_t hdr;
2554 CONFIGPARMS cfg;
2555 SasExpanderPage0_t *buffer;
2556 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002557 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302558 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002559
Kashyap, Desai2f187862009-05-29 16:52:37 +05302560 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002561 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2562 hdr.ExtPageLength = 0;
2563 hdr.PageNumber = 0;
2564 hdr.Reserved1 = 0;
2565 hdr.Reserved2 = 0;
2566 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2567 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2568
2569 cfg.cfghdr.ehdr = &hdr;
2570 cfg.physAddr = -1;
2571 cfg.pageAddr = form + form_specific;
2572 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2573 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302574 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002575
Moore, Ericdb9c9172006-03-14 09:14:18 -07002576 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002577 error = mpt_config(ioc, &cfg);
2578 if (error)
2579 goto out;
2580
2581 if (!hdr.ExtPageLength) {
2582 error = -ENXIO;
2583 goto out;
2584 }
2585
2586 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2587 &dma_handle);
2588 if (!buffer) {
2589 error = -ENOMEM;
2590 goto out;
2591 }
2592
2593 cfg.physAddr = dma_handle;
2594 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2595
2596 error = mpt_config(ioc, &cfg);
2597 if (error)
2598 goto out_free_consistent;
2599
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002600 if (!buffer->NumPhys) {
2601 error = -ENODEV;
2602 goto out_free_consistent;
2603 }
2604
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002605 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302606 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002607 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302608 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002609 if (!port_info->phy_info) {
2610 error = -ENOMEM;
2611 goto out_free_consistent;
2612 }
2613
Kashyap, Desai2f187862009-05-29 16:52:37 +05302614 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002615 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002616 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002617 port_info->phy_info[i].handle =
2618 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302619 port_info->phy_info[i].identify.sas_address =
2620 le64_to_cpu(sas_address);
2621 port_info->phy_info[i].identify.handle_parent =
2622 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002623 }
Eric Moore547f9a22006-06-27 14:42:12 -06002624
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002625 out_free_consistent:
2626 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2627 buffer, dma_handle);
2628 out:
2629 return error;
2630}
2631
2632static int
2633mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2634 u32 form, u32 form_specific)
2635{
2636 ConfigExtendedPageHeader_t hdr;
2637 CONFIGPARMS cfg;
2638 SasExpanderPage1_t *buffer;
2639 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002640 int error=0;
2641
Kashyap, Desai2f187862009-05-29 16:52:37 +05302642 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002643 hdr.ExtPageLength = 0;
2644 hdr.PageNumber = 1;
2645 hdr.Reserved1 = 0;
2646 hdr.Reserved2 = 0;
2647 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2648 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2649
2650 cfg.cfghdr.ehdr = &hdr;
2651 cfg.physAddr = -1;
2652 cfg.pageAddr = form + form_specific;
2653 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2654 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302655 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002656
2657 error = mpt_config(ioc, &cfg);
2658 if (error)
2659 goto out;
2660
2661 if (!hdr.ExtPageLength) {
2662 error = -ENXIO;
2663 goto out;
2664 }
2665
2666 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2667 &dma_handle);
2668 if (!buffer) {
2669 error = -ENOMEM;
2670 goto out;
2671 }
2672
2673 cfg.physAddr = dma_handle;
2674 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2675
2676 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302677
2678 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2679 error = -ENODEV;
2680 goto out;
2681 }
2682
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002683 if (error)
2684 goto out_free_consistent;
2685
2686
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302687 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002688
2689 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002690 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002691 phy_info->port_id = buffer->PhysicalPort;
2692 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2693 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2694 phy_info->hw_link_rate = buffer->HwLinkRate;
2695 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2696 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2697
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002698 out_free_consistent:
2699 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2700 buffer, dma_handle);
2701 out:
2702 return error;
2703}
2704
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302705struct rep_manu_request{
2706 u8 smp_frame_type;
2707 u8 function;
2708 u8 reserved;
2709 u8 request_length;
2710};
2711
2712struct rep_manu_reply{
2713 u8 smp_frame_type; /* 0x41 */
2714 u8 function; /* 0x01 */
2715 u8 function_result;
2716 u8 response_length;
2717 u16 expander_change_count;
2718 u8 reserved0[2];
2719 u8 sas_format:1;
2720 u8 reserved1:7;
2721 u8 reserved2[3];
2722 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2723 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2724 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2725 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2726 u16 component_id;
2727 u8 component_revision_id;
2728 u8 reserved3;
2729 u8 vendor_specific[8];
2730};
2731
2732/**
2733 * mptsas_exp_repmanufacture_info -
2734 * @ioc: per adapter object
2735 * @sas_address: expander sas address
2736 * @edev: the sas_expander_device object
2737 *
2738 * Fills in the sas_expander_device object when SMP port is created.
2739 *
2740 * Returns 0 for success, non-zero for failure.
2741 */
2742static int
2743mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2744 u64 sas_address, struct sas_expander_device *edev)
2745{
2746 MPT_FRAME_HDR *mf;
2747 SmpPassthroughRequest_t *smpreq;
2748 SmpPassthroughReply_t *smprep;
2749 struct rep_manu_reply *manufacture_reply;
2750 struct rep_manu_request *manufacture_request;
2751 int ret;
2752 int flagsLength;
2753 unsigned long timeleft;
2754 char *psge;
2755 unsigned long flags;
2756 void *data_out = NULL;
2757 dma_addr_t data_out_dma = 0;
2758 u32 sz;
2759
2760 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2761 if (ioc->ioc_reset_in_progress) {
2762 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2763 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2764 __func__, ioc->name);
2765 return -EFAULT;
2766 }
2767 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2768
2769 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2770 if (ret)
2771 goto out;
2772
2773 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2774 if (!mf) {
2775 ret = -ENOMEM;
2776 goto out_unlock;
2777 }
2778
2779 smpreq = (SmpPassthroughRequest_t *)mf;
2780 memset(smpreq, 0, sizeof(*smpreq));
2781
2782 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2783
2784 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2785 if (!data_out) {
2786 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2787 __FILE__, __LINE__, __func__);
2788 ret = -ENOMEM;
2789 goto put_mf;
2790 }
2791
2792 manufacture_request = data_out;
2793 manufacture_request->smp_frame_type = 0x40;
2794 manufacture_request->function = 1;
2795 manufacture_request->reserved = 0;
2796 manufacture_request->request_length = 0;
2797
2798 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2799 smpreq->PhysicalPort = 0xFF;
2800 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2801 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2802
2803 psge = (char *)
2804 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2805
2806 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2807 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2808 MPI_SGE_FLAGS_HOST_TO_IOC |
2809 MPI_SGE_FLAGS_END_OF_BUFFER;
2810 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2811 flagsLength |= sizeof(struct rep_manu_request);
2812
2813 ioc->add_sge(psge, flagsLength, data_out_dma);
2814 psge += ioc->SGE_size;
2815
2816 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2817 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2818 MPI_SGE_FLAGS_IOC_TO_HOST |
2819 MPI_SGE_FLAGS_END_OF_BUFFER;
2820 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2821 flagsLength |= sizeof(struct rep_manu_reply);
2822 ioc->add_sge(psge, flagsLength, data_out_dma +
2823 sizeof(struct rep_manu_request));
2824
2825 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2826 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2827
2828 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2829 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2830 ret = -ETIME;
2831 mpt_free_msg_frame(ioc, mf);
2832 mf = NULL;
2833 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2834 goto out_free;
2835 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302836 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302837 goto out_free;
2838 }
2839
2840 mf = NULL;
2841
2842 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2843 u8 *tmp;
2844
2845 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2846 if (le16_to_cpu(smprep->ResponseDataLength) !=
2847 sizeof(struct rep_manu_reply))
2848 goto out_free;
2849
2850 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2851 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2852 SAS_EXPANDER_VENDOR_ID_LEN);
2853 strncpy(edev->product_id, manufacture_reply->product_id,
2854 SAS_EXPANDER_PRODUCT_ID_LEN);
2855 strncpy(edev->product_rev, manufacture_reply->product_rev,
2856 SAS_EXPANDER_PRODUCT_REV_LEN);
2857 edev->level = manufacture_reply->sas_format;
2858 if (manufacture_reply->sas_format) {
2859 strncpy(edev->component_vendor_id,
2860 manufacture_reply->component_vendor_id,
2861 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2862 tmp = (u8 *)&manufacture_reply->component_id;
2863 edev->component_id = tmp[0] << 8 | tmp[1];
2864 edev->component_revision_id =
2865 manufacture_reply->component_revision_id;
2866 }
2867 } else {
2868 printk(MYIOC_s_ERR_FMT
2869 "%s: smp passthru reply failed to be returned\n",
2870 ioc->name, __func__);
2871 ret = -ENXIO;
2872 }
2873out_free:
2874 if (data_out_dma)
2875 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2876put_mf:
2877 if (mf)
2878 mpt_free_msg_frame(ioc, mf);
2879out_unlock:
2880 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2881 mutex_unlock(&ioc->sas_mgmt.mutex);
2882out:
2883 return ret;
2884 }
2885
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002886static void
2887mptsas_parse_device_info(struct sas_identify *identify,
2888 struct mptsas_devinfo *device_info)
2889{
2890 u16 protocols;
2891
2892 identify->sas_address = device_info->sas_address;
2893 identify->phy_identifier = device_info->phy_id;
2894
2895 /*
2896 * Fill in Phy Initiator Port Protocol.
2897 * Bits 6:3, more than one bit can be set, fall through cases.
2898 */
2899 protocols = device_info->device_info & 0x78;
2900 identify->initiator_port_protocols = 0;
2901 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2902 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2903 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2904 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2905 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2906 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2907 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2908 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2909
2910 /*
2911 * Fill in Phy Target Port Protocol.
2912 * Bits 10:7, more than one bit can be set, fall through cases.
2913 */
2914 protocols = device_info->device_info & 0x780;
2915 identify->target_port_protocols = 0;
2916 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2917 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2918 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2919 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2920 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2921 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2922 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2923 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2924
2925 /*
2926 * Fill in Attached device type.
2927 */
2928 switch (device_info->device_info &
2929 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2930 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2931 identify->device_type = SAS_PHY_UNUSED;
2932 break;
2933 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2934 identify->device_type = SAS_END_DEVICE;
2935 break;
2936 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2937 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2938 break;
2939 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2940 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2941 break;
2942 }
2943}
2944
2945static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002946 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002947{
Moore, Erice6b2d762006-03-14 09:14:24 -07002948 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002949 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002950 struct sas_port *port;
2951 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002952
Eric Moore547f9a22006-06-27 14:42:12 -06002953 if (!dev) {
2954 error = -ENODEV;
2955 goto out;
2956 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002957
2958 if (!phy_info->phy) {
2959 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002960 if (!phy) {
2961 error = -ENOMEM;
2962 goto out;
2963 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002964 } else
2965 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002966
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002967 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002968
2969 /*
2970 * Set Negotiated link rate.
2971 */
2972 switch (phy_info->negotiated_link_rate) {
2973 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002974 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002975 break;
2976 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002977 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002978 break;
2979 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002980 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002981 break;
2982 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002983 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002984 break;
2985 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2986 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2987 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002988 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002989 break;
2990 }
2991
2992 /*
2993 * Set Max hardware link rate.
2994 */
2995 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2996 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002997 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002998 break;
2999 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003000 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003001 break;
3002 default:
3003 break;
3004 }
3005
3006 /*
3007 * Set Max programmed link rate.
3008 */
3009 switch (phy_info->programmed_link_rate &
3010 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3011 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003012 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003013 break;
3014 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003015 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003016 break;
3017 default:
3018 break;
3019 }
3020
3021 /*
3022 * Set Min hardware link rate.
3023 */
3024 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3025 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003026 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003027 break;
3028 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003029 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003030 break;
3031 default:
3032 break;
3033 }
3034
3035 /*
3036 * Set Min programmed link rate.
3037 */
3038 switch (phy_info->programmed_link_rate &
3039 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3040 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003041 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003042 break;
3043 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003044 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003045 break;
3046 default:
3047 break;
3048 }
3049
Moore, Erice6b2d762006-03-14 09:14:24 -07003050 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003051
Moore, Erice6b2d762006-03-14 09:14:24 -07003052 error = sas_phy_add(phy);
3053 if (error) {
3054 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003055 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003056 }
3057 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003058 }
3059
Eric Moore547f9a22006-06-27 14:42:12 -06003060 if (!phy_info->attached.handle ||
3061 !phy_info->port_details)
3062 goto out;
3063
3064 port = mptsas_get_port(phy_info);
3065 ioc = phy_to_ioc(phy_info->phy);
3066
3067 if (phy_info->sas_port_add_phy) {
3068
3069 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003070 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003071 if (!port) {
3072 error = -ENOMEM;
3073 goto out;
3074 }
3075 error = sas_port_add(port);
3076 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303077 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003078 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003079 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003080 goto out;
3081 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303082 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303083 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3084 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3085 ioc->name, port->port_identifier,
3086 (unsigned long long)phy_info->
3087 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003088 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303089 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3090 "sas_port_add_phy: phy_id=%d\n",
3091 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003092 sas_port_add_phy(port, phy_info->phy);
3093 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303094 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3095 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3096 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003097 }
Eric Moore547f9a22006-06-27 14:42:12 -06003098 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003099
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003100 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003101 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003102 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003103
James Bottomley2686de22006-06-30 12:54:02 -05003104 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003105 /*
3106 * Let the hotplug_work thread handle processing
3107 * the adding/removing of devices that occur
3108 * after start of day.
3109 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303110 if (mptsas_is_end_device(&phy_info->attached) &&
3111 phy_info->attached.handle_parent) {
3112 goto out;
3113 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003114
James Bottomleyf013db32006-03-18 14:54:36 -06003115 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003116 if (scsi_is_host_device(parent)) {
3117 struct mptsas_portinfo *port_info;
3118 int i;
3119
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303120 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003121
3122 for (i = 0; i < port_info->num_phys; i++)
3123 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003124 identify.sas_address) {
3125 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003126 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003127 }
James Bottomley2686de22006-06-30 12:54:02 -05003128
3129 } else if (scsi_is_sas_rphy(parent)) {
3130 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3131 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003132 parent_rphy->identify.sas_address) {
3133 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003134 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003135 }
James Bottomley2686de22006-06-30 12:54:02 -05003136 }
3137
James Bottomleyf013db32006-03-18 14:54:36 -06003138 switch (identify.device_type) {
3139 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003140 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003141 break;
3142 case SAS_EDGE_EXPANDER_DEVICE:
3143 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003144 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003145 break;
3146 default:
3147 rphy = NULL;
3148 break;
3149 }
Eric Moore547f9a22006-06-27 14:42:12 -06003150 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303151 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003152 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003153 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003154 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003155 }
3156
Eric Moore547f9a22006-06-27 14:42:12 -06003157 rphy->identify = identify;
3158 error = sas_rphy_add(rphy);
3159 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303160 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003161 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003162 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003163 sas_rphy_free(rphy);
3164 goto out;
3165 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303166 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303167 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3168 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3169 mptsas_exp_repmanufacture_info(ioc,
3170 identify.sas_address,
3171 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003172 }
3173
Eric Moore547f9a22006-06-27 14:42:12 -06003174 out:
3175 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003176}
3177
3178static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003179mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003180{
Moore, Erice6b2d762006-03-14 09:14:24 -07003181 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003182 int error = -ENOMEM, i;
3183
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303184 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003185 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003186 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003187
Moore, Erice6b2d762006-03-14 09:14:24 -07003188 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003189 if (error)
3190 goto out_free_port_info;
3191
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303192 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003193 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303194 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003195 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303196 ioc->hba_port_info = port_info = hba;
3197 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003198 list_add_tail(&port_info->list, &ioc->sas_topology);
3199 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003200 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003201 port_info->phy_info[i].negotiated_link_rate =
3202 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003203 port_info->phy_info[i].handle =
3204 hba->phy_info[i].handle;
3205 port_info->phy_info[i].port_id =
3206 hba->phy_info[i].port_id;
3207 }
Eric Moore547f9a22006-06-27 14:42:12 -06003208 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003209 kfree(hba);
3210 hba = NULL;
3211 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003212 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303213#if defined(CPQ_CIM)
3214 ioc->num_ports = port_info->num_phys;
3215#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003216 for (i = 0; i < port_info->num_phys; i++) {
3217 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3218 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3219 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303220 port_info->phy_info[i].identify.handle =
3221 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003222 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003223 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3224 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303225 port_info->phy_info[i].identify.handle);
3226 if (!ioc->hba_port_sas_addr)
3227 ioc->hba_port_sas_addr =
3228 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003229 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003230 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003231 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003232 mptsas_sas_device_pg0(ioc,
3233 &port_info->phy_info[i].attached,
3234 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3235 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3236 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003237 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003238
Eric Moore547f9a22006-06-27 14:42:12 -06003239 mptsas_setup_wide_ports(ioc, port_info);
3240
3241 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003242 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003243 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003244
3245 return 0;
3246
3247 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003248 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003249 out:
3250 return error;
3251}
3252
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303253static void
3254mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003255{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303256 struct mptsas_portinfo *parent;
3257 struct device *parent_dev;
3258 struct sas_rphy *rphy;
3259 int i;
3260 u64 sas_address; /* expander sas address */
3261 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003262
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303263 handle = port_info->phy_info[0].handle;
3264 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003265 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003266 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303267 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3268 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003269
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303270 mptsas_sas_device_pg0(ioc,
3271 &port_info->phy_info[i].identify,
3272 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3273 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3274 port_info->phy_info[i].identify.handle);
3275 port_info->phy_info[i].identify.phy_id =
3276 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003277
3278 if (port_info->phy_info[i].attached.handle) {
3279 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303280 &port_info->phy_info[i].attached,
3281 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3282 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3283 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003284 port_info->phy_info[i].attached.phy_id =
3285 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003286 }
Eric Moore547f9a22006-06-27 14:42:12 -06003287 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003288
Moore, Erice6b2d762006-03-14 09:14:24 -07003289 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303290 parent = mptsas_find_portinfo_by_handle(ioc,
3291 port_info->phy_info[0].identify.handle_parent);
3292 if (!parent) {
3293 mutex_unlock(&ioc->sas_topology_mutex);
3294 return;
3295 }
3296 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3297 i++) {
3298 if (parent->phy_info[i].attached.sas_address == sas_address) {
3299 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3300 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003301 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003302 }
3303 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303304
3305 mptsas_setup_wide_ports(ioc, port_info);
3306 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3307 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3308 ioc->sas_index, 0);
3309}
3310
3311static void
3312mptsas_expander_event_add(MPT_ADAPTER *ioc,
3313 MpiEventDataSasExpanderStatusChange_t *expander_data)
3314{
3315 struct mptsas_portinfo *port_info;
3316 int i;
3317 __le64 sas_address;
3318
3319 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3320 if (!port_info)
3321 BUG();
3322 port_info->num_phys = (expander_data->NumPhys) ?
3323 expander_data->NumPhys : 1;
3324 port_info->phy_info = kcalloc(port_info->num_phys,
3325 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3326 if (!port_info->phy_info)
3327 BUG();
3328 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3329 for (i = 0; i < port_info->num_phys; i++) {
3330 port_info->phy_info[i].portinfo = port_info;
3331 port_info->phy_info[i].handle =
3332 le16_to_cpu(expander_data->DevHandle);
3333 port_info->phy_info[i].identify.sas_address =
3334 le64_to_cpu(sas_address);
3335 port_info->phy_info[i].identify.handle_parent =
3336 le16_to_cpu(expander_data->ParentDevHandle);
3337 }
3338
3339 mutex_lock(&ioc->sas_topology_mutex);
3340 list_add_tail(&port_info->list, &ioc->sas_topology);
3341 mutex_unlock(&ioc->sas_topology_mutex);
3342
3343 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3344 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3345 (unsigned long long)sas_address);
3346
3347 mptsas_expander_refresh(ioc, port_info);
3348}
3349
3350/**
3351 * mptsas_delete_expander_siblings - remove siblings attached to expander
3352 * @ioc: Pointer to MPT_ADAPTER structure
3353 * @parent: the parent port_info object
3354 * @expander: the expander port_info object
3355 **/
3356static void
3357mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3358 *parent, struct mptsas_portinfo *expander)
3359{
3360 struct mptsas_phyinfo *phy_info;
3361 struct mptsas_portinfo *port_info;
3362 struct sas_rphy *rphy;
3363 int i;
3364
3365 phy_info = expander->phy_info;
3366 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3367 rphy = mptsas_get_rphy(phy_info);
3368 if (!rphy)
3369 continue;
3370 if (rphy->identify.device_type == SAS_END_DEVICE)
3371 mptsas_del_end_device(ioc, phy_info);
3372 }
3373
3374 phy_info = expander->phy_info;
3375 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3376 rphy = mptsas_get_rphy(phy_info);
3377 if (!rphy)
3378 continue;
3379 if (rphy->identify.device_type ==
3380 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3381 rphy->identify.device_type ==
3382 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3383 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3384 rphy->identify.sas_address);
3385 if (!port_info)
3386 continue;
3387 if (port_info == parent) /* backlink rphy */
3388 continue;
3389 /*
3390 Delete this expander even if the expdevpage is exists
3391 because the parent expander is already deleted
3392 */
3393 mptsas_expander_delete(ioc, port_info, 1);
3394 }
3395 }
3396}
3397
3398
3399/**
3400 * mptsas_expander_delete - remove this expander
3401 * @ioc: Pointer to MPT_ADAPTER structure
3402 * @port_info: expander port_info struct
3403 * @force: Flag to forcefully delete the expander
3404 *
3405 **/
3406
3407static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3408 struct mptsas_portinfo *port_info, u8 force)
3409{
3410
3411 struct mptsas_portinfo *parent;
3412 int i;
3413 u64 expander_sas_address;
3414 struct mptsas_phyinfo *phy_info;
3415 struct mptsas_portinfo buffer;
3416 struct mptsas_portinfo_details *port_details;
3417 struct sas_port *port;
3418
3419 if (!port_info)
3420 return;
3421
3422 /* see if expander is still there before deleting */
3423 mptsas_sas_expander_pg0(ioc, &buffer,
3424 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3425 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3426 port_info->phy_info[0].identify.handle);
3427
3428 if (buffer.num_phys) {
3429 kfree(buffer.phy_info);
3430 if (!force)
3431 return;
3432 }
3433
3434
3435 /*
3436 * Obtain the port_info instance to the parent port
3437 */
3438 port_details = NULL;
3439 expander_sas_address =
3440 port_info->phy_info[0].identify.sas_address;
3441 parent = mptsas_find_portinfo_by_handle(ioc,
3442 port_info->phy_info[0].identify.handle_parent);
3443 mptsas_delete_expander_siblings(ioc, parent, port_info);
3444 if (!parent)
3445 goto out;
3446
3447 /*
3448 * Delete rphys in the parent that point
3449 * to this expander.
3450 */
3451 phy_info = parent->phy_info;
3452 port = NULL;
3453 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3454 if (!phy_info->phy)
3455 continue;
3456 if (phy_info->attached.sas_address !=
3457 expander_sas_address)
3458 continue;
3459 if (!port) {
3460 port = mptsas_get_port(phy_info);
3461 port_details = phy_info->port_details;
3462 }
3463 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3464 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3465 phy_info->phy_id, phy_info->phy);
3466 sas_port_delete_phy(port, phy_info->phy);
3467 }
3468 if (port) {
3469 dev_printk(KERN_DEBUG, &port->dev,
3470 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3471 ioc->name, port->port_identifier,
3472 (unsigned long long)expander_sas_address);
3473 sas_port_delete(port);
3474 mptsas_port_delete(ioc, port_details);
3475 }
3476 out:
3477
3478 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3479 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3480 (unsigned long long)expander_sas_address);
3481
3482 /*
3483 * free link
3484 */
3485 list_del(&port_info->list);
3486 kfree(port_info->phy_info);
3487 kfree(port_info);
3488}
3489
3490
3491/**
3492 * mptsas_send_expander_event - expanders events
3493 * @ioc: Pointer to MPT_ADAPTER structure
3494 * @expander_data: event data
3495 *
3496 *
3497 * This function handles adding, removing, and refreshing
3498 * device handles within the expander objects.
3499 */
3500static void
3501mptsas_send_expander_event(struct fw_event_work *fw_event)
3502{
3503 MPT_ADAPTER *ioc;
3504 MpiEventDataSasExpanderStatusChange_t *expander_data;
3505 struct mptsas_portinfo *port_info;
3506 __le64 sas_address;
3507 int i;
3508
3509 ioc = fw_event->ioc;
3510 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3511 fw_event->event_data;
3512 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303513 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303514 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3515
3516 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3517 if (port_info) {
3518 for (i = 0; i < port_info->num_phys; i++) {
3519 port_info->phy_info[i].portinfo = port_info;
3520 port_info->phy_info[i].handle =
3521 le16_to_cpu(expander_data->DevHandle);
3522 port_info->phy_info[i].identify.sas_address =
3523 le64_to_cpu(sas_address);
3524 port_info->phy_info[i].identify.handle_parent =
3525 le16_to_cpu(expander_data->ParentDevHandle);
3526 }
3527 mptsas_expander_refresh(ioc, port_info);
3528 } else if (!port_info && expander_data->NumPhys)
3529 mptsas_expander_event_add(ioc, expander_data);
3530 } else if (expander_data->ReasonCode ==
3531 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3532 mptsas_expander_delete(ioc, port_info, 0);
3533
3534 mptsas_free_fw_event(ioc, fw_event);
3535}
3536
3537
3538/**
3539 * mptsas_expander_add -
3540 * @ioc: Pointer to MPT_ADAPTER structure
3541 * @handle:
3542 *
3543 */
3544struct mptsas_portinfo *
3545mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3546{
3547 struct mptsas_portinfo buffer, *port_info;
3548 int i;
3549
3550 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3551 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3552 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3553 return NULL;
3554
3555 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3556 if (!port_info) {
3557 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3558 "%s: exit at line=%d\n", ioc->name,
3559 __func__, __LINE__));
3560 return NULL;
3561 }
3562 port_info->num_phys = buffer.num_phys;
3563 port_info->phy_info = buffer.phy_info;
3564 for (i = 0; i < port_info->num_phys; i++)
3565 port_info->phy_info[i].portinfo = port_info;
3566 mutex_lock(&ioc->sas_topology_mutex);
3567 list_add_tail(&port_info->list, &ioc->sas_topology);
3568 mutex_unlock(&ioc->sas_topology_mutex);
3569 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3570 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3571 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3572 mptsas_expander_refresh(ioc, port_info);
3573 return port_info;
3574}
3575
3576static void
3577mptsas_send_link_status_event(struct fw_event_work *fw_event)
3578{
3579 MPT_ADAPTER *ioc;
3580 MpiEventDataSasPhyLinkStatus_t *link_data;
3581 struct mptsas_portinfo *port_info;
3582 struct mptsas_phyinfo *phy_info = NULL;
3583 __le64 sas_address;
3584 u8 phy_num;
3585 u8 link_rate;
3586
3587 ioc = fw_event->ioc;
3588 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3589
3590 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3591 sas_address = le64_to_cpu(sas_address);
3592 link_rate = link_data->LinkRates >> 4;
3593 phy_num = link_data->PhyNum;
3594
3595 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3596 if (port_info) {
3597 phy_info = &port_info->phy_info[phy_num];
3598 if (phy_info)
3599 phy_info->negotiated_link_rate = link_rate;
3600 }
3601
3602 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3603 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3604
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303605 if (!port_info) {
3606 if (ioc->old_sas_discovery_protocal) {
3607 port_info = mptsas_expander_add(ioc,
3608 le16_to_cpu(link_data->DevHandle));
3609 if (port_info)
3610 goto out;
3611 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303612 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303613 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303614
3615 if (port_info == ioc->hba_port_info)
3616 mptsas_probe_hba_phys(ioc);
3617 else
3618 mptsas_expander_refresh(ioc, port_info);
3619 } else if (phy_info && phy_info->phy) {
3620 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3621 phy_info->phy->negotiated_linkrate =
3622 SAS_PHY_DISABLED;
3623 else if (link_rate ==
3624 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3625 phy_info->phy->negotiated_linkrate =
3626 SAS_LINK_RATE_FAILED;
3627 else
3628 phy_info->phy->negotiated_linkrate =
3629 SAS_LINK_RATE_UNKNOWN;
3630 }
3631 out:
3632 mptsas_free_fw_event(ioc, fw_event);
3633}
3634
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303635static void
3636mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3637{
3638 struct mptsas_portinfo buffer, *port_info;
3639 struct mptsas_device_info *sas_info;
3640 struct mptsas_devinfo sas_device;
3641 u32 handle;
3642 VirtTarget *vtarget = NULL;
3643 struct mptsas_phyinfo *phy_info;
3644 u8 found_expander;
3645 int retval, retry_count;
3646 unsigned long flags;
3647
3648 mpt_findImVolumes(ioc);
3649
3650 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3651 if (ioc->ioc_reset_in_progress) {
3652 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3653 "%s: exiting due to a parallel reset \n", ioc->name,
3654 __func__));
3655 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3656 return;
3657 }
3658 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3659
3660 /* devices, logical volumes */
3661 mutex_lock(&ioc->sas_device_info_mutex);
3662 redo_device_scan:
3663 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303664 if (sas_info->is_cached)
3665 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303666 if (!sas_info->is_logical_volume) {
3667 sas_device.handle = 0;
3668 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303669retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303670 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303671 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3672 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3673 (sas_info->fw.channel << 8) +
3674 sas_info->fw.id);
3675
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303676 if (sas_device.handle)
3677 continue;
3678 if (retval == -EBUSY) {
3679 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3680 if (ioc->ioc_reset_in_progress) {
3681 dfailprintk(ioc,
3682 printk(MYIOC_s_DEBUG_FMT
3683 "%s: exiting due to reset\n",
3684 ioc->name, __func__));
3685 spin_unlock_irqrestore
3686 (&ioc->taskmgmt_lock, flags);
3687 mutex_unlock(&ioc->
3688 sas_device_info_mutex);
3689 return;
3690 }
3691 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3692 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303693 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303694
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303695 if (retval && (retval != -ENODEV)) {
3696 if (retry_count < 10) {
3697 retry_count++;
3698 goto retry_page;
3699 } else {
3700 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3701 "%s: Config page retry exceeded retry "
3702 "count deleting device 0x%llx\n",
3703 ioc->name, __func__,
3704 sas_info->sas_address));
3705 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303706 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303707
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303708 /* delete device */
3709 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303710 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303711
3712 if (vtarget)
3713 vtarget->deleted = 1;
3714
3715 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3716 sas_info->sas_address);
3717
3718 if (phy_info) {
3719 mptsas_del_end_device(ioc, phy_info);
3720 goto redo_device_scan;
3721 }
3722 } else
3723 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303724 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003725 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303726
3727 /* expanders */
3728 mutex_lock(&ioc->sas_topology_mutex);
3729 redo_expander_scan:
3730 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3731
3732 if (port_info->phy_info &&
3733 (!(port_info->phy_info[0].identify.device_info &
3734 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3735 continue;
3736 found_expander = 0;
3737 handle = 0xFFFF;
3738 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3739 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3740 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3741 !found_expander) {
3742
3743 handle = buffer.phy_info[0].handle;
3744 if (buffer.phy_info[0].identify.sas_address ==
3745 port_info->phy_info[0].identify.sas_address) {
3746 found_expander = 1;
3747 }
3748 kfree(buffer.phy_info);
3749 }
3750
3751 if (!found_expander) {
3752 mptsas_expander_delete(ioc, port_info, 0);
3753 goto redo_expander_scan;
3754 }
3755 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003756 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303757}
3758
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303759/**
3760 * mptsas_probe_expanders - adding expanders
3761 * @ioc: Pointer to MPT_ADAPTER structure
3762 *
3763 **/
3764static void
3765mptsas_probe_expanders(MPT_ADAPTER *ioc)
3766{
3767 struct mptsas_portinfo buffer, *port_info;
3768 u32 handle;
3769 int i;
3770
3771 handle = 0xFFFF;
3772 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3773 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3774 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3775
3776 handle = buffer.phy_info[0].handle;
3777 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3778 buffer.phy_info[0].identify.sas_address);
3779
3780 if (port_info) {
3781 /* refreshing handles */
3782 for (i = 0; i < buffer.num_phys; i++) {
3783 port_info->phy_info[i].handle = handle;
3784 port_info->phy_info[i].identify.handle_parent =
3785 buffer.phy_info[0].identify.handle_parent;
3786 }
3787 mptsas_expander_refresh(ioc, port_info);
3788 kfree(buffer.phy_info);
3789 continue;
3790 }
3791
3792 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3793 if (!port_info) {
3794 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3795 "%s: exit at line=%d\n", ioc->name,
3796 __func__, __LINE__));
3797 return;
3798 }
3799 port_info->num_phys = buffer.num_phys;
3800 port_info->phy_info = buffer.phy_info;
3801 for (i = 0; i < port_info->num_phys; i++)
3802 port_info->phy_info[i].portinfo = port_info;
3803 mutex_lock(&ioc->sas_topology_mutex);
3804 list_add_tail(&port_info->list, &ioc->sas_topology);
3805 mutex_unlock(&ioc->sas_topology_mutex);
3806 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3807 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3808 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3809 mptsas_expander_refresh(ioc, port_info);
3810 }
3811}
3812
3813static void
3814mptsas_probe_devices(MPT_ADAPTER *ioc)
3815{
3816 u16 handle;
3817 struct mptsas_devinfo sas_device;
3818 struct mptsas_phyinfo *phy_info;
3819
3820 handle = 0xFFFF;
3821 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3822 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3823
3824 handle = sas_device.handle;
3825
3826 if ((sas_device.device_info &
3827 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3828 MPI_SAS_DEVICE_INFO_STP_TARGET |
3829 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3830 continue;
3831
3832 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3833 if (!phy_info)
3834 continue;
3835
3836 if (mptsas_get_rphy(phy_info))
3837 continue;
3838
3839 mptsas_add_end_device(ioc, phy_info);
3840 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003841}
3842
Kashyap, Desai2f187862009-05-29 16:52:37 +05303843/**
3844 * mptsas_scan_sas_topology -
3845 * @ioc: Pointer to MPT_ADAPTER structure
3846 * @sas_address:
3847 *
3848 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003849static void
3850mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3851{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303852 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003853 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003854
Moore, Erice6b2d762006-03-14 09:14:24 -07003855 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303856 mptsas_probe_expanders(ioc);
3857 mptsas_probe_devices(ioc);
3858
Moore, Ericf44e5462006-03-14 09:14:21 -07003859 /*
3860 Reporting RAID volumes.
3861 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303862 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3863 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3864 return;
Eric Moore793955f2007-01-29 09:42:20 -07003865 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303866 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3867 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3868 if (sdev) {
3869 scsi_device_put(sdev);
3870 continue;
3871 }
3872 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3873 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3874 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003875 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003876 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3877 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003878}
3879
Kashyap, Desai57e98512009-05-29 16:55:09 +05303880
3881static void
3882mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3883{
3884 MPT_ADAPTER *ioc;
3885 EventDataQueueFull_t *qfull_data;
3886 struct mptsas_device_info *sas_info;
3887 struct scsi_device *sdev;
3888 int depth;
3889 int id = -1;
3890 int channel = -1;
3891 int fw_id, fw_channel;
3892 u16 current_depth;
3893
3894
3895 ioc = fw_event->ioc;
3896 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3897 fw_id = qfull_data->TargetID;
3898 fw_channel = qfull_data->Bus;
3899 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3900
3901 /* if hidden raid component, look for the volume id */
3902 mutex_lock(&ioc->sas_device_info_mutex);
3903 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3904 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3905 list) {
3906 if (sas_info->is_cached ||
3907 sas_info->is_logical_volume)
3908 continue;
3909 if (sas_info->is_hidden_raid_component &&
3910 (sas_info->fw.channel == fw_channel &&
3911 sas_info->fw.id == fw_id)) {
3912 id = sas_info->volume_id;
3913 channel = MPTSAS_RAID_CHANNEL;
3914 goto out;
3915 }
3916 }
3917 } else {
3918 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3919 list) {
3920 if (sas_info->is_cached ||
3921 sas_info->is_hidden_raid_component ||
3922 sas_info->is_logical_volume)
3923 continue;
3924 if (sas_info->fw.channel == fw_channel &&
3925 sas_info->fw.id == fw_id) {
3926 id = sas_info->os.id;
3927 channel = sas_info->os.channel;
3928 goto out;
3929 }
3930 }
3931
3932 }
3933
3934 out:
3935 mutex_unlock(&ioc->sas_device_info_mutex);
3936
3937 if (id != -1) {
3938 shost_for_each_device(sdev, ioc->sh) {
3939 if (sdev->id == id && sdev->channel == channel) {
3940 if (current_depth > sdev->queue_depth) {
3941 sdev_printk(KERN_INFO, sdev,
3942 "strange observation, the queue "
3943 "depth is (%d) meanwhile fw queue "
3944 "depth (%d)\n", sdev->queue_depth,
3945 current_depth);
3946 continue;
3947 }
3948 depth = scsi_track_queue_full(sdev,
3949 current_depth - 1);
3950 if (depth > 0)
3951 sdev_printk(KERN_INFO, sdev,
3952 "Queue depth reduced to (%d)\n",
3953 depth);
3954 else if (depth < 0)
3955 sdev_printk(KERN_INFO, sdev,
3956 "Tagged Command Queueing is being "
3957 "disabled\n");
3958 else if (depth == 0)
3959 sdev_printk(KERN_INFO, sdev,
3960 "Queue depth not changed yet\n");
3961 }
3962 }
3963 }
3964
3965 mptsas_free_fw_event(ioc, fw_event);
3966}
3967
3968
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003969static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003970mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003971{
3972 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003973 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003974 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003975
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003976 mutex_lock(&ioc->sas_topology_mutex);
3977 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3978 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003979 if (!mptsas_is_end_device(
3980 &port_info->phy_info[i].attached))
3981 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003982 if (port_info->phy_info[i].attached.sas_address
3983 != sas_address)
3984 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003985 phy_info = &port_info->phy_info[i];
3986 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003987 }
3988 }
3989 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003990 return phy_info;
3991}
3992
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303993/**
3994 * mptsas_find_phyinfo_by_phys_disk_num -
3995 * @ioc: Pointer to MPT_ADAPTER structure
3996 * @phys_disk_num:
3997 * @channel:
3998 * @id:
3999 *
4000 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004001static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304002mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4003 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004004{
Eric Mooreb506ade2007-01-29 09:45:37 -07004005 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304006 struct mptsas_portinfo *port_info;
4007 RaidPhysDiskPage1_t *phys_disk = NULL;
4008 int num_paths;
4009 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004010 int i;
4011
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304012 phy_info = NULL;
4013 if (!ioc->raid_data.pIocPg3)
4014 return NULL;
4015 /* dual port support */
4016 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4017 if (!num_paths)
4018 goto out;
4019 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4020 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4021 if (!phys_disk)
4022 goto out;
4023 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4024 for (i = 0; i < num_paths; i++) {
4025 if ((phys_disk->Path[i].Flags & 1) != 0)
4026 /* entry no longer valid */
4027 continue;
4028 if ((id == phys_disk->Path[i].PhysDiskID) &&
4029 (channel == phys_disk->Path[i].PhysDiskBus)) {
4030 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4031 sizeof(u64));
4032 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4033 sas_address);
4034 goto out;
4035 }
4036 }
4037
4038 out:
4039 kfree(phys_disk);
4040 if (phy_info)
4041 return phy_info;
4042
4043 /*
4044 * Extra code to handle RAID0 case, where the sas_address is not updated
4045 * in phys_disk_page_1 when hotswapped
4046 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004047 mutex_lock(&ioc->sas_topology_mutex);
4048 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304049 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004050 if (!mptsas_is_end_device(
4051 &port_info->phy_info[i].attached))
4052 continue;
4053 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4054 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304055 if ((port_info->phy_info[i].attached.phys_disk_num ==
4056 phys_disk_num) &&
4057 (port_info->phy_info[i].attached.id == id) &&
4058 (port_info->phy_info[i].attached.channel ==
4059 channel))
4060 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004061 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004062 }
4063 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004064 return phy_info;
4065}
4066
4067static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004068mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4069{
Eric Mooref99be432007-01-04 20:46:54 -07004070 int rc;
4071
Moore, Ericf44e5462006-03-14 09:14:21 -07004072 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004073 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004074}
4075
4076static void
4077mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4078{
4079 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4080 mptsas_reprobe_lun);
4081}
4082
Eric Mooreb506ade2007-01-29 09:45:37 -07004083static void
4084mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4085{
4086 CONFIGPARMS cfg;
4087 ConfigPageHeader_t hdr;
4088 dma_addr_t dma_handle;
4089 pRaidVolumePage0_t buffer = NULL;
4090 RaidPhysDiskPage0_t phys_disk;
4091 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304092 struct mptsas_phyinfo *phy_info;
4093 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004094
4095 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4096 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4097 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4098 cfg.pageAddr = (channel << 8) + id;
4099 cfg.cfghdr.hdr = &hdr;
4100 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4101
4102 if (mpt_config(ioc, &cfg) != 0)
4103 goto out;
4104
4105 if (!hdr.PageLength)
4106 goto out;
4107
4108 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4109 &dma_handle);
4110
4111 if (!buffer)
4112 goto out;
4113
4114 cfg.physAddr = dma_handle;
4115 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4116
4117 if (mpt_config(ioc, &cfg) != 0)
4118 goto out;
4119
4120 if (!(buffer->VolumeStatus.Flags &
4121 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4122 goto out;
4123
4124 if (!buffer->NumPhysDisks)
4125 goto out;
4126
4127 for (i = 0; i < buffer->NumPhysDisks; i++) {
4128
4129 if (mpt_raid_phys_disk_pg0(ioc,
4130 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4131 continue;
4132
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304133 if (mptsas_sas_device_pg0(ioc, &sas_device,
4134 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4135 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4136 (phys_disk.PhysDiskBus << 8) +
4137 phys_disk.PhysDiskID))
4138 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004139
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304140 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4141 sas_device.sas_address);
4142 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004143 }
4144
4145 out:
4146 if (buffer)
4147 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4148 dma_handle);
4149}
Moore, Erice6b2d762006-03-14 09:14:24 -07004150/*
4151 * Work queue thread to handle SAS hotplug events
4152 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004153static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304154mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4155 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004156{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004157 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004158 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004159 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004160 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304161 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06004162
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304163 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004164
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304165 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004166
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304167 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004168 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004169
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304170 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4171 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4172 hot_plug_info->id) {
4173 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4174 "to add hidden disk - target_id matchs "
4175 "volume_id\n", ioc->name);
4176 mptsas_free_fw_event(ioc, fw_event);
4177 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004178 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004179 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304180 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004181
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004182 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304183 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4184 mptsas_sas_device_pg0(ioc, &sas_device,
4185 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4186 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4187 (hot_plug_info->channel << 8) +
4188 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004189
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304190 if (!sas_device.handle)
4191 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004192
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304193 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4194 if (!phy_info)
4195 break;
4196
4197 if (mptsas_get_rphy(phy_info))
4198 break;
4199
4200 mptsas_add_end_device(ioc, phy_info);
4201 break;
4202
4203 case MPTSAS_DEL_DEVICE:
4204 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4205 hot_plug_info->sas_address);
4206 mptsas_del_end_device(ioc, phy_info);
4207 break;
4208
4209 case MPTSAS_DEL_PHYSDISK:
4210
4211 mpt_findImVolumes(ioc);
4212
4213 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304214 ioc, hot_plug_info->phys_disk_num,
4215 hot_plug_info->channel,
4216 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304217 mptsas_del_end_device(ioc, phy_info);
4218 break;
4219
4220 case MPTSAS_ADD_PHYSDISK_REPROBE:
4221
Christoph Hellwige3094442006-02-16 13:25:36 +01004222 if (mptsas_sas_device_pg0(ioc, &sas_device,
4223 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004224 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304225 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4226 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4227 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4228 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004229 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004230 }
4231
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304232 phy_info = mptsas_find_phyinfo_by_sas_address(
4233 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004234
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304235 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304236 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304237 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4238 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004239 break;
4240 }
4241
4242 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304243 if (!starget) {
4244 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4245 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4246 __func__, hot_plug_info->id, __LINE__));
4247 break;
4248 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004249
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304250 vtarget = starget->hostdata;
4251 if (!vtarget) {
4252 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4253 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4254 __func__, hot_plug_info->id, __LINE__));
4255 break;
4256 }
Eric Moore547f9a22006-06-27 14:42:12 -06004257
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304258 mpt_findImVolumes(ioc);
4259
4260 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4261 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4262 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4263 hot_plug_info->phys_disk_num, (unsigned long long)
4264 sas_device.sas_address);
4265
4266 vtarget->id = hot_plug_info->phys_disk_num;
4267 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4268 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4269 mptsas_reprobe_target(starget, 1);
4270 break;
4271
4272 case MPTSAS_DEL_PHYSDISK_REPROBE:
4273
4274 if (mptsas_sas_device_pg0(ioc, &sas_device,
4275 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4276 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4277 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
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",
4280 ioc->name, __func__,
4281 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004282 break;
4283 }
4284
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304285 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4286 sas_device.sas_address);
4287 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304288 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304289 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4290 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004291 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004292 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004293
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304294 starget = mptsas_get_starget(phy_info);
4295 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304296 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304297 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4298 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004299 break;
4300 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004301
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304302 vtarget = starget->hostdata;
4303 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304304 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304305 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4306 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004307 break;
4308 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304309
4310 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4311 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4312 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4313 __func__, hot_plug_info->id, __LINE__));
4314 break;
4315 }
4316
4317 mpt_findImVolumes(ioc);
4318
4319 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4320 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4321 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4322 hot_plug_info->phys_disk_num, (unsigned long long)
4323 sas_device.sas_address);
4324
4325 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4326 vtarget->id = hot_plug_info->id;
4327 phy_info->attached.phys_disk_num = ~0;
4328 mptsas_reprobe_target(starget, 0);
4329 mptsas_add_device_component_by_fw(ioc,
4330 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004331 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304332
Moore, Ericc73787ee2006-01-26 16:20:06 -07004333 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304334
Moore, Ericc73787ee2006-01-26 16:20:06 -07004335 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304336 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4337 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4338 hot_plug_info->id);
4339 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4340 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004341 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304342
Moore, Ericc73787ee2006-01-26 16:20:06 -07004343 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304344
Moore, Ericc73787ee2006-01-26 16:20:06 -07004345 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304346 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4347 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4348 hot_plug_info->id);
4349 scsi_remove_device(hot_plug_info->sdev);
4350 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004351 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304352
Eric Mooreb506ade2007-01-29 09:45:37 -07004353 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304354
4355 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004356 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304357 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004358 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304359
Moore, Ericbd23e942006-04-17 12:43:04 -06004360 default:
4361 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004362 }
4363
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304364 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004365}
4366
4367static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304368mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004369{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304370 MPT_ADAPTER *ioc;
4371 struct mptsas_hotplug_event hot_plug_info;
4372 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4373 u32 device_info;
4374 u64 sas_address;
4375
4376 ioc = fw_event->ioc;
4377 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4378 fw_event->event_data;
4379 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004380
4381 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304382 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4383 MPI_SAS_DEVICE_INFO_STP_TARGET |
4384 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4385 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004386 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304387 }
4388
4389 if (sas_event_data->ReasonCode ==
4390 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4391 mptbase_sas_persist_operation(ioc,
4392 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4393 mptsas_free_fw_event(ioc, fw_event);
4394 return;
4395 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004396
Moore, Eric4b766472006-03-14 09:14:12 -07004397 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004398 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004399 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304400 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4401 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4402 hot_plug_info.channel = sas_event_data->Bus;
4403 hot_plug_info.id = sas_event_data->TargetID;
4404 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004405 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304406 sizeof(u64));
4407 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4408 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004409 if (sas_event_data->ReasonCode &
4410 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304411 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004412 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304413 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4414 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004415 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304416
Moore, Eric4b766472006-03-14 09:14:12 -07004417 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304418 mptbase_sas_persist_operation(ioc,
4419 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4420 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004421 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304422
Moore, Eric4b766472006-03-14 09:14:12 -07004423 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304424 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004425 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304426 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004427 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304428 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004429 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004430 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004431}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304432
Moore, Ericc73787ee2006-01-26 16:20:06 -07004433static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304434mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004435{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304436 MPT_ADAPTER *ioc;
4437 EVENT_DATA_RAID *raid_event_data;
4438 struct mptsas_hotplug_event hot_plug_info;
4439 int status;
4440 int state;
4441 struct scsi_device *sdev = NULL;
4442 VirtDevice *vdevice = NULL;
4443 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004444
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304445 ioc = fw_event->ioc;
4446 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4447 status = le32_to_cpu(raid_event_data->SettingsStatus);
4448 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004449
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304450 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4451 hot_plug_info.id = raid_event_data->VolumeID;
4452 hot_plug_info.channel = raid_event_data->VolumeBus;
4453 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4454
4455 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4456 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4457 raid_event_data->ReasonCode ==
4458 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4459 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4460 hot_plug_info.id, 0);
4461 hot_plug_info.sdev = sdev;
4462 if (sdev)
4463 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004464 }
4465
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304466 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4467 "ReasonCode=%02x\n", ioc->name, __func__,
4468 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004469
4470 switch (raid_event_data->ReasonCode) {
4471 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304472 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004473 break;
4474 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304475 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004476 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004477 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4478 switch (state) {
4479 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004480 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304481 mpt_raid_phys_disk_pg0(ioc,
4482 raid_event_data->PhysDiskNum, &phys_disk);
4483 hot_plug_info.id = phys_disk.PhysDiskID;
4484 hot_plug_info.channel = phys_disk.PhysDiskBus;
4485 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004486 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304487 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004488 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004489 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4490 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4491 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304492 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004493 break;
4494 default:
4495 break;
4496 }
4497 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004498 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304499 if (!sdev)
4500 break;
4501 vdevice->vtarget->deleted = 1; /* block IO */
4502 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004503 break;
4504 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304505 if (sdev) {
4506 scsi_device_put(sdev);
4507 break;
4508 }
4509 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004510 break;
4511 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304512 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4513 if (!sdev)
4514 break;
4515 vdevice->vtarget->deleted = 1; /* block IO */
4516 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4517 break;
4518 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004519 switch (state) {
4520 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4521 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304522 if (!sdev)
4523 break;
4524 vdevice->vtarget->deleted = 1; /* block IO */
4525 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004526 break;
4527 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4528 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304529 if (sdev) {
4530 scsi_device_put(sdev);
4531 break;
4532 }
4533 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004534 break;
4535 default:
4536 break;
4537 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004538 break;
4539 default:
4540 break;
4541 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304542
4543 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4544 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4545 else
4546 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004547}
4548
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304549/**
4550 * mptsas_issue_tm - send mptsas internal tm request
4551 * @ioc: Pointer to MPT_ADAPTER structure
4552 * @type: Task Management type
4553 * @channel: channel number for task management
4554 * @id: Logical Target ID for reset (if appropriate)
4555 * @lun: Logical unit for reset (if appropriate)
4556 * @task_context: Context for the task to be aborted
4557 * @timeout: timeout for task management control
4558 *
4559 * return 0 on success and -1 on failure:
4560 *
4561 */
4562static int
4563mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4564 int task_context, ulong timeout, u8 *issue_reset)
4565{
4566 MPT_FRAME_HDR *mf;
4567 SCSITaskMgmt_t *pScsiTm;
4568 int retval;
4569 unsigned long timeleft;
4570
4571 *issue_reset = 0;
4572 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4573 if (mf == NULL) {
4574 retval = -1; /* return failure */
4575 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4576 "msg frames!!\n", ioc->name));
4577 goto out;
4578 }
4579
4580 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4581 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4582 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4583 type, timeout, channel, id, (unsigned long long)lun,
4584 task_context));
4585
4586 pScsiTm = (SCSITaskMgmt_t *) mf;
4587 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4588 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4589 pScsiTm->TaskType = type;
4590 pScsiTm->MsgFlags = 0;
4591 pScsiTm->TargetID = id;
4592 pScsiTm->Bus = channel;
4593 pScsiTm->ChainOffset = 0;
4594 pScsiTm->Reserved = 0;
4595 pScsiTm->Reserved1 = 0;
4596 pScsiTm->TaskMsgContext = task_context;
4597 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4598
4599 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4600 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4601 retval = 0;
4602 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4603
4604 /* Now wait for the command to complete */
4605 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4606 timeout*HZ);
4607 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4608 retval = -1; /* return failure */
4609 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4610 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4611 mpt_free_msg_frame(ioc, mf);
4612 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4613 goto out;
4614 *issue_reset = 1;
4615 goto out;
4616 }
4617
4618 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4619 retval = -1; /* return failure */
4620 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4621 "TaskMgmt request: failed with no reply\n", ioc->name));
4622 goto out;
4623 }
4624
4625 out:
4626 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4627 return retval;
4628}
4629
4630/**
4631 * mptsas_broadcast_primative_work - Handle broadcast primitives
4632 * @work: work queue payload containing info describing the event
4633 *
4634 * this will be handled in workqueue context.
4635 */
4636static void
4637mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4638{
4639 MPT_ADAPTER *ioc = fw_event->ioc;
4640 MPT_FRAME_HDR *mf;
4641 VirtDevice *vdevice;
4642 int ii;
4643 struct scsi_cmnd *sc;
4644 SCSITaskMgmtReply_t *pScsiTmReply;
4645 u8 issue_reset;
4646 int task_context;
4647 u8 channel, id;
4648 int lun;
4649 u32 termination_count;
4650 u32 query_count;
4651
4652 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4653 "%s - enter\n", ioc->name, __func__));
4654
4655 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4656 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4657 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4658 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4659 return;
4660 }
4661
4662 issue_reset = 0;
4663 termination_count = 0;
4664 query_count = 0;
4665 mpt_findImVolumes(ioc);
4666 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4667
4668 for (ii = 0; ii < ioc->req_depth; ii++) {
4669 if (ioc->fw_events_off)
4670 goto out;
4671 sc = mptscsih_get_scsi_lookup(ioc, ii);
4672 if (!sc)
4673 continue;
4674 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4675 if (!mf)
4676 continue;
4677 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4678 vdevice = sc->device->hostdata;
4679 if (!vdevice || !vdevice->vtarget)
4680 continue;
4681 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4682 continue; /* skip hidden raid components */
4683 if (vdevice->vtarget->raidVolume)
4684 continue; /* skip hidden raid components */
4685 channel = vdevice->vtarget->channel;
4686 id = vdevice->vtarget->id;
4687 lun = vdevice->lun;
4688 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4689 channel, id, (u64)lun, task_context, 30, &issue_reset))
4690 goto out;
4691 query_count++;
4692 termination_count +=
4693 le32_to_cpu(pScsiTmReply->TerminationCount);
4694 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4695 (pScsiTmReply->ResponseCode ==
4696 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4697 pScsiTmReply->ResponseCode ==
4698 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4699 continue;
4700 if (mptsas_issue_tm(ioc,
4701 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4702 channel, id, (u64)lun, 0, 30, &issue_reset))
4703 goto out;
4704 termination_count +=
4705 le32_to_cpu(pScsiTmReply->TerminationCount);
4706 }
4707
4708 out:
4709 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4710 "%s - exit, query_count = %d termination_count = %d\n",
4711 ioc->name, __func__, query_count, termination_count));
4712
4713 ioc->broadcast_aen_busy = 0;
4714 mpt_clear_taskmgmt_in_progress_flag(ioc);
4715 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4716
4717 if (issue_reset) {
4718 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4719 ioc->name, __func__);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304720 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304721 }
4722 mptsas_free_fw_event(ioc, fw_event);
4723}
4724
Eric Mooreb506ade2007-01-29 09:45:37 -07004725/*
4726 * mptsas_send_ir2_event - handle exposing hidden disk when
4727 * an inactive raid volume is added
4728 *
4729 * @ioc: Pointer to MPT_ADAPTER structure
4730 * @ir2_data
4731 *
4732 */
4733static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304734mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004735{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304736 MPT_ADAPTER *ioc;
4737 struct mptsas_hotplug_event hot_plug_info;
4738 MPI_EVENT_DATA_IR2 *ir2_data;
4739 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304740 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004741
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304742 ioc = fw_event->ioc;
4743 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4744 reasonCode = ir2_data->ReasonCode;
4745
4746 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4747 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4748
4749 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4750 hot_plug_info.id = ir2_data->TargetID;
4751 hot_plug_info.channel = ir2_data->Bus;
4752 switch (reasonCode) {
4753 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4754 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4755 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304756 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4757 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4758 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4759 break;
4760 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4761 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4762 mpt_raid_phys_disk_pg0(ioc,
4763 ir2_data->PhysDiskNum, &phys_disk);
4764 hot_plug_info.id = phys_disk.PhysDiskID;
4765 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4766 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304767 default:
4768 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004769 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304770 }
4771 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4772}
Moore, Erice6b2d762006-03-14 09:14:24 -07004773
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004774static int
4775mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4776{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304777 u32 event = le32_to_cpu(reply->Event);
4778 int sz, event_data_sz;
4779 struct fw_event_work *fw_event;
4780 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004781
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304782 if (ioc->bus_type != SAS)
4783 return 0;
4784
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304785 /* events turned off due to host reset or driver unloading */
4786 if (ioc->fw_events_off)
4787 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004788
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304789 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004790 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304791 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4792 {
4793 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4794 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4795 if (broadcast_event_data->Primitive !=
4796 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4797 return 0;
4798 if (ioc->broadcast_aen_busy)
4799 return 0;
4800 ioc->broadcast_aen_busy = 1;
4801 break;
4802 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004803 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304804 {
4805 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4806 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4807
4808 if (sas_event_data->ReasonCode ==
4809 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4810 mptsas_target_reset_queue(ioc, sas_event_data);
4811 return 0;
4812 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004813 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304814 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304815 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4816 {
4817 MpiEventDataSasExpanderStatusChange_t *expander_data =
4818 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4819
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304820 if (ioc->old_sas_discovery_protocal)
4821 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304822
4823 if (expander_data->ReasonCode ==
4824 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4825 ioc->device_missing_delay)
4826 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004827 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304828 }
4829 case MPI_EVENT_SAS_DISCOVERY:
4830 {
4831 u32 discovery_status;
4832 EventDataSasDiscovery_t *discovery_data =
4833 (EventDataSasDiscovery_t *)reply->Data;
4834
4835 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4836 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304837 if (ioc->old_sas_discovery_protocal && !discovery_status)
4838 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304839 return 0;
4840 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304841 case MPI_EVENT_INTEGRATED_RAID:
4842 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004843 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304844 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4845 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004846 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004847 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304848 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004849 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004850
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304851 event_data_sz = ((reply->MsgLength * 4) -
4852 offsetof(EventNotificationReply_t, Data));
4853 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4854 fw_event = kzalloc(sz, GFP_ATOMIC);
4855 if (!fw_event) {
4856 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4857 __func__, __LINE__);
4858 return 0;
4859 }
4860 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4861 fw_event->event = event;
4862 fw_event->ioc = ioc;
4863 mptsas_add_fw_event(ioc, fw_event, delay);
4864 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004865}
4866
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304867/* Delete a volume when no longer listed in ioc pg2
4868 */
4869static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4870{
4871 struct scsi_device *sdev;
4872 int i;
4873
4874 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4875 if (!sdev)
4876 return;
4877 if (!ioc->raid_data.pIocPg2)
4878 goto out;
4879 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4880 goto out;
4881 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4882 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4883 goto release_sdev;
4884 out:
4885 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4886 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4887 scsi_remove_device(sdev);
4888 release_sdev:
4889 scsi_device_put(sdev);
4890}
4891
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004892static int
4893mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4894{
4895 struct Scsi_Host *sh;
4896 MPT_SCSI_HOST *hd;
4897 MPT_ADAPTER *ioc;
4898 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004899 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004900 int numSGE = 0;
4901 int scale;
4902 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004903 int error=0;
4904 int r;
4905
4906 r = mpt_attach(pdev,id);
4907 if (r)
4908 return r;
4909
4910 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304911 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004912 ioc->DoneCtx = mptsasDoneCtx;
4913 ioc->TaskCtx = mptsasTaskCtx;
4914 ioc->InternalCtx = mptsasInternalCtx;
4915
4916 /* Added sanity check on readiness of the MPT adapter.
4917 */
4918 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4919 printk(MYIOC_s_WARN_FMT
4920 "Skipping because it's not operational!\n",
4921 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004922 error = -ENODEV;
4923 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004924 }
4925
4926 if (!ioc->active) {
4927 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4928 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004929 error = -ENODEV;
4930 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004931 }
4932
4933 /* Sanity check - ensure at least 1 port is INITIATOR capable
4934 */
4935 ioc_cap = 0;
4936 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4937 if (ioc->pfacts[ii].ProtocolFlags &
4938 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4939 ioc_cap++;
4940 }
4941
4942 if (!ioc_cap) {
4943 printk(MYIOC_s_WARN_FMT
4944 "Skipping ioc=%p because SCSI Initiator mode "
4945 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004946 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004947 }
4948
4949 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4950 if (!sh) {
4951 printk(MYIOC_s_WARN_FMT
4952 "Unable to register controller with SCSI subsystem\n",
4953 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004954 error = -1;
4955 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004956 }
4957
4958 spin_lock_irqsave(&ioc->FreeQlock, flags);
4959
4960 /* Attach the SCSI Host to the IOC structure
4961 */
4962 ioc->sh = sh;
4963
4964 sh->io_port = 0;
4965 sh->n_io_port = 0;
4966 sh->irq = 0;
4967
4968 /* set 16 byte cdb's */
4969 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05304970 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
4971 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07004972 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004973 sh->transportt = mptsas_transport_template;
4974
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004975 /* Required entry.
4976 */
4977 sh->unique_id = ioc->id;
4978
4979 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004980 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004981 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004982 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004983 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004984
4985 /* Verify that we won't exceed the maximum
4986 * number of chain buffers
4987 * We can optimize: ZZ = req_sz/sizeof(SGE)
4988 * For 32bit SGE's:
4989 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4990 * + (req_sz - 64)/sizeof(SGE)
4991 * A slightly different algorithm is required for
4992 * 64bit SGEs.
4993 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304994 scale = ioc->req_sz/ioc->SGE_size;
4995 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004996 numSGE = (scale - 1) *
4997 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304998 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004999 } else {
5000 numSGE = 1 + (scale - 1) *
5001 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305002 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005003 }
5004
5005 if (numSGE < sh->sg_tablesize) {
5006 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305007 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005008 "Resetting sg_tablesize to %d from %d\n",
5009 ioc->name, numSGE, sh->sg_tablesize));
5010 sh->sg_tablesize = numSGE;
5011 }
5012
Eric Mooree7eae9f2007-09-29 10:15:59 -06005013 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005014 hd->ioc = ioc;
5015
5016 /* SCSI needs scsi_cmnd lookup table!
5017 * (with size equal to req_depth*PtrSz!)
5018 */
Eric Mooree8206382007-09-29 10:16:53 -06005019 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5020 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005021 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005022 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005023 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005024 }
Eric Mooree8206382007-09-29 10:16:53 -06005025 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005026
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305027 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005028 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005029
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005030 ioc->sas_data.ptClear = mpt_pt_clear;
5031
Eric Mooredf9e0622007-01-29 09:46:21 -07005032 hd->last_queue_full = 0;
5033 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305034 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5035 mutex_init(&ioc->sas_device_info_mutex);
5036
Eric Mooredf9e0622007-01-29 09:46:21 -07005037 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5038
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005039 if (ioc->sas_data.ptClear==1) {
5040 mptbase_sas_persist_operation(
5041 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5042 }
5043
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005044 error = scsi_add_host(sh, &ioc->pcidev->dev);
5045 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005046 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5047 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005048 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005049 }
5050
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305051 /* older firmware doesn't support expander events */
5052 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5053 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005054 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305055 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005056 return 0;
5057
Eric Moore547f9a22006-06-27 14:42:12 -06005058 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005059
5060 mptscsih_remove(pdev);
5061 return error;
5062}
5063
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305064void
5065mptsas_shutdown(struct pci_dev *pdev)
5066{
5067 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5068
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305069 mptsas_fw_event_off(ioc);
5070 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305071}
5072
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005073static void __devexit mptsas_remove(struct pci_dev *pdev)
5074{
5075 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5076 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005077 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005078
Kashyap, Desai48959f12010-03-18 19:18:30 +05305079 if (!ioc->sh) {
5080 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5081 mpt_detach(pdev);
5082 return;
5083 }
5084
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305085 mptsas_shutdown(pdev);
5086
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305087 mptsas_del_device_components(ioc);
5088
Eric Mooreb506ade2007-01-29 09:45:37 -07005089 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005090 sas_remove_host(ioc->sh);
5091
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005092 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005093 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5094 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005095 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305096 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305097
Eric Moore547f9a22006-06-27 14:42:12 -06005098 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005099 kfree(p);
5100 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005101 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305102 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005103 mptscsih_remove(pdev);
5104}
5105
5106static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005107 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005108 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005109 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005110 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005111 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005112 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005113 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005114 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005115 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005116 PCI_ANY_ID, PCI_ANY_ID },
5117 {0} /* Terminating entry */
5118};
5119MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5120
5121
5122static struct pci_driver mptsas_driver = {
5123 .name = "mptsas",
5124 .id_table = mptsas_pci_table,
5125 .probe = mptsas_probe,
5126 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305127 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005128#ifdef CONFIG_PM
5129 .suspend = mptscsih_suspend,
5130 .resume = mptscsih_resume,
5131#endif
5132};
5133
5134static int __init
5135mptsas_init(void)
5136{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305137 int error;
5138
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005139 show_mptmod_ver(my_NAME, my_VERSION);
5140
5141 mptsas_transport_template =
5142 sas_attach_transport(&mptsas_transport_functions);
5143 if (!mptsas_transport_template)
5144 return -ENODEV;
5145
5146 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305147 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005148 mptsasInternalCtx =
5149 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005150 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305151 mptsasDeviceResetCtx =
5152 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005153
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305154 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5155 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005156
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305157 error = pci_register_driver(&mptsas_driver);
5158 if (error)
5159 sas_release_transport(mptsas_transport_template);
5160
5161 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005162}
5163
5164static void __exit
5165mptsas_exit(void)
5166{
5167 pci_unregister_driver(&mptsas_driver);
5168 sas_release_transport(mptsas_transport_template);
5169
5170 mpt_reset_deregister(mptsasDoneCtx);
5171 mpt_event_deregister(mptsasDoneCtx);
5172
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005173 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005174 mpt_deregister(mptsasInternalCtx);
5175 mpt_deregister(mptsasTaskCtx);
5176 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305177 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005178}
5179
5180module_init(mptsas_init);
5181module_exit(mptsas_exit);