blob: f744f0fc949124fd06181ece3d8bd287bb8c9cb2 [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>
48#include <linux/init.h>
49#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080050#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020051#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060052#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020053
Eric Moore547f9a22006-06-27 14:42:12 -060054#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020055#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
57#include <scsi/scsi_host.h>
58#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060059#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020060
61#include "mptbase.h"
62#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053063#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020064
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Kashyap, Desai4b976502009-08-05 12:52:03 +053075#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020076MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070079MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081static int mpt_pt_clear;
82module_param(mpt_pt_clear, int, 0);
83MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060084 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020085 "(default=MPTSCSIH_PT_CLEAR=0)");
86
Eric Moore793955f2007-01-29 09:42:20 -070087/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
88#define MPTSAS_MAX_LUN (16895)
89static int max_lun = MPTSAS_MAX_LUN;
90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92
Prakash, Sathyaf606f572007-08-14 16:12:53 +053093static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
96static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053097static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Kashyap, Desai3eb08222009-05-29 16:47:26 +053099static void mptsas_firmware_event_work(struct work_struct *work);
100static void mptsas_send_sas_event(struct fw_event_work *fw_event);
101static void mptsas_send_raid_event(struct fw_event_work *fw_event);
102static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
103static void mptsas_parse_device_info(struct sas_identify *identify,
104 struct mptsas_devinfo *device_info);
105static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
106 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
107static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
108 (MPT_ADAPTER *ioc, u64 sas_address);
109static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
110 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
111static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
112 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
113static int mptsas_add_end_device(MPT_ADAPTER *ioc,
114 struct mptsas_phyinfo *phy_info);
115static void mptsas_del_end_device(MPT_ADAPTER *ioc,
116 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530117static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
118static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
119 (MPT_ADAPTER *ioc, u64 sas_address);
120static void mptsas_expander_delete(MPT_ADAPTER *ioc,
121 struct mptsas_portinfo *port_info, u8 force);
122static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530123static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
124static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530125static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530126static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530127static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200128
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530129static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
130 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200131{
Eric Moore29dd3602007-09-14 18:46:51 -0600132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
133 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
135 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
137 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
139 ioc->name, phy_data->Port));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
141 ioc->name, phy_data->PortFlags));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
143 ioc->name, phy_data->PhyFlags));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
145 ioc->name, phy_data->NegotiatedLinkRate));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
147 "Controller PHY Device Info=0x%X\n", ioc->name,
148 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
149 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
150 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200151}
152
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530153static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200154{
155 __le64 sas_address;
156
157 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
158
Eric Moore29dd3602007-09-14 18:46:51 -0600159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
160 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
162 "Attached Device Handle=0x%X\n", ioc->name,
163 le16_to_cpu(pg0->AttachedDevHandle)));
164 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
165 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
166 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
167 "Attached PHY Identifier=0x%X\n", ioc->name,
168 pg0->AttachedPhyIdentifier));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
170 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
172 ioc->name, pg0->ProgrammedLinkRate));
173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
174 ioc->name, pg0->ChangeCount));
175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
176 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200177}
178
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530179static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200180{
Eric Moore29dd3602007-09-14 18:46:51 -0600181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
182 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
184 ioc->name, pg1->InvalidDwordCount));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
186 "Running Disparity Error Count=0x%x\n", ioc->name,
187 pg1->RunningDisparityErrorCount));
188 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
189 "Loss Dword Synch Count=0x%x\n", ioc->name,
190 pg1->LossDwordSynchCount));
191 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
192 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
193 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200194}
195
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530196static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200197{
198 __le64 sas_address;
199
200 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
201
Eric Moore29dd3602007-09-14 18:46:51 -0600202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
203 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
205 ioc->name, le16_to_cpu(pg0->DevHandle)));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
207 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
209 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
211 ioc->name, le16_to_cpu(pg0->Slot)));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
213 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
215 ioc->name, pg0->TargetID));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
217 ioc->name, pg0->Bus));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
219 ioc->name, pg0->PhyNum));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
221 ioc->name, le16_to_cpu(pg0->AccessStatus)));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
223 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
224 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
225 ioc->name, le16_to_cpu(pg0->Flags)));
226 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
227 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200228}
229
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530230static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200231{
Eric Moore29dd3602007-09-14 18:46:51 -0600232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
233 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
235 ioc->name, pg1->PhysicalPort));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
237 ioc->name, pg1->PhyIdentifier));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
239 ioc->name, pg1->NegotiatedLinkRate));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
241 ioc->name, pg1->ProgrammedLinkRate));
242 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
243 ioc->name, pg1->HwLinkRate));
244 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
245 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
246 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
247 "Attached Device Handle=0x%X\n\n", ioc->name,
248 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200249}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200250
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530251/* inhibit sas firmware event handling */
252static void
253mptsas_fw_event_off(MPT_ADAPTER *ioc)
254{
255 unsigned long flags;
256
257 spin_lock_irqsave(&ioc->fw_event_lock, flags);
258 ioc->fw_events_off = 1;
259 ioc->sas_discovery_quiesce_io = 0;
260 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
261
262}
263
264/* enable sas firmware event handling */
265static void
266mptsas_fw_event_on(MPT_ADAPTER *ioc)
267{
268 unsigned long flags;
269
270 spin_lock_irqsave(&ioc->fw_event_lock, flags);
271 ioc->fw_events_off = 0;
272 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
273}
274
275/* queue a sas firmware event */
276static void
277mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
278 unsigned long delay)
279{
280 unsigned long flags;
281
282 spin_lock_irqsave(&ioc->fw_event_lock, flags);
283 list_add_tail(&fw_event->list, &ioc->fw_event_list);
284 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
285 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
286 ioc->name, __func__, fw_event));
287 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
288 delay);
289 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
290}
291
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530292/* requeue a sas firmware event */
293static void
294mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
295 unsigned long delay)
296{
297 unsigned long flags;
298 spin_lock_irqsave(&ioc->fw_event_lock, flags);
299 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
300 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
301 fw_event->retries++;
302 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
303 msecs_to_jiffies(delay));
304 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
305}
306
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530307/* free memory assoicated to a sas firmware event */
308static void
309mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
310{
311 unsigned long flags;
312
313 spin_lock_irqsave(&ioc->fw_event_lock, flags);
314 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
315 ioc->name, __func__, fw_event));
316 list_del(&fw_event->list);
317 kfree(fw_event);
318 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
319}
320
321/* walk the firmware event queue, and either stop or wait for
322 * outstanding events to complete */
323static void
324mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
325{
326 struct fw_event_work *fw_event, *next;
327 struct mptsas_target_reset_event *target_reset_list, *n;
328 u8 flush_q;
329 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
348 flush_q = 0;
349 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
350 if (cancel_delayed_work(&fw_event->work))
351 mptsas_free_fw_event(ioc, fw_event);
352 else
353 flush_q = 1;
354 }
355 if (flush_q)
356 flush_workqueue(ioc->fw_event_q);
357}
358
359
Christoph Hellwige3094442006-02-16 13:25:36 +0100360static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
361{
362 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
363 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
364}
365
366static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
367{
368 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
369 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
370}
371
Moore, Erice6b2d762006-03-14 09:14:24 -0700372/*
373 * mptsas_find_portinfo_by_handle
374 *
375 * This function should be called with the sas_topology_mutex already held
376 */
377static struct mptsas_portinfo *
378mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
379{
380 struct mptsas_portinfo *port_info, *rc=NULL;
381 int i;
382
383 list_for_each_entry(port_info, &ioc->sas_topology, list)
384 for (i = 0; i < port_info->num_phys; i++)
385 if (port_info->phy_info[i].identify.handle == handle) {
386 rc = port_info;
387 goto out;
388 }
389 out:
390 return rc;
391}
392
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530393/**
394 * mptsas_find_portinfo_by_sas_address -
395 * @ioc: Pointer to MPT_ADAPTER structure
396 * @handle:
397 *
398 * This function should be called with the sas_topology_mutex already held
399 *
400 **/
401static struct mptsas_portinfo *
402mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
403{
404 struct mptsas_portinfo *port_info, *rc = NULL;
405 int i;
406
407 if (sas_address >= ioc->hba_port_sas_addr &&
408 sas_address < (ioc->hba_port_sas_addr +
409 ioc->hba_port_num_phy))
410 return ioc->hba_port_info;
411
412 mutex_lock(&ioc->sas_topology_mutex);
413 list_for_each_entry(port_info, &ioc->sas_topology, list)
414 for (i = 0; i < port_info->num_phys; i++)
415 if (port_info->phy_info[i].identify.sas_address ==
416 sas_address) {
417 rc = port_info;
418 goto out;
419 }
420 out:
421 mutex_unlock(&ioc->sas_topology_mutex);
422 return rc;
423}
424
Moore, Ericbd23e942006-04-17 12:43:04 -0600425/*
426 * Returns true if there is a scsi end device
427 */
428static inline int
429mptsas_is_end_device(struct mptsas_devinfo * attached)
430{
Eric Moore547f9a22006-06-27 14:42:12 -0600431 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600432 (attached->device_info &
433 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
434 ((attached->device_info &
435 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
436 (attached->device_info &
437 MPI_SAS_DEVICE_INFO_STP_TARGET) |
438 (attached->device_info &
439 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
440 return 1;
441 else
442 return 0;
443}
444
Eric Moore547f9a22006-06-27 14:42:12 -0600445/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600446static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530447mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600448{
449 struct mptsas_portinfo *port_info;
450 struct mptsas_phyinfo *phy_info;
451 u8 i;
452
453 if (!port_details)
454 return;
455
456 port_info = port_details->port_info;
457 phy_info = port_info->phy_info;
458
Eric Moore29dd3602007-09-14 18:46:51 -0600459 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700460 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700461 port_details->num_phys, (unsigned long long)
462 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600463
464 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
465 if(phy_info->port_details != port_details)
466 continue;
467 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530468 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600469 phy_info->port_details = NULL;
470 }
471 kfree(port_details);
472}
473
474static inline struct sas_rphy *
475mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
476{
477 if (phy_info->port_details)
478 return phy_info->port_details->rphy;
479 else
480 return NULL;
481}
482
483static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530484mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600485{
486 if (phy_info->port_details) {
487 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600488 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
489 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600490 }
491
Eric Moore547f9a22006-06-27 14:42:12 -0600492 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600493 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
494 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600495 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
496 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600497 }
Eric Moore547f9a22006-06-27 14:42:12 -0600498}
499
500static inline struct sas_port *
501mptsas_get_port(struct mptsas_phyinfo *phy_info)
502{
503 if (phy_info->port_details)
504 return phy_info->port_details->port;
505 else
506 return NULL;
507}
508
509static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530510mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600511{
512 if (phy_info->port_details)
513 phy_info->port_details->port = port;
514
Eric Moore547f9a22006-06-27 14:42:12 -0600515 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600516 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
517 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600518 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
519 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600520 }
Eric Moore547f9a22006-06-27 14:42:12 -0600521}
522
523static inline struct scsi_target *
524mptsas_get_starget(struct mptsas_phyinfo *phy_info)
525{
526 if (phy_info->port_details)
527 return phy_info->port_details->starget;
528 else
529 return NULL;
530}
531
532static inline void
533mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
534starget)
535{
536 if (phy_info->port_details)
537 phy_info->port_details->starget = starget;
538}
539
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530540/**
541 * mptsas_add_device_component -
542 * @ioc: Pointer to MPT_ADAPTER structure
543 * @channel: fw mapped id's
544 * @id:
545 * @sas_address:
546 * @device_info:
547 *
548 **/
549static void
550mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
551 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
552{
553 struct mptsas_device_info *sas_info, *next;
554 struct scsi_device *sdev;
555 struct scsi_target *starget;
556 struct sas_rphy *rphy;
557
558 /*
559 * Delete all matching devices out of the list
560 */
561 mutex_lock(&ioc->sas_device_info_mutex);
562 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
563 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530564 if (!sas_info->is_logical_volume &&
565 (sas_info->sas_address == sas_address ||
566 (sas_info->fw.channel == channel &&
567 sas_info->fw.id == id))) {
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530568 list_del(&sas_info->list);
569 kfree(sas_info);
570 }
571 }
572
573 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
574 if (!sas_info)
575 goto out;
576
577 /*
578 * Set Firmware mapping
579 */
580 sas_info->fw.id = id;
581 sas_info->fw.channel = channel;
582
583 sas_info->sas_address = sas_address;
584 sas_info->device_info = device_info;
585 sas_info->slot = slot;
586 sas_info->enclosure_logical_id = enclosure_logical_id;
587 INIT_LIST_HEAD(&sas_info->list);
588 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
589
590 /*
591 * Set OS mapping
592 */
593 shost_for_each_device(sdev, ioc->sh) {
594 starget = scsi_target(sdev);
595 rphy = dev_to_rphy(starget->dev.parent);
596 if (rphy->identify.sas_address == sas_address) {
597 sas_info->os.id = starget->id;
598 sas_info->os.channel = starget->channel;
599 }
600 }
601
602 out:
603 mutex_unlock(&ioc->sas_device_info_mutex);
604 return;
605}
606
607/**
608 * mptsas_add_device_component_by_fw -
609 * @ioc: Pointer to MPT_ADAPTER structure
610 * @channel: fw mapped id's
611 * @id:
612 *
613 **/
614static void
615mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
616{
617 struct mptsas_devinfo sas_device;
618 struct mptsas_enclosure enclosure_info;
619 int rc;
620
621 rc = mptsas_sas_device_pg0(ioc, &sas_device,
622 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
623 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
624 (channel << 8) + id);
625 if (rc)
626 return;
627
628 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
629 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
630 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
631 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
632 sas_device.handle_enclosure);
633
634 mptsas_add_device_component(ioc, sas_device.channel,
635 sas_device.id, sas_device.sas_address, sas_device.device_info,
636 sas_device.slot, enclosure_info.enclosure_logical_id);
637}
638
639/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000640 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530641 * @ioc: Pointer to MPT_ADAPTER structure
642 * @channel: fw mapped id's
643 * @id:
644 *
645 **/
646static void
647mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
648 struct scsi_target *starget)
649{
650 CONFIGPARMS cfg;
651 ConfigPageHeader_t hdr;
652 dma_addr_t dma_handle;
653 pRaidVolumePage0_t buffer = NULL;
654 int i;
655 RaidPhysDiskPage0_t phys_disk;
656 struct mptsas_device_info *sas_info, *next;
657
658 memset(&cfg, 0 , sizeof(CONFIGPARMS));
659 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
660 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
661 /* assumption that all volumes on channel = 0 */
662 cfg.pageAddr = starget->id;
663 cfg.cfghdr.hdr = &hdr;
664 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530665 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530666
667 if (mpt_config(ioc, &cfg) != 0)
668 goto out;
669
670 if (!hdr.PageLength)
671 goto out;
672
673 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
674 &dma_handle);
675
676 if (!buffer)
677 goto out;
678
679 cfg.physAddr = dma_handle;
680 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
681
682 if (mpt_config(ioc, &cfg) != 0)
683 goto out;
684
685 if (!buffer->NumPhysDisks)
686 goto out;
687
688 /*
689 * Adding entry for hidden components
690 */
691 for (i = 0; i < buffer->NumPhysDisks; i++) {
692
693 if (mpt_raid_phys_disk_pg0(ioc,
694 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
695 continue;
696
697 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
698 phys_disk.PhysDiskID);
699
Kashyap, Desai57e98512009-05-29 16:55:09 +0530700 mutex_lock(&ioc->sas_device_info_mutex);
701 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
702 list) {
703 if (!sas_info->is_logical_volume &&
704 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
705 sas_info->fw.id == phys_disk.PhysDiskID)) {
706 sas_info->is_hidden_raid_component = 1;
707 sas_info->volume_id = starget->id;
708 }
709 }
710 mutex_unlock(&ioc->sas_device_info_mutex);
711
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530712 }
713
714 /*
715 * Delete all matching devices out of the list
716 */
717 mutex_lock(&ioc->sas_device_info_mutex);
718 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
719 list) {
720 if (sas_info->is_logical_volume && sas_info->fw.id ==
721 starget->id) {
722 list_del(&sas_info->list);
723 kfree(sas_info);
724 }
725 }
726
727 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
728 if (sas_info) {
729 sas_info->fw.id = starget->id;
730 sas_info->os.id = starget->id;
731 sas_info->os.channel = starget->channel;
732 sas_info->is_logical_volume = 1;
733 INIT_LIST_HEAD(&sas_info->list);
734 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
735 }
736 mutex_unlock(&ioc->sas_device_info_mutex);
737
738 out:
739 if (buffer)
740 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
741 dma_handle);
742}
743
744/**
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530745 * mptsas_add_device_component_starget -
746 * @ioc: Pointer to MPT_ADAPTER structure
747 * @starget:
748 *
749 **/
750static void
751mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
752 struct scsi_target *starget)
753{
754 VirtTarget *vtarget;
755 struct sas_rphy *rphy;
756 struct mptsas_phyinfo *phy_info = NULL;
757 struct mptsas_enclosure enclosure_info;
758
759 rphy = dev_to_rphy(starget->dev.parent);
760 vtarget = starget->hostdata;
761 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
762 rphy->identify.sas_address);
763 if (!phy_info)
764 return;
765
766 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
767 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
768 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
769 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
770 phy_info->attached.handle_enclosure);
771
772 mptsas_add_device_component(ioc, phy_info->attached.channel,
773 phy_info->attached.id, phy_info->attached.sas_address,
774 phy_info->attached.device_info,
775 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
776}
777
778/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000779 * 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 +0530780 * @ioc: Pointer to MPT_ADAPTER structure
781 * @channel: os mapped id's
782 * @id:
783 *
784 **/
785static void
786mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
787{
788 struct mptsas_device_info *sas_info, *next;
789
790 /*
791 * Set is_cached flag
792 */
793 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
794 list) {
795 if (sas_info->os.channel == channel && sas_info->os.id == id)
796 sas_info->is_cached = 1;
797 }
798}
799
800/**
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530801 * mptsas_del_device_components - Cleaning the list
802 * @ioc: Pointer to MPT_ADAPTER structure
803 *
804 **/
805static void
806mptsas_del_device_components(MPT_ADAPTER *ioc)
807{
808 struct mptsas_device_info *sas_info, *next;
809
810 mutex_lock(&ioc->sas_device_info_mutex);
811 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
812 list) {
813 list_del(&sas_info->list);
814 kfree(sas_info);
815 }
816 mutex_unlock(&ioc->sas_device_info_mutex);
817}
818
Eric Moore547f9a22006-06-27 14:42:12 -0600819
820/*
821 * mptsas_setup_wide_ports
822 *
823 * Updates for new and existing narrow/wide port configuration
824 * in the sas_topology
825 */
Eric Moore376ac832006-06-29 17:36:26 -0600826static void
Eric Moore547f9a22006-06-27 14:42:12 -0600827mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
828{
829 struct mptsas_portinfo_details * port_details;
830 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
831 u64 sas_address;
832 int i, j;
833
834 mutex_lock(&ioc->sas_topology_mutex);
835
836 phy_info = port_info->phy_info;
837 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
838 if (phy_info->attached.handle)
839 continue;
840 port_details = phy_info->port_details;
841 if (!port_details)
842 continue;
843 if (port_details->num_phys < 2)
844 continue;
845 /*
846 * Removing a phy from a port, letting the last
847 * phy be removed by firmware events.
848 */
Eric Moore29dd3602007-09-14 18:46:51 -0600849 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
850 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700851 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600852 port_details->num_phys--;
853 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
854 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530855 if (phy_info->phy) {
856 devtprintk(ioc, dev_printk(KERN_DEBUG,
857 &phy_info->phy->dev, MYIOC_s_FMT
858 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
859 phy_info->phy_id, phy_info->phy));
860 sas_port_delete_phy(port_details->port, phy_info->phy);
861 }
Eric Moore547f9a22006-06-27 14:42:12 -0600862 phy_info->port_details = NULL;
863 }
864
865 /*
866 * Populate and refresh the tree
867 */
868 phy_info = port_info->phy_info;
869 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
870 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600871 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
872 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600873 if (!sas_address)
874 continue;
875 port_details = phy_info->port_details;
876 /*
877 * Forming a port
878 */
879 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530880 port_details = kzalloc(sizeof(struct
881 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600882 if (!port_details)
883 goto out;
884 port_details->num_phys = 1;
885 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600886 if (phy_info->phy_id < 64 )
887 port_details->phy_bitmask |=
888 (1 << phy_info->phy_id);
889 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600890 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700891 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600892 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600893 phy_info->port_details = port_details;
894 }
895
896 if (i == port_info->num_phys - 1)
897 continue;
898 phy_info_cmp = &port_info->phy_info[i + 1];
899 for (j = i + 1 ; j < port_info->num_phys ; j++,
900 phy_info_cmp++) {
901 if (!phy_info_cmp->attached.sas_address)
902 continue;
903 if (sas_address != phy_info_cmp->attached.sas_address)
904 continue;
905 if (phy_info_cmp->port_details == port_details )
906 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600907 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700908 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600909 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700910 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600911 if (phy_info_cmp->port_details) {
912 port_details->rphy =
913 mptsas_get_rphy(phy_info_cmp);
914 port_details->port =
915 mptsas_get_port(phy_info_cmp);
916 port_details->starget =
917 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600918 port_details->num_phys =
919 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600920 if (!phy_info_cmp->port_details->num_phys)
921 kfree(phy_info_cmp->port_details);
922 } else
923 phy_info_cmp->sas_port_add_phy=1;
924 /*
925 * Adding a phy to a port
926 */
927 phy_info_cmp->port_details = port_details;
928 if (phy_info_cmp->phy_id < 64 )
929 port_details->phy_bitmask |=
930 (1 << phy_info_cmp->phy_id);
931 port_details->num_phys++;
932 }
933 }
934
935 out:
936
Eric Moore547f9a22006-06-27 14:42:12 -0600937 for (i = 0; i < port_info->num_phys; i++) {
938 port_details = port_info->phy_info[i].port_details;
939 if (!port_details)
940 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600941 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700942 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700943 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700944 port_details, i, port_details->num_phys,
945 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600946 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
947 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600948 }
Eric Moore29dd3602007-09-14 18:46:51 -0600949 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600950 mutex_unlock(&ioc->sas_topology_mutex);
951}
952
Eric Mooredf9e0622007-01-29 09:46:21 -0700953/**
954 * csmisas_find_vtarget
955 *
956 * @ioc
957 * @volume_id
958 * @volume_bus
959 *
960 **/
961static VirtTarget *
962mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600963{
Eric Mooredf9e0622007-01-29 09:46:21 -0700964 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600965 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700966 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600967
Eric Mooredf9e0622007-01-29 09:46:21 -0700968 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530969 vdevice = sdev->hostdata;
970 if ((vdevice == NULL) ||
971 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700972 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530973 if ((vdevice->vtarget->tflags &
974 MPT_TARGET_FLAGS_RAID_COMPONENT ||
975 vdevice->vtarget->raidVolume))
976 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600977 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530978 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600979 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600980 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700981 return vtarget;
982}
983
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530984static void
985mptsas_queue_device_delete(MPT_ADAPTER *ioc,
986 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
987{
988 struct fw_event_work *fw_event;
989 int sz;
990
991 sz = offsetof(struct fw_event_work, event_data) +
992 sizeof(MpiEventDataSasDeviceStatusChange_t);
993 fw_event = kzalloc(sz, GFP_ATOMIC);
994 if (!fw_event) {
995 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
996 ioc->name, __func__, __LINE__);
997 return;
998 }
999 memcpy(fw_event->event_data, sas_event_data,
1000 sizeof(MpiEventDataSasDeviceStatusChange_t));
1001 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
1002 fw_event->ioc = ioc;
1003 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1004}
1005
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301006static void
1007mptsas_queue_rescan(MPT_ADAPTER *ioc)
1008{
1009 struct fw_event_work *fw_event;
1010 int sz;
1011
1012 sz = offsetof(struct fw_event_work, event_data);
1013 fw_event = kzalloc(sz, GFP_ATOMIC);
1014 if (!fw_event) {
1015 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1016 ioc->name, __func__, __LINE__);
1017 return;
1018 }
1019 fw_event->event = -1;
1020 fw_event->ioc = ioc;
1021 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1022}
1023
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301024
Eric Mooredf9e0622007-01-29 09:46:21 -07001025/**
1026 * mptsas_target_reset
1027 *
1028 * Issues TARGET_RESET to end device using handshaking method
1029 *
1030 * @ioc
1031 * @channel
1032 * @id
1033 *
1034 * Returns (1) success
1035 * (0) failure
1036 *
1037 **/
1038static int
1039mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1040{
1041 MPT_FRAME_HDR *mf;
1042 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301043 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1044 return 0;
1045
Eric Mooredf9e0622007-01-29 09:46:21 -07001046
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301047 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1048 if (mf == NULL) {
1049 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301050 "%s, no msg frames @%d!!\n", ioc->name,
1051 __func__, __LINE__));
1052 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001053 }
1054
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301055 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1056 ioc->name, mf));
1057
Eric Mooredf9e0622007-01-29 09:46:21 -07001058 /* Format the Request
1059 */
1060 pScsiTm = (SCSITaskMgmt_t *) mf;
1061 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1062 pScsiTm->TargetID = id;
1063 pScsiTm->Bus = channel;
1064 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1065 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1066 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1067
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301068 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001069
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301070 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1071 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1072 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1073
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301074 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001075
1076 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301077
1078 out_fail:
1079
1080 mpt_clear_taskmgmt_in_progress_flag(ioc);
1081 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001082}
1083
1084/**
1085 * mptsas_target_reset_queue
1086 *
1087 * Receive request for TARGET_RESET after recieving an firmware
1088 * event NOT_RESPONDING_EVENT, then put command in link list
1089 * and queue if task_queue already in use.
1090 *
1091 * @ioc
1092 * @sas_event_data
1093 *
1094 **/
1095static void
1096mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1097 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1098{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001099 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001100 VirtTarget *vtarget = NULL;
1101 struct mptsas_target_reset_event *target_reset_list;
1102 u8 id, channel;
1103
1104 id = sas_event_data->TargetID;
1105 channel = sas_event_data->Bus;
1106
1107 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
1108 return;
1109
1110 vtarget->deleted = 1; /* block IO */
1111
Kashyap, Desai2f187862009-05-29 16:52:37 +05301112 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001113 GFP_ATOMIC);
1114 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301115 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1116 "%s, failed to allocate mem @%d..!!\n",
1117 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001118 return;
1119 }
1120
1121 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1122 sizeof(*sas_event_data));
1123 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1124
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301125 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001126
1127 if (mptsas_target_reset(ioc, channel, id)) {
1128 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001129 }
1130}
1131
1132/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001133 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301134 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001135 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001136 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1137 * queue to finish off removing device from upper layers. then send next
1138 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001139 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301140static int
1141mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001142{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001143 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001144 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001145 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301146 struct mptsas_target_reset_event *target_reset_list;
1147 SCSITaskMgmtReply_t *pScsiTmReply;
1148
1149 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1150 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1151
1152 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1153 if (pScsiTmReply) {
1154 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1155 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1156 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1157 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1158 "term_cmnds = %d\n", ioc->name,
1159 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1160 pScsiTmReply->TaskType,
1161 le16_to_cpu(pScsiTmReply->IOCStatus),
1162 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1163 pScsiTmReply->ResponseCode,
1164 le32_to_cpu(pScsiTmReply->TerminationCount)));
1165
1166 if (pScsiTmReply->ResponseCode)
1167 mptscsih_taskmgmt_response_code(ioc,
1168 pScsiTmReply->ResponseCode);
1169 }
1170
1171 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1172 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1173 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1174 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1175 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1176 memcpy(ioc->taskmgmt_cmds.reply, mr,
1177 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1178 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1179 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1180 complete(&ioc->taskmgmt_cmds.done);
1181 return 1;
1182 }
1183 return 0;
1184 }
1185
1186 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001187
1188 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301189 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001190
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301191 target_reset_list = list_entry(head->next,
1192 struct mptsas_target_reset_event, list);
1193
1194 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1195 "TaskMgmt: completed (%d seconds)\n",
1196 ioc->name, jiffies_to_msecs(jiffies -
1197 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001198
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301199 id = pScsiTmReply->TargetID;
1200 channel = pScsiTmReply->Bus;
1201 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001202
1203 /*
1204 * retry target reset
1205 */
1206 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301207 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001208 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301209 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001210 }
1211
1212 /*
1213 * enable work queue to remove device from upper layers
1214 */
1215 list_del(&target_reset_list->list);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301216 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1217 mptsas_queue_device_delete(ioc,
1218 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301219
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301220
Eric Mooredf9e0622007-01-29 09:46:21 -07001221 /*
1222 * issue target reset to next device in the queue
1223 */
1224
1225 head = &hd->target_reset_list;
1226 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301227 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001228
1229 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1230 list);
1231
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301232 id = target_reset_list->sas_event_data.TargetID;
1233 channel = target_reset_list->sas_event_data.Bus;
1234 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001235
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301236 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001237 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001238
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301239 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001240}
1241
1242/**
1243 * mptscsih_ioc_reset
1244 *
1245 * @ioc
1246 * @reset_phase
1247 *
1248 **/
1249static int
1250mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1251{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001252 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001253 int rc;
1254
1255 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301256 if ((ioc->bus_type != SAS) || (!rc))
1257 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001258
Eric Mooree7eae9f2007-09-29 10:15:59 -06001259 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001260 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001261 goto out;
1262
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301263 switch (reset_phase) {
1264 case MPT_IOC_SETUP_RESET:
1265 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1266 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1267 mptsas_fw_event_off(ioc);
1268 break;
1269 case MPT_IOC_PRE_RESET:
1270 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1271 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1272 break;
1273 case MPT_IOC_POST_RESET:
1274 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1275 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1276 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1277 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1278 complete(&ioc->sas_mgmt.done);
1279 }
1280 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301281 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301282 mptsas_fw_event_on(ioc);
1283 break;
1284 default:
1285 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001286 }
1287
1288 out:
1289 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001290}
1291
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301292
1293/**
1294 * enum device_state -
1295 * @DEVICE_RETRY: need to retry the TUR
1296 * @DEVICE_ERROR: TUR return error, don't add device
1297 * @DEVICE_READY: device can be added
1298 *
1299 */
1300enum device_state{
1301 DEVICE_RETRY,
1302 DEVICE_ERROR,
1303 DEVICE_READY,
1304};
1305
Christoph Hellwige3094442006-02-16 13:25:36 +01001306static int
Moore, Eric52435432006-03-14 09:14:15 -07001307mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001308 u32 form, u32 form_specific)
1309{
1310 ConfigExtendedPageHeader_t hdr;
1311 CONFIGPARMS cfg;
1312 SasEnclosurePage0_t *buffer;
1313 dma_addr_t dma_handle;
1314 int error;
1315 __le64 le_identifier;
1316
1317 memset(&hdr, 0, sizeof(hdr));
1318 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1319 hdr.PageNumber = 0;
1320 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1321 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1322
1323 cfg.cfghdr.ehdr = &hdr;
1324 cfg.physAddr = -1;
1325 cfg.pageAddr = form + form_specific;
1326 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1327 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301328 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001329
1330 error = mpt_config(ioc, &cfg);
1331 if (error)
1332 goto out;
1333 if (!hdr.ExtPageLength) {
1334 error = -ENXIO;
1335 goto out;
1336 }
1337
1338 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1339 &dma_handle);
1340 if (!buffer) {
1341 error = -ENOMEM;
1342 goto out;
1343 }
1344
1345 cfg.physAddr = dma_handle;
1346 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1347
1348 error = mpt_config(ioc, &cfg);
1349 if (error)
1350 goto out_free_consistent;
1351
1352 /* save config data */
1353 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1354 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1355 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1356 enclosure->flags = le16_to_cpu(buffer->Flags);
1357 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1358 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1359 enclosure->start_id = buffer->StartTargetID;
1360 enclosure->start_channel = buffer->StartBus;
1361 enclosure->sep_id = buffer->SEPTargetID;
1362 enclosure->sep_channel = buffer->SEPBus;
1363
1364 out_free_consistent:
1365 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1366 buffer, dma_handle);
1367 out:
1368 return error;
1369}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001370
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301371/**
1372 * mptsas_add_end_device - report a new end device to sas transport layer
1373 * @ioc: Pointer to MPT_ADAPTER structure
1374 * @phy_info: decribes attached device
1375 *
1376 * return (0) success (1) failure
1377 *
1378 **/
1379static int
1380mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1381{
1382 struct sas_rphy *rphy;
1383 struct sas_port *port;
1384 struct sas_identify identify;
1385 char *ds = NULL;
1386 u8 fw_id;
1387
1388 if (!phy_info) {
1389 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1390 "%s: exit at line=%d\n", ioc->name,
1391 __func__, __LINE__));
1392 return 1;
1393 }
1394
1395 fw_id = phy_info->attached.id;
1396
1397 if (mptsas_get_rphy(phy_info)) {
1398 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1399 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1400 __func__, fw_id, __LINE__));
1401 return 2;
1402 }
1403
1404 port = mptsas_get_port(phy_info);
1405 if (!port) {
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 3;
1410 }
1411
1412 if (phy_info->attached.device_info &
1413 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1414 ds = "ssp";
1415 if (phy_info->attached.device_info &
1416 MPI_SAS_DEVICE_INFO_STP_TARGET)
1417 ds = "stp";
1418 if (phy_info->attached.device_info &
1419 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1420 ds = "sata";
1421
1422 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1423 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1424 phy_info->attached.channel, phy_info->attached.id,
1425 phy_info->attached.phy_id, (unsigned long long)
1426 phy_info->attached.sas_address);
1427
1428 mptsas_parse_device_info(&identify, &phy_info->attached);
1429 rphy = sas_end_device_alloc(port);
1430 if (!rphy) {
1431 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1432 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1433 __func__, fw_id, __LINE__));
1434 return 5; /* non-fatal: an rphy can be added later */
1435 }
1436
1437 rphy->identify = identify;
1438 if (sas_rphy_add(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 sas_rphy_free(rphy);
1443 return 6;
1444 }
1445 mptsas_set_rphy(ioc, phy_info, rphy);
1446 return 0;
1447}
1448
1449/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001450 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301451 * @ioc: Pointer to MPT_ADAPTER structure
1452 * @phy_info: decribes attached device
1453 *
1454 **/
1455static void
1456mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1457{
1458 struct sas_rphy *rphy;
1459 struct sas_port *port;
1460 struct mptsas_portinfo *port_info;
1461 struct mptsas_phyinfo *phy_info_parent;
1462 int i;
1463 char *ds = NULL;
1464 u8 fw_id;
1465 u64 sas_address;
1466
1467 if (!phy_info)
1468 return;
1469
1470 fw_id = phy_info->attached.id;
1471 sas_address = phy_info->attached.sas_address;
1472
1473 if (!phy_info->port_details) {
1474 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1475 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1476 __func__, fw_id, __LINE__));
1477 return;
1478 }
1479 rphy = mptsas_get_rphy(phy_info);
1480 if (!rphy) {
1481 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1482 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1483 __func__, fw_id, __LINE__));
1484 return;
1485 }
1486
1487 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1488 || phy_info->attached.device_info
1489 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1490 || phy_info->attached.device_info
1491 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1492 ds = "initiator";
1493 if (phy_info->attached.device_info &
1494 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1495 ds = "ssp";
1496 if (phy_info->attached.device_info &
1497 MPI_SAS_DEVICE_INFO_STP_TARGET)
1498 ds = "stp";
1499 if (phy_info->attached.device_info &
1500 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1501 ds = "sata";
1502
1503 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1504 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1505 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1506 phy_info->attached.id, phy_info->attached.phy_id,
1507 (unsigned long long) sas_address);
1508
1509 port = mptsas_get_port(phy_info);
1510 if (!port) {
1511 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1512 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1513 __func__, fw_id, __LINE__));
1514 return;
1515 }
1516 port_info = phy_info->portinfo;
1517 phy_info_parent = port_info->phy_info;
1518 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1519 if (!phy_info_parent->phy)
1520 continue;
1521 if (phy_info_parent->attached.sas_address !=
1522 sas_address)
1523 continue;
1524 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1525 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1526 ioc->name, phy_info_parent->phy_id,
1527 phy_info_parent->phy);
1528 sas_port_delete_phy(port, phy_info_parent->phy);
1529 }
1530
1531 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1532 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1533 port->port_identifier, (unsigned long long)sas_address);
1534 sas_port_delete(port);
1535 mptsas_set_port(ioc, phy_info, NULL);
1536 mptsas_port_delete(ioc, phy_info->port_details);
1537}
1538
1539struct mptsas_phyinfo *
1540mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1541 struct mptsas_devinfo *sas_device)
1542{
1543 struct mptsas_phyinfo *phy_info;
1544 struct mptsas_portinfo *port_info;
1545 int i;
1546
1547 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1548 sas_device->sas_address);
1549 if (!phy_info)
1550 goto out;
1551 port_info = phy_info->portinfo;
1552 if (!port_info)
1553 goto out;
1554 mutex_lock(&ioc->sas_topology_mutex);
1555 for (i = 0; i < port_info->num_phys; i++) {
1556 if (port_info->phy_info[i].attached.sas_address !=
1557 sas_device->sas_address)
1558 continue;
1559 port_info->phy_info[i].attached.channel = sas_device->channel;
1560 port_info->phy_info[i].attached.id = sas_device->id;
1561 port_info->phy_info[i].attached.sas_address =
1562 sas_device->sas_address;
1563 port_info->phy_info[i].attached.handle = sas_device->handle;
1564 port_info->phy_info[i].attached.handle_parent =
1565 sas_device->handle_parent;
1566 port_info->phy_info[i].attached.handle_enclosure =
1567 sas_device->handle_enclosure;
1568 }
1569 mutex_unlock(&ioc->sas_topology_mutex);
1570 out:
1571 return phy_info;
1572}
1573
1574/**
1575 * mptsas_firmware_event_work - work thread for processing fw events
1576 * @work: work queue payload containing info describing the event
1577 * Context: user
1578 *
1579 */
1580static void
1581mptsas_firmware_event_work(struct work_struct *work)
1582{
1583 struct fw_event_work *fw_event =
1584 container_of(work, struct fw_event_work, work.work);
1585 MPT_ADAPTER *ioc = fw_event->ioc;
1586
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301587 /* special rescan topology handling */
1588 if (fw_event->event == -1) {
1589 if (ioc->in_rescan) {
1590 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1591 "%s: rescan ignored as it is in progress\n",
1592 ioc->name, __func__));
1593 return;
1594 }
1595 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1596 "reset\n", ioc->name, __func__));
1597 ioc->in_rescan = 1;
1598 mptsas_not_responding_devices(ioc);
1599 mptsas_scan_sas_topology(ioc);
1600 ioc->in_rescan = 0;
1601 mptsas_free_fw_event(ioc, fw_event);
1602 return;
1603 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301604
1605 /* events handling turned off during host reset */
1606 if (ioc->fw_events_off) {
1607 mptsas_free_fw_event(ioc, fw_event);
1608 return;
1609 }
1610
1611 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1612 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1613 (fw_event->event & 0xFF)));
1614
1615 switch (fw_event->event) {
1616 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1617 mptsas_send_sas_event(fw_event);
1618 break;
1619 case MPI_EVENT_INTEGRATED_RAID:
1620 mptsas_send_raid_event(fw_event);
1621 break;
1622 case MPI_EVENT_IR2:
1623 mptsas_send_ir2_event(fw_event);
1624 break;
1625 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1626 mptbase_sas_persist_operation(ioc,
1627 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1628 mptsas_free_fw_event(ioc, fw_event);
1629 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301630 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1631 mptsas_broadcast_primative_work(fw_event);
1632 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301633 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1634 mptsas_send_expander_event(fw_event);
1635 break;
1636 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1637 mptsas_send_link_status_event(fw_event);
1638 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301639 case MPI_EVENT_QUEUE_FULL:
1640 mptsas_handle_queue_full_event(fw_event);
1641 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301642 }
1643}
1644
1645
1646
James Bottomleyf013db32006-03-18 14:54:36 -06001647static int
1648mptsas_slave_configure(struct scsi_device *sdev)
1649{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301650 struct Scsi_Host *host = sdev->host;
1651 MPT_SCSI_HOST *hd = shost_priv(host);
1652 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301653 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001654
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301655 if (vdevice->vtarget->deleted) {
1656 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1657 vdevice->vtarget->deleted = 0;
1658 }
1659
1660 /*
1661 * RAID volumes placed beyond the last expected port.
1662 * Ignore sending sas mode pages in that case..
1663 */
1664 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1665 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001666 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301667 }
James Bottomleyf013db32006-03-18 14:54:36 -06001668
James Bottomleye8bf3942006-07-11 17:49:34 -04001669 sas_read_port_mode_page(sdev);
1670
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301671 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1672
James Bottomleye8bf3942006-07-11 17:49:34 -04001673 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001674 return mptscsih_slave_configure(sdev);
1675}
1676
Eric Moore547f9a22006-06-27 14:42:12 -06001677static int
1678mptsas_target_alloc(struct scsi_target *starget)
1679{
1680 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001681 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001682 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001683 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001684 struct sas_rphy *rphy;
1685 struct mptsas_portinfo *p;
1686 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001687 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001688
1689 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1690 if (!vtarget)
1691 return -ENOMEM;
1692
1693 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001694 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001695 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1696 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001697 channel = 0;
1698
Eric Moore793955f2007-01-29 09:42:20 -07001699 /*
1700 * RAID volumes placed beyond the last expected port.
1701 */
1702 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301703 if (!ioc->raid_data.pIocPg2) {
1704 kfree(vtarget);
1705 return -ENXIO;
1706 }
1707 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1708 if (id == ioc->raid_data.pIocPg2->
1709 RaidVolume[i].VolumeID) {
1710 channel = ioc->raid_data.pIocPg2->
1711 RaidVolume[i].VolumeBus;
1712 }
1713 }
1714 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001715 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001716 }
Eric Moore547f9a22006-06-27 14:42:12 -06001717
1718 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001719 mutex_lock(&ioc->sas_topology_mutex);
1720 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001721 for (i = 0; i < p->num_phys; i++) {
1722 if (p->phy_info[i].attached.sas_address !=
1723 rphy->identify.sas_address)
1724 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001725 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001726 channel = p->phy_info[i].attached.channel;
1727 mptsas_set_starget(&p->phy_info[i], starget);
1728
1729 /*
1730 * Exposing hidden raid components
1731 */
Eric Mooree80b0022007-09-14 18:49:03 -06001732 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1733 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001734 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001735 vtarget->tflags |=
1736 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001737 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001738 }
Eric Mooree80b0022007-09-14 18:49:03 -06001739 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001740 goto out;
1741 }
1742 }
Eric Mooree80b0022007-09-14 18:49:03 -06001743 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001744
1745 kfree(vtarget);
1746 return -ENXIO;
1747
1748 out:
Eric Moore793955f2007-01-29 09:42:20 -07001749 vtarget->id = id;
1750 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001751 starget->hostdata = vtarget;
1752 return 0;
1753}
1754
1755static void
1756mptsas_target_destroy(struct scsi_target *starget)
1757{
1758 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001759 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001760 struct sas_rphy *rphy;
1761 struct mptsas_portinfo *p;
1762 int i;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301763 MPT_ADAPTER *ioc = hd->ioc;
1764 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001765
1766 if (!starget->hostdata)
1767 return;
1768
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301769 vtarget = starget->hostdata;
1770
Kashyap, Desai57e98512009-05-29 16:55:09 +05301771 mptsas_del_device_component_by_os(ioc, starget->channel,
1772 starget->id);
1773
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301774
James Bottomleye8bf3942006-07-11 17:49:34 -04001775 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001776 goto out;
1777
1778 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001779 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001780 for (i = 0; i < p->num_phys; i++) {
1781 if (p->phy_info[i].attached.sas_address !=
1782 rphy->identify.sas_address)
1783 continue;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301784
1785 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1786 "delete device: fw_channel %d, fw_id %d, phy %d, "
1787 "sas_addr 0x%llx\n", ioc->name,
1788 p->phy_info[i].attached.channel,
1789 p->phy_info[i].attached.id,
1790 p->phy_info[i].attached.phy_id, (unsigned long long)
1791 p->phy_info[i].attached.sas_address);
1792
Eric Moore547f9a22006-06-27 14:42:12 -06001793 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001794 }
1795 }
1796
1797 out:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301798 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001799 kfree(starget->hostdata);
1800 starget->hostdata = NULL;
1801}
1802
1803
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001804static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001805mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001806{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001807 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001808 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001809 struct sas_rphy *rphy;
1810 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001811 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001812 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001813 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001814 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001815
Eric Moorea69de502007-09-14 18:48:19 -06001816 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1817 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001818 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001819 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001820 return -ENOMEM;
1821 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001822 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001823 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824
James Bottomleye8bf3942006-07-11 17:49:34 -04001825 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001826 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001827
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001828 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001829 mutex_lock(&ioc->sas_topology_mutex);
1830 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001831 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001832 if (p->phy_info[i].attached.sas_address !=
1833 rphy->identify.sas_address)
1834 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001835 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001836 /*
1837 * Exposing hidden raid components
1838 */
Eric Mooree80b0022007-09-14 18:49:03 -06001839 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001840 p->phy_info[i].attached.channel,
1841 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001842 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001843 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001844 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001845 }
1846 }
Eric Mooree80b0022007-09-14 18:49:03 -06001847 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001848
Eric Moorea69de502007-09-14 18:48:19 -06001849 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001850 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001851
1852 out:
Eric Moorea69de502007-09-14 18:48:19 -06001853 vdevice->vtarget->num_luns++;
1854 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001855 return 0;
1856}
1857
Eric Moore547f9a22006-06-27 14:42:12 -06001858static int
1859mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001860{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301861 MPT_SCSI_HOST *hd;
1862 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001863 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001864
Eric Moorea69de502007-09-14 18:48:19 -06001865 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001866 SCpnt->result = DID_NO_CONNECT << 16;
1867 done(SCpnt);
1868 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001869 }
Eric Moore547f9a22006-06-27 14:42:12 -06001870
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301871 hd = shost_priv(SCpnt->device->host);
1872 ioc = hd->ioc;
1873
1874 if (ioc->sas_discovery_quiesce_io)
1875 return SCSI_MLQUEUE_HOST_BUSY;
1876
Eric Moore793955f2007-01-29 09:42:20 -07001877// scsi_print_command(SCpnt);
1878
Eric Moore547f9a22006-06-27 14:42:12 -06001879 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001880}
1881
Eric Moore547f9a22006-06-27 14:42:12 -06001882
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001883static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001884 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001885 .proc_name = "mptsas",
1886 .proc_info = mptscsih_proc_info,
1887 .name = "MPT SPI Host",
1888 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001889 .queuecommand = mptsas_qcmd,
1890 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001891 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001892 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001893 .target_destroy = mptsas_target_destroy,
1894 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001895 .change_queue_depth = mptscsih_change_queue_depth,
1896 .eh_abort_handler = mptscsih_abort,
1897 .eh_device_reset_handler = mptscsih_dev_reset,
1898 .eh_bus_reset_handler = mptscsih_bus_reset,
1899 .eh_host_reset_handler = mptscsih_host_reset,
1900 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301901 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001902 .this_id = -1,
1903 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1904 .max_sectors = 8192,
1905 .cmd_per_lun = 7,
1906 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301907 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001908};
1909
Christoph Hellwigb5141122005-10-28 22:07:41 +02001910static int mptsas_get_linkerrors(struct sas_phy *phy)
1911{
1912 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1913 ConfigExtendedPageHeader_t hdr;
1914 CONFIGPARMS cfg;
1915 SasPhyPage1_t *buffer;
1916 dma_addr_t dma_handle;
1917 int error;
1918
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001919 /* FIXME: only have link errors on local phys */
1920 if (!scsi_is_sas_phy_local(phy))
1921 return -EINVAL;
1922
Christoph Hellwigb5141122005-10-28 22:07:41 +02001923 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1924 hdr.ExtPageLength = 0;
1925 hdr.PageNumber = 1 /* page number 1*/;
1926 hdr.Reserved1 = 0;
1927 hdr.Reserved2 = 0;
1928 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1929 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1930
1931 cfg.cfghdr.ehdr = &hdr;
1932 cfg.physAddr = -1;
1933 cfg.pageAddr = phy->identify.phy_identifier;
1934 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1935 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301936 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02001937
1938 error = mpt_config(ioc, &cfg);
1939 if (error)
1940 return error;
1941 if (!hdr.ExtPageLength)
1942 return -ENXIO;
1943
1944 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1945 &dma_handle);
1946 if (!buffer)
1947 return -ENOMEM;
1948
1949 cfg.physAddr = dma_handle;
1950 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1951
1952 error = mpt_config(ioc, &cfg);
1953 if (error)
1954 goto out_free_consistent;
1955
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301956 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001957
1958 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1959 phy->running_disparity_error_count =
1960 le32_to_cpu(buffer->RunningDisparityErrorCount);
1961 phy->loss_of_dword_sync_count =
1962 le32_to_cpu(buffer->LossDwordSynchCount);
1963 phy->phy_reset_problem_count =
1964 le32_to_cpu(buffer->PhyResetProblemCount);
1965
1966 out_free_consistent:
1967 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1968 buffer, dma_handle);
1969 return error;
1970}
1971
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001972static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1973 MPT_FRAME_HDR *reply)
1974{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301975 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001976 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301977 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001978 memcpy(ioc->sas_mgmt.reply, reply,
1979 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1980 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301981
1982 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1983 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1984 complete(&ioc->sas_mgmt.done);
1985 return 1;
1986 }
1987 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001988}
1989
1990static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1991{
1992 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1993 SasIoUnitControlRequest_t *req;
1994 SasIoUnitControlReply_t *reply;
1995 MPT_FRAME_HDR *mf;
1996 MPIHeader_t *hdr;
1997 unsigned long timeleft;
1998 int error = -ERESTARTSYS;
1999
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002000 /* FIXME: fusion doesn't allow non-local phy reset */
2001 if (!scsi_is_sas_phy_local(phy))
2002 return -EINVAL;
2003
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002004 /* not implemented for expanders */
2005 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2006 return -ENXIO;
2007
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002008 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002009 goto out;
2010
2011 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2012 if (!mf) {
2013 error = -ENOMEM;
2014 goto out_unlock;
2015 }
2016
2017 hdr = (MPIHeader_t *) mf;
2018 req = (SasIoUnitControlRequest_t *)mf;
2019 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2020 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2021 req->MsgContext = hdr->MsgContext;
2022 req->Operation = hard_reset ?
2023 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2024 req->PhyNum = phy->identify.phy_identifier;
2025
Kashyap, Desai2f187862009-05-29 16:52:37 +05302026 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002027 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2028
2029 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2030 10 * HZ);
2031 if (!timeleft) {
2032 /* On timeout reset the board */
2033 mpt_free_msg_frame(ioc, mf);
2034 mpt_HardResetHandler(ioc, CAN_SLEEP);
2035 error = -ETIMEDOUT;
2036 goto out_unlock;
2037 }
2038
2039 /* a reply frame is expected */
2040 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302041 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002042 error = -ENXIO;
2043 goto out_unlock;
2044 }
2045
2046 /* process the completed Reply Message Frame */
2047 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2048 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002049 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002050 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002051 error = -ENXIO;
2052 goto out_unlock;
2053 }
2054
2055 error = 0;
2056
2057 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302058 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002059 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002060 out:
2061 return error;
2062}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002063
Christoph Hellwige3094442006-02-16 13:25:36 +01002064static int
2065mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2066{
2067 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2068 int i, error;
2069 struct mptsas_portinfo *p;
2070 struct mptsas_enclosure enclosure_info;
2071 u64 enclosure_handle;
2072
2073 mutex_lock(&ioc->sas_topology_mutex);
2074 list_for_each_entry(p, &ioc->sas_topology, list) {
2075 for (i = 0; i < p->num_phys; i++) {
2076 if (p->phy_info[i].attached.sas_address ==
2077 rphy->identify.sas_address) {
2078 enclosure_handle = p->phy_info[i].
2079 attached.handle_enclosure;
2080 goto found_info;
2081 }
2082 }
2083 }
2084 mutex_unlock(&ioc->sas_topology_mutex);
2085 return -ENXIO;
2086
2087 found_info:
2088 mutex_unlock(&ioc->sas_topology_mutex);
2089 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002090 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002091 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2092 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2093 if (!error)
2094 *identifier = enclosure_info.enclosure_logical_id;
2095 return error;
2096}
2097
2098static int
2099mptsas_get_bay_identifier(struct sas_rphy *rphy)
2100{
2101 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2102 struct mptsas_portinfo *p;
2103 int i, rc;
2104
2105 mutex_lock(&ioc->sas_topology_mutex);
2106 list_for_each_entry(p, &ioc->sas_topology, list) {
2107 for (i = 0; i < p->num_phys; i++) {
2108 if (p->phy_info[i].attached.sas_address ==
2109 rphy->identify.sas_address) {
2110 rc = p->phy_info[i].attached.slot;
2111 goto out;
2112 }
2113 }
2114 }
2115 rc = -ENXIO;
2116 out:
2117 mutex_unlock(&ioc->sas_topology_mutex);
2118 return rc;
2119}
2120
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002121static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2122 struct request *req)
2123{
2124 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2125 MPT_FRAME_HDR *mf;
2126 SmpPassthroughRequest_t *smpreq;
2127 struct request *rsp = req->next_rq;
2128 int ret;
2129 int flagsLength;
2130 unsigned long timeleft;
2131 char *psge;
2132 dma_addr_t dma_addr_in = 0;
2133 dma_addr_t dma_addr_out = 0;
2134 u64 sas_address = 0;
2135
2136 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002137 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002138 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002139 return -EINVAL;
2140 }
2141
2142 /* do we need to support multiple segments? */
2143 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002144 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002145 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2146 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002147 return -EINVAL;
2148 }
2149
2150 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2151 if (ret)
2152 goto out;
2153
2154 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2155 if (!mf) {
2156 ret = -ENOMEM;
2157 goto out_unlock;
2158 }
2159
2160 smpreq = (SmpPassthroughRequest_t *)mf;
2161 memset(smpreq, 0, sizeof(*smpreq));
2162
Tejun Heob0790412009-05-07 22:24:42 +09002163 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002164 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2165
2166 if (rphy)
2167 sas_address = rphy->identify.sas_address;
2168 else {
2169 struct mptsas_portinfo *port_info;
2170
2171 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302172 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002173 if (port_info && port_info->phy_info)
2174 sas_address =
2175 port_info->phy_info[0].phy->identify.sas_address;
2176 mutex_unlock(&ioc->sas_topology_mutex);
2177 }
2178
2179 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2180
2181 psge = (char *)
2182 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2183
2184 /* request */
2185 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2186 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302187 MPI_SGE_FLAGS_DIRECTION)
2188 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002189 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002190
2191 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002192 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002193 if (!dma_addr_out)
2194 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302195 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302196 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002197
2198 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302199 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2200 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2201 MPI_SGE_FLAGS_IOC_TO_HOST |
2202 MPI_SGE_FLAGS_END_OF_BUFFER;
2203
2204 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002205 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002206 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002207 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002208 if (!dma_addr_in)
2209 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302210 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002211
Kashyap, Desai2f187862009-05-29 16:52:37 +05302212 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002213 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2214
2215 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2216 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002217 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002218 /* On timeout reset the board */
2219 mpt_HardResetHandler(ioc, CAN_SLEEP);
2220 ret = -ETIMEDOUT;
2221 goto unmap;
2222 }
2223 mf = NULL;
2224
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302225 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002226 SmpPassthroughReply_t *smprep;
2227
2228 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2229 memcpy(req->sense, smprep, sizeof(*smprep));
2230 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002231 req->resid_len = 0;
2232 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002233 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302234 printk(MYIOC_s_ERR_FMT
2235 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002236 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002237 ret = -ENXIO;
2238 }
2239unmap:
2240 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002241 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002242 PCI_DMA_BIDIRECTIONAL);
2243 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002244 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002245 PCI_DMA_BIDIRECTIONAL);
2246put_mf:
2247 if (mf)
2248 mpt_free_msg_frame(ioc, mf);
2249out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302250 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002251 mutex_unlock(&ioc->sas_mgmt.mutex);
2252out:
2253 return ret;
2254}
2255
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002256static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002257 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002258 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2259 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002260 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002261 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002262};
2263
2264static struct scsi_transport_template *mptsas_transport_template;
2265
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002266static int
2267mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2268{
2269 ConfigExtendedPageHeader_t hdr;
2270 CONFIGPARMS cfg;
2271 SasIOUnitPage0_t *buffer;
2272 dma_addr_t dma_handle;
2273 int error, i;
2274
2275 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2276 hdr.ExtPageLength = 0;
2277 hdr.PageNumber = 0;
2278 hdr.Reserved1 = 0;
2279 hdr.Reserved2 = 0;
2280 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2281 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2282
2283 cfg.cfghdr.ehdr = &hdr;
2284 cfg.physAddr = -1;
2285 cfg.pageAddr = 0;
2286 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2287 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302288 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002289
2290 error = mpt_config(ioc, &cfg);
2291 if (error)
2292 goto out;
2293 if (!hdr.ExtPageLength) {
2294 error = -ENXIO;
2295 goto out;
2296 }
2297
2298 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2299 &dma_handle);
2300 if (!buffer) {
2301 error = -ENOMEM;
2302 goto out;
2303 }
2304
2305 cfg.physAddr = dma_handle;
2306 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2307
2308 error = mpt_config(ioc, &cfg);
2309 if (error)
2310 goto out_free_consistent;
2311
2312 port_info->num_phys = buffer->NumPhys;
2313 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302314 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002315 if (!port_info->phy_info) {
2316 error = -ENOMEM;
2317 goto out_free_consistent;
2318 }
2319
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302320 ioc->nvdata_version_persistent =
2321 le16_to_cpu(buffer->NvdataVersionPersistent);
2322 ioc->nvdata_version_default =
2323 le16_to_cpu(buffer->NvdataVersionDefault);
2324
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002325 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302326 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002327 port_info->phy_info[i].phy_id = i;
2328 port_info->phy_info[i].port_id =
2329 buffer->PhyData[i].Port;
2330 port_info->phy_info[i].negotiated_link_rate =
2331 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002332 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002333 port_info->phy_info[i].handle =
2334 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002335 }
2336
2337 out_free_consistent:
2338 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2339 buffer, dma_handle);
2340 out:
2341 return error;
2342}
2343
2344static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302345mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2346{
2347 ConfigExtendedPageHeader_t hdr;
2348 CONFIGPARMS cfg;
2349 SasIOUnitPage1_t *buffer;
2350 dma_addr_t dma_handle;
2351 int error;
2352 u16 device_missing_delay;
2353
2354 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2355 memset(&cfg, 0, sizeof(CONFIGPARMS));
2356
2357 cfg.cfghdr.ehdr = &hdr;
2358 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302359 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302360 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2361 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2362 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2363 cfg.cfghdr.ehdr->PageNumber = 1;
2364
2365 error = mpt_config(ioc, &cfg);
2366 if (error)
2367 goto out;
2368 if (!hdr.ExtPageLength) {
2369 error = -ENXIO;
2370 goto out;
2371 }
2372
2373 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2374 &dma_handle);
2375 if (!buffer) {
2376 error = -ENOMEM;
2377 goto out;
2378 }
2379
2380 cfg.physAddr = dma_handle;
2381 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2382
2383 error = mpt_config(ioc, &cfg);
2384 if (error)
2385 goto out_free_consistent;
2386
2387 ioc->io_missing_delay =
2388 le16_to_cpu(buffer->IODeviceMissingDelay);
2389 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2390 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2391 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2392 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2393
2394 out_free_consistent:
2395 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2396 buffer, dma_handle);
2397 out:
2398 return error;
2399}
2400
2401static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002402mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2403 u32 form, u32 form_specific)
2404{
2405 ConfigExtendedPageHeader_t hdr;
2406 CONFIGPARMS cfg;
2407 SasPhyPage0_t *buffer;
2408 dma_addr_t dma_handle;
2409 int error;
2410
2411 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2412 hdr.ExtPageLength = 0;
2413 hdr.PageNumber = 0;
2414 hdr.Reserved1 = 0;
2415 hdr.Reserved2 = 0;
2416 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2417 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2418
2419 cfg.cfghdr.ehdr = &hdr;
2420 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302421 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002422
2423 /* Get Phy Pg 0 for each Phy. */
2424 cfg.physAddr = -1;
2425 cfg.pageAddr = form + form_specific;
2426 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2427
2428 error = mpt_config(ioc, &cfg);
2429 if (error)
2430 goto out;
2431
2432 if (!hdr.ExtPageLength) {
2433 error = -ENXIO;
2434 goto out;
2435 }
2436
2437 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2438 &dma_handle);
2439 if (!buffer) {
2440 error = -ENOMEM;
2441 goto out;
2442 }
2443
2444 cfg.physAddr = dma_handle;
2445 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2446
2447 error = mpt_config(ioc, &cfg);
2448 if (error)
2449 goto out_free_consistent;
2450
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302451 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002452
2453 phy_info->hw_link_rate = buffer->HwLinkRate;
2454 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2455 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2456 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2457
2458 out_free_consistent:
2459 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2460 buffer, dma_handle);
2461 out:
2462 return error;
2463}
2464
2465static int
2466mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2467 u32 form, u32 form_specific)
2468{
2469 ConfigExtendedPageHeader_t hdr;
2470 CONFIGPARMS cfg;
2471 SasDevicePage0_t *buffer;
2472 dma_addr_t dma_handle;
2473 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002474 int error=0;
2475
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002476 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2477 hdr.ExtPageLength = 0;
2478 hdr.PageNumber = 0;
2479 hdr.Reserved1 = 0;
2480 hdr.Reserved2 = 0;
2481 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2482 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2483
2484 cfg.cfghdr.ehdr = &hdr;
2485 cfg.pageAddr = form + form_specific;
2486 cfg.physAddr = -1;
2487 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2488 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302489 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002490
Moore, Ericdb9c9172006-03-14 09:14:18 -07002491 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002492 error = mpt_config(ioc, &cfg);
2493 if (error)
2494 goto out;
2495 if (!hdr.ExtPageLength) {
2496 error = -ENXIO;
2497 goto out;
2498 }
2499
2500 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2501 &dma_handle);
2502 if (!buffer) {
2503 error = -ENOMEM;
2504 goto out;
2505 }
2506
2507 cfg.physAddr = dma_handle;
2508 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2509
2510 error = mpt_config(ioc, &cfg);
2511 if (error)
2512 goto out_free_consistent;
2513
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302514 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002515
Kashyap, Desai2f187862009-05-29 16:52:37 +05302516 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002517 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -07002518 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002519 device_info->handle_enclosure =
2520 le16_to_cpu(buffer->EnclosureHandle);
2521 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002522 device_info->phy_id = buffer->PhyNum;
2523 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002524 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002525 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002526 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002527 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2528 device_info->sas_address = le64_to_cpu(sas_address);
2529 device_info->device_info =
2530 le32_to_cpu(buffer->DeviceInfo);
2531
2532 out_free_consistent:
2533 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2534 buffer, dma_handle);
2535 out:
2536 return error;
2537}
2538
2539static int
2540mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2541 u32 form, u32 form_specific)
2542{
2543 ConfigExtendedPageHeader_t hdr;
2544 CONFIGPARMS cfg;
2545 SasExpanderPage0_t *buffer;
2546 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002547 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302548 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002549
Kashyap, Desai2f187862009-05-29 16:52:37 +05302550 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002551 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2552 hdr.ExtPageLength = 0;
2553 hdr.PageNumber = 0;
2554 hdr.Reserved1 = 0;
2555 hdr.Reserved2 = 0;
2556 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2557 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2558
2559 cfg.cfghdr.ehdr = &hdr;
2560 cfg.physAddr = -1;
2561 cfg.pageAddr = form + form_specific;
2562 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2563 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302564 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002565
Moore, Ericdb9c9172006-03-14 09:14:18 -07002566 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002567 error = mpt_config(ioc, &cfg);
2568 if (error)
2569 goto out;
2570
2571 if (!hdr.ExtPageLength) {
2572 error = -ENXIO;
2573 goto out;
2574 }
2575
2576 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2577 &dma_handle);
2578 if (!buffer) {
2579 error = -ENOMEM;
2580 goto out;
2581 }
2582
2583 cfg.physAddr = dma_handle;
2584 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2585
2586 error = mpt_config(ioc, &cfg);
2587 if (error)
2588 goto out_free_consistent;
2589
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002590 if (!buffer->NumPhys) {
2591 error = -ENODEV;
2592 goto out_free_consistent;
2593 }
2594
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002595 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302596 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002597 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302598 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002599 if (!port_info->phy_info) {
2600 error = -ENOMEM;
2601 goto out_free_consistent;
2602 }
2603
Kashyap, Desai2f187862009-05-29 16:52:37 +05302604 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002605 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002606 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002607 port_info->phy_info[i].handle =
2608 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302609 port_info->phy_info[i].identify.sas_address =
2610 le64_to_cpu(sas_address);
2611 port_info->phy_info[i].identify.handle_parent =
2612 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002613 }
Eric Moore547f9a22006-06-27 14:42:12 -06002614
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002615 out_free_consistent:
2616 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2617 buffer, dma_handle);
2618 out:
2619 return error;
2620}
2621
2622static int
2623mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2624 u32 form, u32 form_specific)
2625{
2626 ConfigExtendedPageHeader_t hdr;
2627 CONFIGPARMS cfg;
2628 SasExpanderPage1_t *buffer;
2629 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002630 int error=0;
2631
Kashyap, Desai2f187862009-05-29 16:52:37 +05302632 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002633 hdr.ExtPageLength = 0;
2634 hdr.PageNumber = 1;
2635 hdr.Reserved1 = 0;
2636 hdr.Reserved2 = 0;
2637 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2638 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2639
2640 cfg.cfghdr.ehdr = &hdr;
2641 cfg.physAddr = -1;
2642 cfg.pageAddr = form + form_specific;
2643 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2644 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302645 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002646
2647 error = mpt_config(ioc, &cfg);
2648 if (error)
2649 goto out;
2650
2651 if (!hdr.ExtPageLength) {
2652 error = -ENXIO;
2653 goto out;
2654 }
2655
2656 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2657 &dma_handle);
2658 if (!buffer) {
2659 error = -ENOMEM;
2660 goto out;
2661 }
2662
2663 cfg.physAddr = dma_handle;
2664 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2665
2666 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302667
2668 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2669 error = -ENODEV;
2670 goto out;
2671 }
2672
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002673 if (error)
2674 goto out_free_consistent;
2675
2676
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302677 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002678
2679 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002680 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002681 phy_info->port_id = buffer->PhysicalPort;
2682 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2683 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2684 phy_info->hw_link_rate = buffer->HwLinkRate;
2685 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2686 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2687
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002688 out_free_consistent:
2689 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2690 buffer, dma_handle);
2691 out:
2692 return error;
2693}
2694
2695static void
2696mptsas_parse_device_info(struct sas_identify *identify,
2697 struct mptsas_devinfo *device_info)
2698{
2699 u16 protocols;
2700
2701 identify->sas_address = device_info->sas_address;
2702 identify->phy_identifier = device_info->phy_id;
2703
2704 /*
2705 * Fill in Phy Initiator Port Protocol.
2706 * Bits 6:3, more than one bit can be set, fall through cases.
2707 */
2708 protocols = device_info->device_info & 0x78;
2709 identify->initiator_port_protocols = 0;
2710 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2711 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2712 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2713 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2714 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2715 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2716 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2717 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2718
2719 /*
2720 * Fill in Phy Target Port Protocol.
2721 * Bits 10:7, more than one bit can be set, fall through cases.
2722 */
2723 protocols = device_info->device_info & 0x780;
2724 identify->target_port_protocols = 0;
2725 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2726 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2727 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2728 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2729 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2730 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2731 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2732 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2733
2734 /*
2735 * Fill in Attached device type.
2736 */
2737 switch (device_info->device_info &
2738 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2739 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2740 identify->device_type = SAS_PHY_UNUSED;
2741 break;
2742 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2743 identify->device_type = SAS_END_DEVICE;
2744 break;
2745 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2746 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2747 break;
2748 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2749 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2750 break;
2751 }
2752}
2753
2754static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002755 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002756{
Moore, Erice6b2d762006-03-14 09:14:24 -07002757 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002758 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002759 struct sas_port *port;
2760 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002761
Eric Moore547f9a22006-06-27 14:42:12 -06002762 if (!dev) {
2763 error = -ENODEV;
2764 goto out;
2765 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002766
2767 if (!phy_info->phy) {
2768 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002769 if (!phy) {
2770 error = -ENOMEM;
2771 goto out;
2772 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002773 } else
2774 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002775
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002776 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002777
2778 /*
2779 * Set Negotiated link rate.
2780 */
2781 switch (phy_info->negotiated_link_rate) {
2782 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002783 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002784 break;
2785 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002786 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002787 break;
2788 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002789 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002790 break;
2791 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002792 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002793 break;
2794 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2795 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2796 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002797 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002798 break;
2799 }
2800
2801 /*
2802 * Set Max hardware link rate.
2803 */
2804 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2805 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002806 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002807 break;
2808 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002809 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002810 break;
2811 default:
2812 break;
2813 }
2814
2815 /*
2816 * Set Max programmed link rate.
2817 */
2818 switch (phy_info->programmed_link_rate &
2819 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2820 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002821 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002822 break;
2823 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002824 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002825 break;
2826 default:
2827 break;
2828 }
2829
2830 /*
2831 * Set Min hardware link rate.
2832 */
2833 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2834 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002835 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002836 break;
2837 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002838 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002839 break;
2840 default:
2841 break;
2842 }
2843
2844 /*
2845 * Set Min programmed link rate.
2846 */
2847 switch (phy_info->programmed_link_rate &
2848 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2849 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002850 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002851 break;
2852 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002853 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002854 break;
2855 default:
2856 break;
2857 }
2858
Moore, Erice6b2d762006-03-14 09:14:24 -07002859 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002860
Moore, Erice6b2d762006-03-14 09:14:24 -07002861 error = sas_phy_add(phy);
2862 if (error) {
2863 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002864 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002865 }
2866 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002867 }
2868
Eric Moore547f9a22006-06-27 14:42:12 -06002869 if (!phy_info->attached.handle ||
2870 !phy_info->port_details)
2871 goto out;
2872
2873 port = mptsas_get_port(phy_info);
2874 ioc = phy_to_ioc(phy_info->phy);
2875
2876 if (phy_info->sas_port_add_phy) {
2877
2878 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002879 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002880 if (!port) {
2881 error = -ENOMEM;
2882 goto out;
2883 }
2884 error = sas_port_add(port);
2885 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302886 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002887 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002888 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002889 goto out;
2890 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302891 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302892 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
2893 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
2894 ioc->name, port->port_identifier,
2895 (unsigned long long)phy_info->
2896 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06002897 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302898 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2899 "sas_port_add_phy: phy_id=%d\n",
2900 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002901 sas_port_add_phy(port, phy_info->phy);
2902 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302903 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
2904 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
2905 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06002906 }
Eric Moore547f9a22006-06-27 14:42:12 -06002907 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002908
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002909 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002910 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002911 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002912
James Bottomley2686de22006-06-30 12:54:02 -05002913 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002914 /*
2915 * Let the hotplug_work thread handle processing
2916 * the adding/removing of devices that occur
2917 * after start of day.
2918 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302919 if (mptsas_is_end_device(&phy_info->attached) &&
2920 phy_info->attached.handle_parent) {
2921 goto out;
2922 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002923
James Bottomleyf013db32006-03-18 14:54:36 -06002924 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002925 if (scsi_is_host_device(parent)) {
2926 struct mptsas_portinfo *port_info;
2927 int i;
2928
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302929 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002930
2931 for (i = 0; i < port_info->num_phys; i++)
2932 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002933 identify.sas_address) {
2934 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002935 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002936 }
James Bottomley2686de22006-06-30 12:54:02 -05002937
2938 } else if (scsi_is_sas_rphy(parent)) {
2939 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2940 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002941 parent_rphy->identify.sas_address) {
2942 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002943 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002944 }
James Bottomley2686de22006-06-30 12:54:02 -05002945 }
2946
James Bottomleyf013db32006-03-18 14:54:36 -06002947 switch (identify.device_type) {
2948 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002949 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002950 break;
2951 case SAS_EDGE_EXPANDER_DEVICE:
2952 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002953 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002954 break;
2955 default:
2956 rphy = NULL;
2957 break;
2958 }
Eric Moore547f9a22006-06-27 14:42:12 -06002959 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302960 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002961 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002962 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002963 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002964 }
2965
Eric Moore547f9a22006-06-27 14:42:12 -06002966 rphy->identify = identify;
2967 error = sas_rphy_add(rphy);
2968 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302969 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002970 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002971 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002972 sas_rphy_free(rphy);
2973 goto out;
2974 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302975 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002976 }
2977
Eric Moore547f9a22006-06-27 14:42:12 -06002978 out:
2979 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002980}
2981
2982static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002983mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002984{
Moore, Erice6b2d762006-03-14 09:14:24 -07002985 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002986 int error = -ENOMEM, i;
2987
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302988 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002989 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002990 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002991
Moore, Erice6b2d762006-03-14 09:14:24 -07002992 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002993 if (error)
2994 goto out_free_port_info;
2995
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302996 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002997 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302998 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002999 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303000 ioc->hba_port_info = port_info = hba;
3001 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003002 list_add_tail(&port_info->list, &ioc->sas_topology);
3003 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003004 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003005 port_info->phy_info[i].negotiated_link_rate =
3006 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003007 port_info->phy_info[i].handle =
3008 hba->phy_info[i].handle;
3009 port_info->phy_info[i].port_id =
3010 hba->phy_info[i].port_id;
3011 }
Eric Moore547f9a22006-06-27 14:42:12 -06003012 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003013 kfree(hba);
3014 hba = NULL;
3015 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003016 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303017#if defined(CPQ_CIM)
3018 ioc->num_ports = port_info->num_phys;
3019#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003020 for (i = 0; i < port_info->num_phys; i++) {
3021 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3022 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3023 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303024 port_info->phy_info[i].identify.handle =
3025 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003026 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003027 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3028 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303029 port_info->phy_info[i].identify.handle);
3030 if (!ioc->hba_port_sas_addr)
3031 ioc->hba_port_sas_addr =
3032 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003033 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003034 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003035 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003036 mptsas_sas_device_pg0(ioc,
3037 &port_info->phy_info[i].attached,
3038 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3039 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3040 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003041 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003042
Eric Moore547f9a22006-06-27 14:42:12 -06003043 mptsas_setup_wide_ports(ioc, port_info);
3044
3045 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003046 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003047 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003048
3049 return 0;
3050
3051 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003052 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003053 out:
3054 return error;
3055}
3056
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303057static void
3058mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003059{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303060 struct mptsas_portinfo *parent;
3061 struct device *parent_dev;
3062 struct sas_rphy *rphy;
3063 int i;
3064 u64 sas_address; /* expander sas address */
3065 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003066
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303067 handle = port_info->phy_info[0].handle;
3068 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003069 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003070 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303071 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3072 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003073
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303074 mptsas_sas_device_pg0(ioc,
3075 &port_info->phy_info[i].identify,
3076 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3077 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3078 port_info->phy_info[i].identify.handle);
3079 port_info->phy_info[i].identify.phy_id =
3080 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003081
3082 if (port_info->phy_info[i].attached.handle) {
3083 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303084 &port_info->phy_info[i].attached,
3085 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3086 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3087 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003088 port_info->phy_info[i].attached.phy_id =
3089 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003090 }
Eric Moore547f9a22006-06-27 14:42:12 -06003091 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003092
Moore, Erice6b2d762006-03-14 09:14:24 -07003093 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303094 parent = mptsas_find_portinfo_by_handle(ioc,
3095 port_info->phy_info[0].identify.handle_parent);
3096 if (!parent) {
3097 mutex_unlock(&ioc->sas_topology_mutex);
3098 return;
3099 }
3100 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3101 i++) {
3102 if (parent->phy_info[i].attached.sas_address == sas_address) {
3103 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3104 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003105 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003106 }
3107 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303108
3109 mptsas_setup_wide_ports(ioc, port_info);
3110 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3111 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3112 ioc->sas_index, 0);
3113}
3114
3115static void
3116mptsas_expander_event_add(MPT_ADAPTER *ioc,
3117 MpiEventDataSasExpanderStatusChange_t *expander_data)
3118{
3119 struct mptsas_portinfo *port_info;
3120 int i;
3121 __le64 sas_address;
3122
3123 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3124 if (!port_info)
3125 BUG();
3126 port_info->num_phys = (expander_data->NumPhys) ?
3127 expander_data->NumPhys : 1;
3128 port_info->phy_info = kcalloc(port_info->num_phys,
3129 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3130 if (!port_info->phy_info)
3131 BUG();
3132 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3133 for (i = 0; i < port_info->num_phys; i++) {
3134 port_info->phy_info[i].portinfo = port_info;
3135 port_info->phy_info[i].handle =
3136 le16_to_cpu(expander_data->DevHandle);
3137 port_info->phy_info[i].identify.sas_address =
3138 le64_to_cpu(sas_address);
3139 port_info->phy_info[i].identify.handle_parent =
3140 le16_to_cpu(expander_data->ParentDevHandle);
3141 }
3142
3143 mutex_lock(&ioc->sas_topology_mutex);
3144 list_add_tail(&port_info->list, &ioc->sas_topology);
3145 mutex_unlock(&ioc->sas_topology_mutex);
3146
3147 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3148 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3149 (unsigned long long)sas_address);
3150
3151 mptsas_expander_refresh(ioc, port_info);
3152}
3153
3154/**
3155 * mptsas_delete_expander_siblings - remove siblings attached to expander
3156 * @ioc: Pointer to MPT_ADAPTER structure
3157 * @parent: the parent port_info object
3158 * @expander: the expander port_info object
3159 **/
3160static void
3161mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3162 *parent, struct mptsas_portinfo *expander)
3163{
3164 struct mptsas_phyinfo *phy_info;
3165 struct mptsas_portinfo *port_info;
3166 struct sas_rphy *rphy;
3167 int i;
3168
3169 phy_info = expander->phy_info;
3170 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3171 rphy = mptsas_get_rphy(phy_info);
3172 if (!rphy)
3173 continue;
3174 if (rphy->identify.device_type == SAS_END_DEVICE)
3175 mptsas_del_end_device(ioc, phy_info);
3176 }
3177
3178 phy_info = expander->phy_info;
3179 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3180 rphy = mptsas_get_rphy(phy_info);
3181 if (!rphy)
3182 continue;
3183 if (rphy->identify.device_type ==
3184 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3185 rphy->identify.device_type ==
3186 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3187 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3188 rphy->identify.sas_address);
3189 if (!port_info)
3190 continue;
3191 if (port_info == parent) /* backlink rphy */
3192 continue;
3193 /*
3194 Delete this expander even if the expdevpage is exists
3195 because the parent expander is already deleted
3196 */
3197 mptsas_expander_delete(ioc, port_info, 1);
3198 }
3199 }
3200}
3201
3202
3203/**
3204 * mptsas_expander_delete - remove this expander
3205 * @ioc: Pointer to MPT_ADAPTER structure
3206 * @port_info: expander port_info struct
3207 * @force: Flag to forcefully delete the expander
3208 *
3209 **/
3210
3211static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3212 struct mptsas_portinfo *port_info, u8 force)
3213{
3214
3215 struct mptsas_portinfo *parent;
3216 int i;
3217 u64 expander_sas_address;
3218 struct mptsas_phyinfo *phy_info;
3219 struct mptsas_portinfo buffer;
3220 struct mptsas_portinfo_details *port_details;
3221 struct sas_port *port;
3222
3223 if (!port_info)
3224 return;
3225
3226 /* see if expander is still there before deleting */
3227 mptsas_sas_expander_pg0(ioc, &buffer,
3228 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3229 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3230 port_info->phy_info[0].identify.handle);
3231
3232 if (buffer.num_phys) {
3233 kfree(buffer.phy_info);
3234 if (!force)
3235 return;
3236 }
3237
3238
3239 /*
3240 * Obtain the port_info instance to the parent port
3241 */
3242 port_details = NULL;
3243 expander_sas_address =
3244 port_info->phy_info[0].identify.sas_address;
3245 parent = mptsas_find_portinfo_by_handle(ioc,
3246 port_info->phy_info[0].identify.handle_parent);
3247 mptsas_delete_expander_siblings(ioc, parent, port_info);
3248 if (!parent)
3249 goto out;
3250
3251 /*
3252 * Delete rphys in the parent that point
3253 * to this expander.
3254 */
3255 phy_info = parent->phy_info;
3256 port = NULL;
3257 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3258 if (!phy_info->phy)
3259 continue;
3260 if (phy_info->attached.sas_address !=
3261 expander_sas_address)
3262 continue;
3263 if (!port) {
3264 port = mptsas_get_port(phy_info);
3265 port_details = phy_info->port_details;
3266 }
3267 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3268 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3269 phy_info->phy_id, phy_info->phy);
3270 sas_port_delete_phy(port, phy_info->phy);
3271 }
3272 if (port) {
3273 dev_printk(KERN_DEBUG, &port->dev,
3274 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3275 ioc->name, port->port_identifier,
3276 (unsigned long long)expander_sas_address);
3277 sas_port_delete(port);
3278 mptsas_port_delete(ioc, port_details);
3279 }
3280 out:
3281
3282 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3283 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3284 (unsigned long long)expander_sas_address);
3285
3286 /*
3287 * free link
3288 */
3289 list_del(&port_info->list);
3290 kfree(port_info->phy_info);
3291 kfree(port_info);
3292}
3293
3294
3295/**
3296 * mptsas_send_expander_event - expanders events
3297 * @ioc: Pointer to MPT_ADAPTER structure
3298 * @expander_data: event data
3299 *
3300 *
3301 * This function handles adding, removing, and refreshing
3302 * device handles within the expander objects.
3303 */
3304static void
3305mptsas_send_expander_event(struct fw_event_work *fw_event)
3306{
3307 MPT_ADAPTER *ioc;
3308 MpiEventDataSasExpanderStatusChange_t *expander_data;
3309 struct mptsas_portinfo *port_info;
3310 __le64 sas_address;
3311 int i;
3312
3313 ioc = fw_event->ioc;
3314 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3315 fw_event->event_data;
3316 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3317 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3318
3319 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3320 if (port_info) {
3321 for (i = 0; i < port_info->num_phys; i++) {
3322 port_info->phy_info[i].portinfo = port_info;
3323 port_info->phy_info[i].handle =
3324 le16_to_cpu(expander_data->DevHandle);
3325 port_info->phy_info[i].identify.sas_address =
3326 le64_to_cpu(sas_address);
3327 port_info->phy_info[i].identify.handle_parent =
3328 le16_to_cpu(expander_data->ParentDevHandle);
3329 }
3330 mptsas_expander_refresh(ioc, port_info);
3331 } else if (!port_info && expander_data->NumPhys)
3332 mptsas_expander_event_add(ioc, expander_data);
3333 } else if (expander_data->ReasonCode ==
3334 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3335 mptsas_expander_delete(ioc, port_info, 0);
3336
3337 mptsas_free_fw_event(ioc, fw_event);
3338}
3339
3340
3341/**
3342 * mptsas_expander_add -
3343 * @ioc: Pointer to MPT_ADAPTER structure
3344 * @handle:
3345 *
3346 */
3347struct mptsas_portinfo *
3348mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3349{
3350 struct mptsas_portinfo buffer, *port_info;
3351 int i;
3352
3353 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3354 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3355 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3356 return NULL;
3357
3358 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3359 if (!port_info) {
3360 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3361 "%s: exit at line=%d\n", ioc->name,
3362 __func__, __LINE__));
3363 return NULL;
3364 }
3365 port_info->num_phys = buffer.num_phys;
3366 port_info->phy_info = buffer.phy_info;
3367 for (i = 0; i < port_info->num_phys; i++)
3368 port_info->phy_info[i].portinfo = port_info;
3369 mutex_lock(&ioc->sas_topology_mutex);
3370 list_add_tail(&port_info->list, &ioc->sas_topology);
3371 mutex_unlock(&ioc->sas_topology_mutex);
3372 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3373 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3374 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3375 mptsas_expander_refresh(ioc, port_info);
3376 return port_info;
3377}
3378
3379static void
3380mptsas_send_link_status_event(struct fw_event_work *fw_event)
3381{
3382 MPT_ADAPTER *ioc;
3383 MpiEventDataSasPhyLinkStatus_t *link_data;
3384 struct mptsas_portinfo *port_info;
3385 struct mptsas_phyinfo *phy_info = NULL;
3386 __le64 sas_address;
3387 u8 phy_num;
3388 u8 link_rate;
3389
3390 ioc = fw_event->ioc;
3391 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3392
3393 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3394 sas_address = le64_to_cpu(sas_address);
3395 link_rate = link_data->LinkRates >> 4;
3396 phy_num = link_data->PhyNum;
3397
3398 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3399 if (port_info) {
3400 phy_info = &port_info->phy_info[phy_num];
3401 if (phy_info)
3402 phy_info->negotiated_link_rate = link_rate;
3403 }
3404
3405 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3406 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3407
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303408 if (!port_info) {
3409 if (ioc->old_sas_discovery_protocal) {
3410 port_info = mptsas_expander_add(ioc,
3411 le16_to_cpu(link_data->DevHandle));
3412 if (port_info)
3413 goto out;
3414 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303415 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303416 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303417
3418 if (port_info == ioc->hba_port_info)
3419 mptsas_probe_hba_phys(ioc);
3420 else
3421 mptsas_expander_refresh(ioc, port_info);
3422 } else if (phy_info && phy_info->phy) {
3423 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3424 phy_info->phy->negotiated_linkrate =
3425 SAS_PHY_DISABLED;
3426 else if (link_rate ==
3427 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3428 phy_info->phy->negotiated_linkrate =
3429 SAS_LINK_RATE_FAILED;
3430 else
3431 phy_info->phy->negotiated_linkrate =
3432 SAS_LINK_RATE_UNKNOWN;
3433 }
3434 out:
3435 mptsas_free_fw_event(ioc, fw_event);
3436}
3437
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303438static void
3439mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3440{
3441 struct mptsas_portinfo buffer, *port_info;
3442 struct mptsas_device_info *sas_info;
3443 struct mptsas_devinfo sas_device;
3444 u32 handle;
3445 VirtTarget *vtarget = NULL;
3446 struct mptsas_phyinfo *phy_info;
3447 u8 found_expander;
3448 int retval, retry_count;
3449 unsigned long flags;
3450
3451 mpt_findImVolumes(ioc);
3452
3453 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3454 if (ioc->ioc_reset_in_progress) {
3455 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3456 "%s: exiting due to a parallel reset \n", ioc->name,
3457 __func__));
3458 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3459 return;
3460 }
3461 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3462
3463 /* devices, logical volumes */
3464 mutex_lock(&ioc->sas_device_info_mutex);
3465 redo_device_scan:
3466 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303467 if (sas_info->is_cached)
3468 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303469 if (!sas_info->is_logical_volume) {
3470 sas_device.handle = 0;
3471 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303472retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303473 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303474 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3475 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3476 (sas_info->fw.channel << 8) +
3477 sas_info->fw.id);
3478
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303479 if (sas_device.handle)
3480 continue;
3481 if (retval == -EBUSY) {
3482 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3483 if (ioc->ioc_reset_in_progress) {
3484 dfailprintk(ioc,
3485 printk(MYIOC_s_DEBUG_FMT
3486 "%s: exiting due to reset\n",
3487 ioc->name, __func__));
3488 spin_unlock_irqrestore
3489 (&ioc->taskmgmt_lock, flags);
3490 mutex_unlock(&ioc->
3491 sas_device_info_mutex);
3492 return;
3493 }
3494 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3495 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303496 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303497
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303498 if (retval && (retval != -ENODEV)) {
3499 if (retry_count < 10) {
3500 retry_count++;
3501 goto retry_page;
3502 } else {
3503 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3504 "%s: Config page retry exceeded retry "
3505 "count deleting device 0x%llx\n",
3506 ioc->name, __func__,
3507 sas_info->sas_address));
3508 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303509 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303510
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303511 /* delete device */
3512 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303513 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303514
3515 if (vtarget)
3516 vtarget->deleted = 1;
3517
3518 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3519 sas_info->sas_address);
3520
3521 if (phy_info) {
3522 mptsas_del_end_device(ioc, phy_info);
3523 goto redo_device_scan;
3524 }
3525 } else
3526 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303527 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003528 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303529
3530 /* expanders */
3531 mutex_lock(&ioc->sas_topology_mutex);
3532 redo_expander_scan:
3533 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3534
3535 if (port_info->phy_info &&
3536 (!(port_info->phy_info[0].identify.device_info &
3537 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3538 continue;
3539 found_expander = 0;
3540 handle = 0xFFFF;
3541 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3542 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3543 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3544 !found_expander) {
3545
3546 handle = buffer.phy_info[0].handle;
3547 if (buffer.phy_info[0].identify.sas_address ==
3548 port_info->phy_info[0].identify.sas_address) {
3549 found_expander = 1;
3550 }
3551 kfree(buffer.phy_info);
3552 }
3553
3554 if (!found_expander) {
3555 mptsas_expander_delete(ioc, port_info, 0);
3556 goto redo_expander_scan;
3557 }
3558 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003559 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303560}
3561
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303562/**
3563 * mptsas_probe_expanders - adding expanders
3564 * @ioc: Pointer to MPT_ADAPTER structure
3565 *
3566 **/
3567static void
3568mptsas_probe_expanders(MPT_ADAPTER *ioc)
3569{
3570 struct mptsas_portinfo buffer, *port_info;
3571 u32 handle;
3572 int i;
3573
3574 handle = 0xFFFF;
3575 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3576 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3577 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3578
3579 handle = buffer.phy_info[0].handle;
3580 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3581 buffer.phy_info[0].identify.sas_address);
3582
3583 if (port_info) {
3584 /* refreshing handles */
3585 for (i = 0; i < buffer.num_phys; i++) {
3586 port_info->phy_info[i].handle = handle;
3587 port_info->phy_info[i].identify.handle_parent =
3588 buffer.phy_info[0].identify.handle_parent;
3589 }
3590 mptsas_expander_refresh(ioc, port_info);
3591 kfree(buffer.phy_info);
3592 continue;
3593 }
3594
3595 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3596 if (!port_info) {
3597 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3598 "%s: exit at line=%d\n", ioc->name,
3599 __func__, __LINE__));
3600 return;
3601 }
3602 port_info->num_phys = buffer.num_phys;
3603 port_info->phy_info = buffer.phy_info;
3604 for (i = 0; i < port_info->num_phys; i++)
3605 port_info->phy_info[i].portinfo = port_info;
3606 mutex_lock(&ioc->sas_topology_mutex);
3607 list_add_tail(&port_info->list, &ioc->sas_topology);
3608 mutex_unlock(&ioc->sas_topology_mutex);
3609 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3610 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3611 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3612 mptsas_expander_refresh(ioc, port_info);
3613 }
3614}
3615
3616static void
3617mptsas_probe_devices(MPT_ADAPTER *ioc)
3618{
3619 u16 handle;
3620 struct mptsas_devinfo sas_device;
3621 struct mptsas_phyinfo *phy_info;
3622
3623 handle = 0xFFFF;
3624 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3625 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3626
3627 handle = sas_device.handle;
3628
3629 if ((sas_device.device_info &
3630 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3631 MPI_SAS_DEVICE_INFO_STP_TARGET |
3632 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3633 continue;
3634
3635 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3636 if (!phy_info)
3637 continue;
3638
3639 if (mptsas_get_rphy(phy_info))
3640 continue;
3641
3642 mptsas_add_end_device(ioc, phy_info);
3643 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003644}
3645
Kashyap, Desai2f187862009-05-29 16:52:37 +05303646/**
3647 * mptsas_scan_sas_topology -
3648 * @ioc: Pointer to MPT_ADAPTER structure
3649 * @sas_address:
3650 *
3651 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003652static void
3653mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3654{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303655 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003656 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003657
Moore, Erice6b2d762006-03-14 09:14:24 -07003658 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303659 mptsas_probe_expanders(ioc);
3660 mptsas_probe_devices(ioc);
3661
Moore, Ericf44e5462006-03-14 09:14:21 -07003662 /*
3663 Reporting RAID volumes.
3664 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303665 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3666 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3667 return;
Eric Moore793955f2007-01-29 09:42:20 -07003668 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303669 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3670 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3671 if (sdev) {
3672 scsi_device_put(sdev);
3673 continue;
3674 }
3675 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3676 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3677 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003678 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003679 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3680 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003681}
3682
Kashyap, Desai57e98512009-05-29 16:55:09 +05303683
3684static void
3685mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3686{
3687 MPT_ADAPTER *ioc;
3688 EventDataQueueFull_t *qfull_data;
3689 struct mptsas_device_info *sas_info;
3690 struct scsi_device *sdev;
3691 int depth;
3692 int id = -1;
3693 int channel = -1;
3694 int fw_id, fw_channel;
3695 u16 current_depth;
3696
3697
3698 ioc = fw_event->ioc;
3699 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3700 fw_id = qfull_data->TargetID;
3701 fw_channel = qfull_data->Bus;
3702 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3703
3704 /* if hidden raid component, look for the volume id */
3705 mutex_lock(&ioc->sas_device_info_mutex);
3706 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3707 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3708 list) {
3709 if (sas_info->is_cached ||
3710 sas_info->is_logical_volume)
3711 continue;
3712 if (sas_info->is_hidden_raid_component &&
3713 (sas_info->fw.channel == fw_channel &&
3714 sas_info->fw.id == fw_id)) {
3715 id = sas_info->volume_id;
3716 channel = MPTSAS_RAID_CHANNEL;
3717 goto out;
3718 }
3719 }
3720 } else {
3721 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3722 list) {
3723 if (sas_info->is_cached ||
3724 sas_info->is_hidden_raid_component ||
3725 sas_info->is_logical_volume)
3726 continue;
3727 if (sas_info->fw.channel == fw_channel &&
3728 sas_info->fw.id == fw_id) {
3729 id = sas_info->os.id;
3730 channel = sas_info->os.channel;
3731 goto out;
3732 }
3733 }
3734
3735 }
3736
3737 out:
3738 mutex_unlock(&ioc->sas_device_info_mutex);
3739
3740 if (id != -1) {
3741 shost_for_each_device(sdev, ioc->sh) {
3742 if (sdev->id == id && sdev->channel == channel) {
3743 if (current_depth > sdev->queue_depth) {
3744 sdev_printk(KERN_INFO, sdev,
3745 "strange observation, the queue "
3746 "depth is (%d) meanwhile fw queue "
3747 "depth (%d)\n", sdev->queue_depth,
3748 current_depth);
3749 continue;
3750 }
3751 depth = scsi_track_queue_full(sdev,
3752 current_depth - 1);
3753 if (depth > 0)
3754 sdev_printk(KERN_INFO, sdev,
3755 "Queue depth reduced to (%d)\n",
3756 depth);
3757 else if (depth < 0)
3758 sdev_printk(KERN_INFO, sdev,
3759 "Tagged Command Queueing is being "
3760 "disabled\n");
3761 else if (depth == 0)
3762 sdev_printk(KERN_INFO, sdev,
3763 "Queue depth not changed yet\n");
3764 }
3765 }
3766 }
3767
3768 mptsas_free_fw_event(ioc, fw_event);
3769}
3770
3771
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003772static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003773mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003774{
3775 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003776 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003777 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003778
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003779 mutex_lock(&ioc->sas_topology_mutex);
3780 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3781 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003782 if (!mptsas_is_end_device(
3783 &port_info->phy_info[i].attached))
3784 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003785 if (port_info->phy_info[i].attached.sas_address
3786 != sas_address)
3787 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003788 phy_info = &port_info->phy_info[i];
3789 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003790 }
3791 }
3792 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003793 return phy_info;
3794}
3795
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303796/**
3797 * mptsas_find_phyinfo_by_phys_disk_num -
3798 * @ioc: Pointer to MPT_ADAPTER structure
3799 * @phys_disk_num:
3800 * @channel:
3801 * @id:
3802 *
3803 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003804static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303805mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3806 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003807{
Eric Mooreb506ade2007-01-29 09:45:37 -07003808 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303809 struct mptsas_portinfo *port_info;
3810 RaidPhysDiskPage1_t *phys_disk = NULL;
3811 int num_paths;
3812 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003813 int i;
3814
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303815 phy_info = NULL;
3816 if (!ioc->raid_data.pIocPg3)
3817 return NULL;
3818 /* dual port support */
3819 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
3820 if (!num_paths)
3821 goto out;
3822 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
3823 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
3824 if (!phys_disk)
3825 goto out;
3826 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
3827 for (i = 0; i < num_paths; i++) {
3828 if ((phys_disk->Path[i].Flags & 1) != 0)
3829 /* entry no longer valid */
3830 continue;
3831 if ((id == phys_disk->Path[i].PhysDiskID) &&
3832 (channel == phys_disk->Path[i].PhysDiskBus)) {
3833 memcpy(&sas_address, &phys_disk->Path[i].WWID,
3834 sizeof(u64));
3835 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3836 sas_address);
3837 goto out;
3838 }
3839 }
3840
3841 out:
3842 kfree(phys_disk);
3843 if (phy_info)
3844 return phy_info;
3845
3846 /*
3847 * Extra code to handle RAID0 case, where the sas_address is not updated
3848 * in phys_disk_page_1 when hotswapped
3849 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003850 mutex_lock(&ioc->sas_topology_mutex);
3851 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303852 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07003853 if (!mptsas_is_end_device(
3854 &port_info->phy_info[i].attached))
3855 continue;
3856 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3857 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303858 if ((port_info->phy_info[i].attached.phys_disk_num ==
3859 phys_disk_num) &&
3860 (port_info->phy_info[i].attached.id == id) &&
3861 (port_info->phy_info[i].attached.channel ==
3862 channel))
3863 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06003864 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003865 }
3866 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003867 return phy_info;
3868}
3869
3870static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003871mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3872{
Eric Mooref99be432007-01-04 20:46:54 -07003873 int rc;
3874
Moore, Ericf44e5462006-03-14 09:14:21 -07003875 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003876 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003877}
3878
3879static void
3880mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3881{
3882 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3883 mptsas_reprobe_lun);
3884}
3885
Eric Mooreb506ade2007-01-29 09:45:37 -07003886static void
3887mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3888{
3889 CONFIGPARMS cfg;
3890 ConfigPageHeader_t hdr;
3891 dma_addr_t dma_handle;
3892 pRaidVolumePage0_t buffer = NULL;
3893 RaidPhysDiskPage0_t phys_disk;
3894 int i;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303895 struct mptsas_phyinfo *phy_info;
3896 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003897
3898 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3899 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3900 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3901 cfg.pageAddr = (channel << 8) + id;
3902 cfg.cfghdr.hdr = &hdr;
3903 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3904
3905 if (mpt_config(ioc, &cfg) != 0)
3906 goto out;
3907
3908 if (!hdr.PageLength)
3909 goto out;
3910
3911 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3912 &dma_handle);
3913
3914 if (!buffer)
3915 goto out;
3916
3917 cfg.physAddr = dma_handle;
3918 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3919
3920 if (mpt_config(ioc, &cfg) != 0)
3921 goto out;
3922
3923 if (!(buffer->VolumeStatus.Flags &
3924 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3925 goto out;
3926
3927 if (!buffer->NumPhysDisks)
3928 goto out;
3929
3930 for (i = 0; i < buffer->NumPhysDisks; i++) {
3931
3932 if (mpt_raid_phys_disk_pg0(ioc,
3933 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3934 continue;
3935
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303936 if (mptsas_sas_device_pg0(ioc, &sas_device,
3937 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3938 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3939 (phys_disk.PhysDiskBus << 8) +
3940 phys_disk.PhysDiskID))
3941 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003942
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303943 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3944 sas_device.sas_address);
3945 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003946 }
3947
3948 out:
3949 if (buffer)
3950 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3951 dma_handle);
3952}
Moore, Erice6b2d762006-03-14 09:14:24 -07003953/*
3954 * Work queue thread to handle SAS hotplug events
3955 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003956static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303957mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3958 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003959{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003960 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003961 struct scsi_target * starget;
Moore, Ericc73787e2006-01-26 16:20:06 -07003962 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003963 VirtTarget *vtarget;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303964 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003965
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303966 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003967
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303968 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003969
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303970 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003971 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003972
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303973 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3974 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3975 hot_plug_info->id) {
3976 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3977 "to add hidden disk - target_id matchs "
3978 "volume_id\n", ioc->name);
3979 mptsas_free_fw_event(ioc, fw_event);
3980 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003981 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003982 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303983 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003984
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003985 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303986 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3987 mptsas_sas_device_pg0(ioc, &sas_device,
3988 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3989 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3990 (hot_plug_info->channel << 8) +
3991 hot_plug_info->id);
Moore, Ericc73787e2006-01-26 16:20:06 -07003992
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303993 if (!sas_device.handle)
3994 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003995
Kashyap, Desai3eb08222009-05-29 16:47:26 +05303996 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3997 if (!phy_info)
3998 break;
3999
4000 if (mptsas_get_rphy(phy_info))
4001 break;
4002
4003 mptsas_add_end_device(ioc, phy_info);
4004 break;
4005
4006 case MPTSAS_DEL_DEVICE:
4007 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4008 hot_plug_info->sas_address);
4009 mptsas_del_end_device(ioc, phy_info);
4010 break;
4011
4012 case MPTSAS_DEL_PHYSDISK:
4013
4014 mpt_findImVolumes(ioc);
4015
4016 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304017 ioc, hot_plug_info->phys_disk_num,
4018 hot_plug_info->channel,
4019 hot_plug_info->id);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304020 mptsas_del_end_device(ioc, phy_info);
4021 break;
4022
4023 case MPTSAS_ADD_PHYSDISK_REPROBE:
4024
Christoph Hellwige3094442006-02-16 13:25:36 +01004025 if (mptsas_sas_device_pg0(ioc, &sas_device,
4026 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004027 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304028 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4029 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4030 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4031 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004032 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004033 }
4034
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304035 phy_info = mptsas_find_phyinfo_by_sas_address(
4036 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004037
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304038 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304039 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304040 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4041 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004042 break;
4043 }
4044
4045 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304046 if (!starget) {
4047 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4048 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4049 __func__, hot_plug_info->id, __LINE__));
4050 break;
4051 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004052
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304053 vtarget = starget->hostdata;
4054 if (!vtarget) {
4055 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4056 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4057 __func__, hot_plug_info->id, __LINE__));
4058 break;
4059 }
Eric Moore547f9a22006-06-27 14:42:12 -06004060
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304061 mpt_findImVolumes(ioc);
4062
4063 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4064 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4065 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4066 hot_plug_info->phys_disk_num, (unsigned long long)
4067 sas_device.sas_address);
4068
4069 vtarget->id = hot_plug_info->phys_disk_num;
4070 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4071 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4072 mptsas_reprobe_target(starget, 1);
4073 break;
4074
4075 case MPTSAS_DEL_PHYSDISK_REPROBE:
4076
4077 if (mptsas_sas_device_pg0(ioc, &sas_device,
4078 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4079 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4080 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304081 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304082 "%s: fw_id=%d exit at line=%d\n",
4083 ioc->name, __func__,
4084 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004085 break;
4086 }
4087
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304088 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4089 sas_device.sas_address);
4090 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304091 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304092 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4093 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004094 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004095 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004096
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304097 starget = mptsas_get_starget(phy_info);
4098 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304099 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304100 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4101 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004102 break;
4103 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004104
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304105 vtarget = starget->hostdata;
4106 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304107 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304108 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4109 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004110 break;
4111 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304112
4113 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4114 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4115 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4116 __func__, hot_plug_info->id, __LINE__));
4117 break;
4118 }
4119
4120 mpt_findImVolumes(ioc);
4121
4122 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4123 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4124 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4125 hot_plug_info->phys_disk_num, (unsigned long long)
4126 sas_device.sas_address);
4127
4128 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4129 vtarget->id = hot_plug_info->id;
4130 phy_info->attached.phys_disk_num = ~0;
4131 mptsas_reprobe_target(starget, 0);
4132 mptsas_add_device_component_by_fw(ioc,
4133 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004134 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304135
Moore, Ericc73787e2006-01-26 16:20:06 -07004136 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304137
Moore, Ericc73787e2006-01-26 16:20:06 -07004138 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304139 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4140 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4141 hot_plug_info->id);
4142 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4143 hot_plug_info->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07004144 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304145
Moore, Ericc73787e2006-01-26 16:20:06 -07004146 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304147
Moore, Ericc73787e2006-01-26 16:20:06 -07004148 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304149 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4150 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4151 hot_plug_info->id);
4152 scsi_remove_device(hot_plug_info->sdev);
4153 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787e2006-01-26 16:20:06 -07004154 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304155
Eric Mooreb506ade2007-01-29 09:45:37 -07004156 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304157
4158 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004159 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304160 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004161 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304162
Moore, Ericbd23e942006-04-17 12:43:04 -06004163 default:
4164 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004165 }
4166
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304167 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004168}
4169
4170static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304171mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004172{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304173 MPT_ADAPTER *ioc;
4174 struct mptsas_hotplug_event hot_plug_info;
4175 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4176 u32 device_info;
4177 u64 sas_address;
4178
4179 ioc = fw_event->ioc;
4180 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4181 fw_event->event_data;
4182 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004183
4184 if ((device_info &
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304185 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4186 MPI_SAS_DEVICE_INFO_STP_TARGET |
4187 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4188 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004189 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304190 }
4191
4192 if (sas_event_data->ReasonCode ==
4193 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4194 mptbase_sas_persist_operation(ioc,
4195 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4196 mptsas_free_fw_event(ioc, fw_event);
4197 return;
4198 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004199
Moore, Eric4b766472006-03-14 09:14:12 -07004200 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004201 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004202 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304203 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4204 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4205 hot_plug_info.channel = sas_event_data->Bus;
4206 hot_plug_info.id = sas_event_data->TargetID;
4207 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004208 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304209 sizeof(u64));
4210 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4211 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004212 if (sas_event_data->ReasonCode &
4213 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304214 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004215 else
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304216 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4217 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004218 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304219
Moore, Eric4b766472006-03-14 09:14:12 -07004220 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304221 mptbase_sas_persist_operation(ioc,
4222 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4223 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004224 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304225
Moore, Eric4b766472006-03-14 09:14:12 -07004226 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304227 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004228 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304229 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004230 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304231 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004232 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004233 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004234}
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304235
Moore, Ericc73787e2006-01-26 16:20:06 -07004236static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304237mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787e2006-01-26 16:20:06 -07004238{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304239 MPT_ADAPTER *ioc;
4240 EVENT_DATA_RAID *raid_event_data;
4241 struct mptsas_hotplug_event hot_plug_info;
4242 int status;
4243 int state;
4244 struct scsi_device *sdev = NULL;
4245 VirtDevice *vdevice = NULL;
4246 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787e2006-01-26 16:20:06 -07004247
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304248 ioc = fw_event->ioc;
4249 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4250 status = le32_to_cpu(raid_event_data->SettingsStatus);
4251 state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07004252
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304253 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4254 hot_plug_info.id = raid_event_data->VolumeID;
4255 hot_plug_info.channel = raid_event_data->VolumeBus;
4256 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4257
4258 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4259 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4260 raid_event_data->ReasonCode ==
4261 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4262 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4263 hot_plug_info.id, 0);
4264 hot_plug_info.sdev = sdev;
4265 if (sdev)
4266 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07004267 }
4268
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304269 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4270 "ReasonCode=%02x\n", ioc->name, __func__,
4271 raid_event_data->ReasonCode));
Moore, Ericc73787e2006-01-26 16:20:06 -07004272
4273 switch (raid_event_data->ReasonCode) {
4274 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304275 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004276 break;
4277 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304278 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004279 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004280 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4281 switch (state) {
4282 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004283 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304284 mpt_raid_phys_disk_pg0(ioc,
4285 raid_event_data->PhysDiskNum, &phys_disk);
4286 hot_plug_info.id = phys_disk.PhysDiskID;
4287 hot_plug_info.channel = phys_disk.PhysDiskBus;
4288 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004289 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304290 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004291 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004292 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4293 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4294 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304295 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004296 break;
4297 default:
4298 break;
4299 }
4300 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07004301 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304302 if (!sdev)
4303 break;
4304 vdevice->vtarget->deleted = 1; /* block IO */
4305 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004306 break;
4307 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304308 if (sdev) {
4309 scsi_device_put(sdev);
4310 break;
4311 }
4312 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004313 break;
4314 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304315 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4316 if (!sdev)
4317 break;
4318 vdevice->vtarget->deleted = 1; /* block IO */
4319 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4320 break;
4321 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004322 switch (state) {
4323 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4324 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304325 if (!sdev)
4326 break;
4327 vdevice->vtarget->deleted = 1; /* block IO */
4328 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004329 break;
4330 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4331 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304332 if (sdev) {
4333 scsi_device_put(sdev);
4334 break;
4335 }
4336 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004337 break;
4338 default:
4339 break;
4340 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004341 break;
4342 default:
4343 break;
4344 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304345
4346 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4347 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4348 else
4349 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787e2006-01-26 16:20:06 -07004350}
4351
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304352/**
4353 * mptsas_issue_tm - send mptsas internal tm request
4354 * @ioc: Pointer to MPT_ADAPTER structure
4355 * @type: Task Management type
4356 * @channel: channel number for task management
4357 * @id: Logical Target ID for reset (if appropriate)
4358 * @lun: Logical unit for reset (if appropriate)
4359 * @task_context: Context for the task to be aborted
4360 * @timeout: timeout for task management control
4361 *
4362 * return 0 on success and -1 on failure:
4363 *
4364 */
4365static int
4366mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4367 int task_context, ulong timeout, u8 *issue_reset)
4368{
4369 MPT_FRAME_HDR *mf;
4370 SCSITaskMgmt_t *pScsiTm;
4371 int retval;
4372 unsigned long timeleft;
4373
4374 *issue_reset = 0;
4375 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4376 if (mf == NULL) {
4377 retval = -1; /* return failure */
4378 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4379 "msg frames!!\n", ioc->name));
4380 goto out;
4381 }
4382
4383 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4384 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4385 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4386 type, timeout, channel, id, (unsigned long long)lun,
4387 task_context));
4388
4389 pScsiTm = (SCSITaskMgmt_t *) mf;
4390 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4391 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4392 pScsiTm->TaskType = type;
4393 pScsiTm->MsgFlags = 0;
4394 pScsiTm->TargetID = id;
4395 pScsiTm->Bus = channel;
4396 pScsiTm->ChainOffset = 0;
4397 pScsiTm->Reserved = 0;
4398 pScsiTm->Reserved1 = 0;
4399 pScsiTm->TaskMsgContext = task_context;
4400 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4401
4402 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4403 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4404 retval = 0;
4405 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4406
4407 /* Now wait for the command to complete */
4408 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4409 timeout*HZ);
4410 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4411 retval = -1; /* return failure */
4412 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4413 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4414 mpt_free_msg_frame(ioc, mf);
4415 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4416 goto out;
4417 *issue_reset = 1;
4418 goto out;
4419 }
4420
4421 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4422 retval = -1; /* return failure */
4423 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4424 "TaskMgmt request: failed with no reply\n", ioc->name));
4425 goto out;
4426 }
4427
4428 out:
4429 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4430 return retval;
4431}
4432
4433/**
4434 * mptsas_broadcast_primative_work - Handle broadcast primitives
4435 * @work: work queue payload containing info describing the event
4436 *
4437 * this will be handled in workqueue context.
4438 */
4439static void
4440mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4441{
4442 MPT_ADAPTER *ioc = fw_event->ioc;
4443 MPT_FRAME_HDR *mf;
4444 VirtDevice *vdevice;
4445 int ii;
4446 struct scsi_cmnd *sc;
4447 SCSITaskMgmtReply_t *pScsiTmReply;
4448 u8 issue_reset;
4449 int task_context;
4450 u8 channel, id;
4451 int lun;
4452 u32 termination_count;
4453 u32 query_count;
4454
4455 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4456 "%s - enter\n", ioc->name, __func__));
4457
4458 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4459 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4460 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4461 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4462 return;
4463 }
4464
4465 issue_reset = 0;
4466 termination_count = 0;
4467 query_count = 0;
4468 mpt_findImVolumes(ioc);
4469 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4470
4471 for (ii = 0; ii < ioc->req_depth; ii++) {
4472 if (ioc->fw_events_off)
4473 goto out;
4474 sc = mptscsih_get_scsi_lookup(ioc, ii);
4475 if (!sc)
4476 continue;
4477 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4478 if (!mf)
4479 continue;
4480 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4481 vdevice = sc->device->hostdata;
4482 if (!vdevice || !vdevice->vtarget)
4483 continue;
4484 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4485 continue; /* skip hidden raid components */
4486 if (vdevice->vtarget->raidVolume)
4487 continue; /* skip hidden raid components */
4488 channel = vdevice->vtarget->channel;
4489 id = vdevice->vtarget->id;
4490 lun = vdevice->lun;
4491 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4492 channel, id, (u64)lun, task_context, 30, &issue_reset))
4493 goto out;
4494 query_count++;
4495 termination_count +=
4496 le32_to_cpu(pScsiTmReply->TerminationCount);
4497 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4498 (pScsiTmReply->ResponseCode ==
4499 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4500 pScsiTmReply->ResponseCode ==
4501 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4502 continue;
4503 if (mptsas_issue_tm(ioc,
4504 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4505 channel, id, (u64)lun, 0, 30, &issue_reset))
4506 goto out;
4507 termination_count +=
4508 le32_to_cpu(pScsiTmReply->TerminationCount);
4509 }
4510
4511 out:
4512 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4513 "%s - exit, query_count = %d termination_count = %d\n",
4514 ioc->name, __func__, query_count, termination_count));
4515
4516 ioc->broadcast_aen_busy = 0;
4517 mpt_clear_taskmgmt_in_progress_flag(ioc);
4518 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4519
4520 if (issue_reset) {
4521 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4522 ioc->name, __func__);
4523 mpt_HardResetHandler(ioc, CAN_SLEEP);
4524 }
4525 mptsas_free_fw_event(ioc, fw_event);
4526}
4527
Eric Mooreb506ade2007-01-29 09:45:37 -07004528/*
4529 * mptsas_send_ir2_event - handle exposing hidden disk when
4530 * an inactive raid volume is added
4531 *
4532 * @ioc: Pointer to MPT_ADAPTER structure
4533 * @ir2_data
4534 *
4535 */
4536static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304537mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004538{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304539 MPT_ADAPTER *ioc;
4540 struct mptsas_hotplug_event hot_plug_info;
4541 MPI_EVENT_DATA_IR2 *ir2_data;
4542 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304543 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004544
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304545 ioc = fw_event->ioc;
4546 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4547 reasonCode = ir2_data->ReasonCode;
4548
4549 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4550 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4551
4552 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4553 hot_plug_info.id = ir2_data->TargetID;
4554 hot_plug_info.channel = ir2_data->Bus;
4555 switch (reasonCode) {
4556 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4557 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4558 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304559 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4560 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4561 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4562 break;
4563 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4564 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4565 mpt_raid_phys_disk_pg0(ioc,
4566 ir2_data->PhysDiskNum, &phys_disk);
4567 hot_plug_info.id = phys_disk.PhysDiskID;
4568 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4569 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304570 default:
4571 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004572 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304573 }
4574 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4575}
Moore, Erice6b2d762006-03-14 09:14:24 -07004576
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004577static int
4578mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4579{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304580 u32 event = le32_to_cpu(reply->Event);
4581 int sz, event_data_sz;
4582 struct fw_event_work *fw_event;
4583 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004584
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304585 /* events turned off due to host reset or driver unloading */
4586 if (ioc->fw_events_off)
4587 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004588
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304589 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004590 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304591 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4592 {
4593 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4594 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4595 if (broadcast_event_data->Primitive !=
4596 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4597 return 0;
4598 if (ioc->broadcast_aen_busy)
4599 return 0;
4600 ioc->broadcast_aen_busy = 1;
4601 break;
4602 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004603 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304604 {
4605 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4606 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4607
4608 if (sas_event_data->ReasonCode ==
4609 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4610 mptsas_target_reset_queue(ioc, sas_event_data);
4611 return 0;
4612 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004613 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304614 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304615 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4616 {
4617 MpiEventDataSasExpanderStatusChange_t *expander_data =
4618 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4619
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304620 if (ioc->old_sas_discovery_protocal)
4621 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304622
4623 if (expander_data->ReasonCode ==
4624 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4625 ioc->device_missing_delay)
4626 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004627 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304628 }
4629 case MPI_EVENT_SAS_DISCOVERY:
4630 {
4631 u32 discovery_status;
4632 EventDataSasDiscovery_t *discovery_data =
4633 (EventDataSasDiscovery_t *)reply->Data;
4634
4635 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4636 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304637 if (ioc->old_sas_discovery_protocal && !discovery_status)
4638 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304639 return 0;
4640 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304641 case MPI_EVENT_INTEGRATED_RAID:
4642 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004643 case MPI_EVENT_IR2:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304644 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4645 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004646 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004647 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304648 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004649 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004650
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304651 event_data_sz = ((reply->MsgLength * 4) -
4652 offsetof(EventNotificationReply_t, Data));
4653 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4654 fw_event = kzalloc(sz, GFP_ATOMIC);
4655 if (!fw_event) {
4656 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4657 __func__, __LINE__);
4658 return 0;
4659 }
4660 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4661 fw_event->event = event;
4662 fw_event->ioc = ioc;
4663 mptsas_add_fw_event(ioc, fw_event, delay);
4664 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004665}
4666
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304667/* Delete a volume when no longer listed in ioc pg2
4668 */
4669static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4670{
4671 struct scsi_device *sdev;
4672 int i;
4673
4674 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4675 if (!sdev)
4676 return;
4677 if (!ioc->raid_data.pIocPg2)
4678 goto out;
4679 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4680 goto out;
4681 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4682 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4683 goto release_sdev;
4684 out:
4685 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4686 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4687 scsi_remove_device(sdev);
4688 release_sdev:
4689 scsi_device_put(sdev);
4690}
4691
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004692static int
4693mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4694{
4695 struct Scsi_Host *sh;
4696 MPT_SCSI_HOST *hd;
4697 MPT_ADAPTER *ioc;
4698 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004699 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004700 int numSGE = 0;
4701 int scale;
4702 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004703 int error=0;
4704 int r;
4705
4706 r = mpt_attach(pdev,id);
4707 if (r)
4708 return r;
4709
4710 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304711 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004712 ioc->DoneCtx = mptsasDoneCtx;
4713 ioc->TaskCtx = mptsasTaskCtx;
4714 ioc->InternalCtx = mptsasInternalCtx;
4715
4716 /* Added sanity check on readiness of the MPT adapter.
4717 */
4718 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4719 printk(MYIOC_s_WARN_FMT
4720 "Skipping because it's not operational!\n",
4721 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004722 error = -ENODEV;
4723 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004724 }
4725
4726 if (!ioc->active) {
4727 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4728 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004729 error = -ENODEV;
4730 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004731 }
4732
4733 /* Sanity check - ensure at least 1 port is INITIATOR capable
4734 */
4735 ioc_cap = 0;
4736 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4737 if (ioc->pfacts[ii].ProtocolFlags &
4738 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4739 ioc_cap++;
4740 }
4741
4742 if (!ioc_cap) {
4743 printk(MYIOC_s_WARN_FMT
4744 "Skipping ioc=%p because SCSI Initiator mode "
4745 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004746 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004747 }
4748
4749 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4750 if (!sh) {
4751 printk(MYIOC_s_WARN_FMT
4752 "Unable to register controller with SCSI subsystem\n",
4753 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004754 error = -1;
4755 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004756 }
4757
4758 spin_lock_irqsave(&ioc->FreeQlock, flags);
4759
4760 /* Attach the SCSI Host to the IOC structure
4761 */
4762 ioc->sh = sh;
4763
4764 sh->io_port = 0;
4765 sh->n_io_port = 0;
4766 sh->irq = 0;
4767
4768 /* set 16 byte cdb's */
4769 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05304770 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
4771 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07004772 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004773 sh->transportt = mptsas_transport_template;
4774
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004775 /* Required entry.
4776 */
4777 sh->unique_id = ioc->id;
4778
4779 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004780 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004781 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004782 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004783 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004784
4785 /* Verify that we won't exceed the maximum
4786 * number of chain buffers
4787 * We can optimize: ZZ = req_sz/sizeof(SGE)
4788 * For 32bit SGE's:
4789 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4790 * + (req_sz - 64)/sizeof(SGE)
4791 * A slightly different algorithm is required for
4792 * 64bit SGEs.
4793 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304794 scale = ioc->req_sz/ioc->SGE_size;
4795 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004796 numSGE = (scale - 1) *
4797 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304798 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004799 } else {
4800 numSGE = 1 + (scale - 1) *
4801 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304802 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004803 }
4804
4805 if (numSGE < sh->sg_tablesize) {
4806 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304807 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004808 "Resetting sg_tablesize to %d from %d\n",
4809 ioc->name, numSGE, sh->sg_tablesize));
4810 sh->sg_tablesize = numSGE;
4811 }
4812
Eric Mooree7eae9f2007-09-29 10:15:59 -06004813 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004814 hd->ioc = ioc;
4815
4816 /* SCSI needs scsi_cmnd lookup table!
4817 * (with size equal to req_depth*PtrSz!)
4818 */
Eric Mooree8206382007-09-29 10:16:53 -06004819 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4820 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004821 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004822 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004823 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004824 }
Eric Mooree8206382007-09-29 10:16:53 -06004825 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004826
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304827 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004828 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004829
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004830 ioc->sas_data.ptClear = mpt_pt_clear;
4831
Eric Mooredf9e0622007-01-29 09:46:21 -07004832 hd->last_queue_full = 0;
4833 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304834 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4835 mutex_init(&ioc->sas_device_info_mutex);
4836
Eric Mooredf9e0622007-01-29 09:46:21 -07004837 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4838
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004839 if (ioc->sas_data.ptClear==1) {
4840 mptbase_sas_persist_operation(
4841 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4842 }
4843
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004844 error = scsi_add_host(sh, &ioc->pcidev->dev);
4845 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004846 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4847 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004848 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004849 }
4850
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304851 /* older firmware doesn't support expander events */
4852 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4853 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004854 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304855 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004856 return 0;
4857
Eric Moore547f9a22006-06-27 14:42:12 -06004858 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004859
4860 mptscsih_remove(pdev);
4861 return error;
4862}
4863
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304864void
4865mptsas_shutdown(struct pci_dev *pdev)
4866{
4867 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4868
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304869 mptsas_fw_event_off(ioc);
4870 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304871}
4872
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004873static void __devexit mptsas_remove(struct pci_dev *pdev)
4874{
4875 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4876 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004877 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004878
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304879 mptsas_shutdown(pdev);
4880
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304881 mptsas_del_device_components(ioc);
4882
Eric Mooreb506ade2007-01-29 09:45:37 -07004883 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004884 sas_remove_host(ioc->sh);
4885
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004886 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004887 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4888 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004889 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304890 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304891
Eric Moore547f9a22006-06-27 14:42:12 -06004892 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004893 kfree(p);
4894 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004895 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304896 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004897 mptscsih_remove(pdev);
4898}
4899
4900static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004901 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004902 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004903 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004904 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004905 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004906 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004907 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004908 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004909 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004910 PCI_ANY_ID, PCI_ANY_ID },
4911 {0} /* Terminating entry */
4912};
4913MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4914
4915
4916static struct pci_driver mptsas_driver = {
4917 .name = "mptsas",
4918 .id_table = mptsas_pci_table,
4919 .probe = mptsas_probe,
4920 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304921 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004922#ifdef CONFIG_PM
4923 .suspend = mptscsih_suspend,
4924 .resume = mptscsih_resume,
4925#endif
4926};
4927
4928static int __init
4929mptsas_init(void)
4930{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304931 int error;
4932
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004933 show_mptmod_ver(my_NAME, my_VERSION);
4934
4935 mptsas_transport_template =
4936 sas_attach_transport(&mptsas_transport_functions);
4937 if (!mptsas_transport_template)
4938 return -ENODEV;
4939
4940 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304941 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004942 mptsasInternalCtx =
4943 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004944 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304945 mptsasDeviceResetCtx =
4946 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004947
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304948 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4949 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004950
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304951 error = pci_register_driver(&mptsas_driver);
4952 if (error)
4953 sas_release_transport(mptsas_transport_template);
4954
4955 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004956}
4957
4958static void __exit
4959mptsas_exit(void)
4960{
4961 pci_unregister_driver(&mptsas_driver);
4962 sas_release_transport(mptsas_transport_template);
4963
4964 mpt_reset_deregister(mptsasDoneCtx);
4965 mpt_event_deregister(mptsasDoneCtx);
4966
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004967 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004968 mpt_deregister(mptsasInternalCtx);
4969 mpt_deregister(mptsasTaskCtx);
4970 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304971 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004972}
4973
4974module_init(mptsas_init);
4975module_exit(mptsas_exit);