blob: 02a18dfcd52a18e06267abfd6d1a43424370d086 [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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Ericc73787ee2006-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));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303317 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303318 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3319
3320 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3321 if (port_info) {
3322 for (i = 0; i < port_info->num_phys; i++) {
3323 port_info->phy_info[i].portinfo = port_info;
3324 port_info->phy_info[i].handle =
3325 le16_to_cpu(expander_data->DevHandle);
3326 port_info->phy_info[i].identify.sas_address =
3327 le64_to_cpu(sas_address);
3328 port_info->phy_info[i].identify.handle_parent =
3329 le16_to_cpu(expander_data->ParentDevHandle);
3330 }
3331 mptsas_expander_refresh(ioc, port_info);
3332 } else if (!port_info && expander_data->NumPhys)
3333 mptsas_expander_event_add(ioc, expander_data);
3334 } else if (expander_data->ReasonCode ==
3335 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3336 mptsas_expander_delete(ioc, port_info, 0);
3337
3338 mptsas_free_fw_event(ioc, fw_event);
3339}
3340
3341
3342/**
3343 * mptsas_expander_add -
3344 * @ioc: Pointer to MPT_ADAPTER structure
3345 * @handle:
3346 *
3347 */
3348struct mptsas_portinfo *
3349mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3350{
3351 struct mptsas_portinfo buffer, *port_info;
3352 int i;
3353
3354 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3355 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3356 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3357 return NULL;
3358
3359 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3360 if (!port_info) {
3361 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3362 "%s: exit at line=%d\n", ioc->name,
3363 __func__, __LINE__));
3364 return NULL;
3365 }
3366 port_info->num_phys = buffer.num_phys;
3367 port_info->phy_info = buffer.phy_info;
3368 for (i = 0; i < port_info->num_phys; i++)
3369 port_info->phy_info[i].portinfo = port_info;
3370 mutex_lock(&ioc->sas_topology_mutex);
3371 list_add_tail(&port_info->list, &ioc->sas_topology);
3372 mutex_unlock(&ioc->sas_topology_mutex);
3373 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3374 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3375 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3376 mptsas_expander_refresh(ioc, port_info);
3377 return port_info;
3378}
3379
3380static void
3381mptsas_send_link_status_event(struct fw_event_work *fw_event)
3382{
3383 MPT_ADAPTER *ioc;
3384 MpiEventDataSasPhyLinkStatus_t *link_data;
3385 struct mptsas_portinfo *port_info;
3386 struct mptsas_phyinfo *phy_info = NULL;
3387 __le64 sas_address;
3388 u8 phy_num;
3389 u8 link_rate;
3390
3391 ioc = fw_event->ioc;
3392 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3393
3394 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3395 sas_address = le64_to_cpu(sas_address);
3396 link_rate = link_data->LinkRates >> 4;
3397 phy_num = link_data->PhyNum;
3398
3399 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3400 if (port_info) {
3401 phy_info = &port_info->phy_info[phy_num];
3402 if (phy_info)
3403 phy_info->negotiated_link_rate = link_rate;
3404 }
3405
3406 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3407 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3408
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303409 if (!port_info) {
3410 if (ioc->old_sas_discovery_protocal) {
3411 port_info = mptsas_expander_add(ioc,
3412 le16_to_cpu(link_data->DevHandle));
3413 if (port_info)
3414 goto out;
3415 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303416 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303417 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303418
3419 if (port_info == ioc->hba_port_info)
3420 mptsas_probe_hba_phys(ioc);
3421 else
3422 mptsas_expander_refresh(ioc, port_info);
3423 } else if (phy_info && phy_info->phy) {
3424 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3425 phy_info->phy->negotiated_linkrate =
3426 SAS_PHY_DISABLED;
3427 else if (link_rate ==
3428 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3429 phy_info->phy->negotiated_linkrate =
3430 SAS_LINK_RATE_FAILED;
3431 else
3432 phy_info->phy->negotiated_linkrate =
3433 SAS_LINK_RATE_UNKNOWN;
3434 }
3435 out:
3436 mptsas_free_fw_event(ioc, fw_event);
3437}
3438
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303439static void
3440mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3441{
3442 struct mptsas_portinfo buffer, *port_info;
3443 struct mptsas_device_info *sas_info;
3444 struct mptsas_devinfo sas_device;
3445 u32 handle;
3446 VirtTarget *vtarget = NULL;
3447 struct mptsas_phyinfo *phy_info;
3448 u8 found_expander;
3449 int retval, retry_count;
3450 unsigned long flags;
3451
3452 mpt_findImVolumes(ioc);
3453
3454 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3455 if (ioc->ioc_reset_in_progress) {
3456 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3457 "%s: exiting due to a parallel reset \n", ioc->name,
3458 __func__));
3459 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3460 return;
3461 }
3462 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3463
3464 /* devices, logical volumes */
3465 mutex_lock(&ioc->sas_device_info_mutex);
3466 redo_device_scan:
3467 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303468 if (sas_info->is_cached)
3469 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303470 if (!sas_info->is_logical_volume) {
3471 sas_device.handle = 0;
3472 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303473retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303474 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303475 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3476 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3477 (sas_info->fw.channel << 8) +
3478 sas_info->fw.id);
3479
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303480 if (sas_device.handle)
3481 continue;
3482 if (retval == -EBUSY) {
3483 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3484 if (ioc->ioc_reset_in_progress) {
3485 dfailprintk(ioc,
3486 printk(MYIOC_s_DEBUG_FMT
3487 "%s: exiting due to reset\n",
3488 ioc->name, __func__));
3489 spin_unlock_irqrestore
3490 (&ioc->taskmgmt_lock, flags);
3491 mutex_unlock(&ioc->
3492 sas_device_info_mutex);
3493 return;
3494 }
3495 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3496 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303497 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303498
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303499 if (retval && (retval != -ENODEV)) {
3500 if (retry_count < 10) {
3501 retry_count++;
3502 goto retry_page;
3503 } else {
3504 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3505 "%s: Config page retry exceeded retry "
3506 "count deleting device 0x%llx\n",
3507 ioc->name, __func__,
3508 sas_info->sas_address));
3509 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303510 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303511
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303512 /* delete device */
3513 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303514 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303515
3516 if (vtarget)
3517 vtarget->deleted = 1;
3518
3519 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3520 sas_info->sas_address);
3521
3522 if (phy_info) {
3523 mptsas_del_end_device(ioc, phy_info);
3524 goto redo_device_scan;
3525 }
3526 } else
3527 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303528 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003529 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303530
3531 /* expanders */
3532 mutex_lock(&ioc->sas_topology_mutex);
3533 redo_expander_scan:
3534 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3535
3536 if (port_info->phy_info &&
3537 (!(port_info->phy_info[0].identify.device_info &
3538 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3539 continue;
3540 found_expander = 0;
3541 handle = 0xFFFF;
3542 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3543 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3544 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3545 !found_expander) {
3546
3547 handle = buffer.phy_info[0].handle;
3548 if (buffer.phy_info[0].identify.sas_address ==
3549 port_info->phy_info[0].identify.sas_address) {
3550 found_expander = 1;
3551 }
3552 kfree(buffer.phy_info);
3553 }
3554
3555 if (!found_expander) {
3556 mptsas_expander_delete(ioc, port_info, 0);
3557 goto redo_expander_scan;
3558 }
3559 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003560 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303561}
3562
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303563/**
3564 * mptsas_probe_expanders - adding expanders
3565 * @ioc: Pointer to MPT_ADAPTER structure
3566 *
3567 **/
3568static void
3569mptsas_probe_expanders(MPT_ADAPTER *ioc)
3570{
3571 struct mptsas_portinfo buffer, *port_info;
3572 u32 handle;
3573 int i;
3574
3575 handle = 0xFFFF;
3576 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3577 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3578 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3579
3580 handle = buffer.phy_info[0].handle;
3581 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3582 buffer.phy_info[0].identify.sas_address);
3583
3584 if (port_info) {
3585 /* refreshing handles */
3586 for (i = 0; i < buffer.num_phys; i++) {
3587 port_info->phy_info[i].handle = handle;
3588 port_info->phy_info[i].identify.handle_parent =
3589 buffer.phy_info[0].identify.handle_parent;
3590 }
3591 mptsas_expander_refresh(ioc, port_info);
3592 kfree(buffer.phy_info);
3593 continue;
3594 }
3595
3596 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3597 if (!port_info) {
3598 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3599 "%s: exit at line=%d\n", ioc->name,
3600 __func__, __LINE__));
3601 return;
3602 }
3603 port_info->num_phys = buffer.num_phys;
3604 port_info->phy_info = buffer.phy_info;
3605 for (i = 0; i < port_info->num_phys; i++)
3606 port_info->phy_info[i].portinfo = port_info;
3607 mutex_lock(&ioc->sas_topology_mutex);
3608 list_add_tail(&port_info->list, &ioc->sas_topology);
3609 mutex_unlock(&ioc->sas_topology_mutex);
3610 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3611 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3612 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3613 mptsas_expander_refresh(ioc, port_info);
3614 }
3615}
3616
3617static void
3618mptsas_probe_devices(MPT_ADAPTER *ioc)
3619{
3620 u16 handle;
3621 struct mptsas_devinfo sas_device;
3622 struct mptsas_phyinfo *phy_info;
3623
3624 handle = 0xFFFF;
3625 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3626 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3627
3628 handle = sas_device.handle;
3629
3630 if ((sas_device.device_info &
3631 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3632 MPI_SAS_DEVICE_INFO_STP_TARGET |
3633 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3634 continue;
3635
3636 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3637 if (!phy_info)
3638 continue;
3639
3640 if (mptsas_get_rphy(phy_info))
3641 continue;
3642
3643 mptsas_add_end_device(ioc, phy_info);
3644 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003645}
3646
Kashyap, Desai2f187862009-05-29 16:52:37 +05303647/**
3648 * mptsas_scan_sas_topology -
3649 * @ioc: Pointer to MPT_ADAPTER structure
3650 * @sas_address:
3651 *
3652 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003653static void
3654mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3655{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303656 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003657 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003658
Moore, Erice6b2d762006-03-14 09:14:24 -07003659 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303660 mptsas_probe_expanders(ioc);
3661 mptsas_probe_devices(ioc);
3662
Moore, Ericf44e5462006-03-14 09:14:21 -07003663 /*
3664 Reporting RAID volumes.
3665 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303666 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3667 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3668 return;
Eric Moore793955f2007-01-29 09:42:20 -07003669 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303670 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3671 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3672 if (sdev) {
3673 scsi_device_put(sdev);
3674 continue;
3675 }
3676 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3677 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3678 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003679 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003680 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3681 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003682}
3683
Kashyap, Desai57e98512009-05-29 16:55:09 +05303684
3685static void
3686mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3687{
3688 MPT_ADAPTER *ioc;
3689 EventDataQueueFull_t *qfull_data;
3690 struct mptsas_device_info *sas_info;
3691 struct scsi_device *sdev;
3692 int depth;
3693 int id = -1;
3694 int channel = -1;
3695 int fw_id, fw_channel;
3696 u16 current_depth;
3697
3698
3699 ioc = fw_event->ioc;
3700 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3701 fw_id = qfull_data->TargetID;
3702 fw_channel = qfull_data->Bus;
3703 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3704
3705 /* if hidden raid component, look for the volume id */
3706 mutex_lock(&ioc->sas_device_info_mutex);
3707 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3708 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3709 list) {
3710 if (sas_info->is_cached ||
3711 sas_info->is_logical_volume)
3712 continue;
3713 if (sas_info->is_hidden_raid_component &&
3714 (sas_info->fw.channel == fw_channel &&
3715 sas_info->fw.id == fw_id)) {
3716 id = sas_info->volume_id;
3717 channel = MPTSAS_RAID_CHANNEL;
3718 goto out;
3719 }
3720 }
3721 } else {
3722 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3723 list) {
3724 if (sas_info->is_cached ||
3725 sas_info->is_hidden_raid_component ||
3726 sas_info->is_logical_volume)
3727 continue;
3728 if (sas_info->fw.channel == fw_channel &&
3729 sas_info->fw.id == fw_id) {
3730 id = sas_info->os.id;
3731 channel = sas_info->os.channel;
3732 goto out;
3733 }
3734 }
3735
3736 }
3737
3738 out:
3739 mutex_unlock(&ioc->sas_device_info_mutex);
3740
3741 if (id != -1) {
3742 shost_for_each_device(sdev, ioc->sh) {
3743 if (sdev->id == id && sdev->channel == channel) {
3744 if (current_depth > sdev->queue_depth) {
3745 sdev_printk(KERN_INFO, sdev,
3746 "strange observation, the queue "
3747 "depth is (%d) meanwhile fw queue "
3748 "depth (%d)\n", sdev->queue_depth,
3749 current_depth);
3750 continue;
3751 }
3752 depth = scsi_track_queue_full(sdev,
3753 current_depth - 1);
3754 if (depth > 0)
3755 sdev_printk(KERN_INFO, sdev,
3756 "Queue depth reduced to (%d)\n",
3757 depth);
3758 else if (depth < 0)
3759 sdev_printk(KERN_INFO, sdev,
3760 "Tagged Command Queueing is being "
3761 "disabled\n");
3762 else if (depth == 0)
3763 sdev_printk(KERN_INFO, sdev,
3764 "Queue depth not changed yet\n");
3765 }
3766 }
3767 }
3768
3769 mptsas_free_fw_event(ioc, fw_event);
3770}
3771
3772
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003773static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003774mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003775{
3776 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003777 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003778 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003779
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003780 mutex_lock(&ioc->sas_topology_mutex);
3781 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3782 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003783 if (!mptsas_is_end_device(
3784 &port_info->phy_info[i].attached))
3785 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003786 if (port_info->phy_info[i].attached.sas_address
3787 != sas_address)
3788 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003789 phy_info = &port_info->phy_info[i];
3790 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003791 }
3792 }
3793 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003794 return phy_info;
3795}
3796
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303797/**
3798 * mptsas_find_phyinfo_by_phys_disk_num -
3799 * @ioc: Pointer to MPT_ADAPTER structure
3800 * @phys_disk_num:
3801 * @channel:
3802 * @id:
3803 *
3804 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003805static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303806mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3807 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003808{
Eric Mooreb506ade2007-01-29 09:45:37 -07003809 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303810 struct mptsas_portinfo *port_info;
3811 RaidPhysDiskPage1_t *phys_disk = NULL;
3812 int num_paths;
3813 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003814 int i;
3815
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303816 phy_info = NULL;
3817 if (!ioc->raid_data.pIocPg3)
3818 return NULL;
3819 /* dual port support */
3820 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
3821 if (!num_paths)
3822 goto out;
3823 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
3824 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
3825 if (!phys_disk)
3826 goto out;
3827 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
3828 for (i = 0; i < num_paths; i++) {
3829 if ((phys_disk->Path[i].Flags & 1) != 0)
3830 /* entry no longer valid */
3831 continue;
3832 if ((id == phys_disk->Path[i].PhysDiskID) &&
3833 (channel == phys_disk->Path[i].PhysDiskBus)) {
3834 memcpy(&sas_address, &phys_disk->Path[i].WWID,
3835 sizeof(u64));
3836 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3837 sas_address);
3838 goto out;
3839 }
3840 }
3841
3842 out:
3843 kfree(phys_disk);
3844 if (phy_info)
3845 return phy_info;
3846
3847 /*
3848 * Extra code to handle RAID0 case, where the sas_address is not updated
3849 * in phys_disk_page_1 when hotswapped
3850 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003851 mutex_lock(&ioc->sas_topology_mutex);
3852 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303853 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07003854 if (!mptsas_is_end_device(
3855 &port_info->phy_info[i].attached))
3856 continue;
3857 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3858 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303859 if ((port_info->phy_info[i].attached.phys_disk_num ==
3860 phys_disk_num) &&
3861 (port_info->phy_info[i].attached.id == id) &&
3862 (port_info->phy_info[i].attached.channel ==
3863 channel))
3864 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06003865 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003866 }
3867 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003868 return phy_info;
3869}
3870
3871static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003872mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3873{
Eric Mooref99be432007-01-04 20:46:54 -07003874 int rc;
3875
Moore, Ericf44e5462006-03-14 09:14:21 -07003876 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003877 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003878}
3879
3880static void
3881mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3882{
3883 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3884 mptsas_reprobe_lun);
3885}
3886
Eric Mooreb506ade2007-01-29 09:45:37 -07003887static void
3888mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3889{
3890 CONFIGPARMS cfg;
3891 ConfigPageHeader_t hdr;
3892 dma_addr_t dma_handle;
3893 pRaidVolumePage0_t buffer = NULL;
3894 RaidPhysDiskPage0_t phys_disk;
3895 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303896 struct mptsas_phyinfo *phy_info;
3897 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003898
3899 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3900 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3901 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3902 cfg.pageAddr = (channel << 8) + id;
3903 cfg.cfghdr.hdr = &hdr;
3904 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3905
3906 if (mpt_config(ioc, &cfg) != 0)
3907 goto out;
3908
3909 if (!hdr.PageLength)
3910 goto out;
3911
3912 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3913 &dma_handle);
3914
3915 if (!buffer)
3916 goto out;
3917
3918 cfg.physAddr = dma_handle;
3919 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3920
3921 if (mpt_config(ioc, &cfg) != 0)
3922 goto out;
3923
3924 if (!(buffer->VolumeStatus.Flags &
3925 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3926 goto out;
3927
3928 if (!buffer->NumPhysDisks)
3929 goto out;
3930
3931 for (i = 0; i < buffer->NumPhysDisks; i++) {
3932
3933 if (mpt_raid_phys_disk_pg0(ioc,
3934 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3935 continue;
3936
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303937 if (mptsas_sas_device_pg0(ioc, &sas_device,
3938 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3939 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3940 (phys_disk.PhysDiskBus << 8) +
3941 phys_disk.PhysDiskID))
3942 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003943
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303944 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3945 sas_device.sas_address);
3946 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003947 }
3948
3949 out:
3950 if (buffer)
3951 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3952 dma_handle);
3953}
Moore, Erice6b2d762006-03-14 09:14:24 -07003954/*
3955 * Work queue thread to handle SAS hotplug events
3956 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003957static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303958mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3959 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003960{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003961 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003962 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003963 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003964 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303965 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003966
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303967 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003968
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303969 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003970
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303971 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003972 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003973
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303974 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3975 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3976 hot_plug_info->id) {
3977 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3978 "to add hidden disk - target_id matchs "
3979 "volume_id\n", ioc->name);
3980 mptsas_free_fw_event(ioc, fw_event);
3981 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003982 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003983 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303984 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003985
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003986 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303987 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3988 mptsas_sas_device_pg0(ioc, &sas_device,
3989 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3990 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3991 (hot_plug_info->channel << 8) +
3992 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003993
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303994 if (!sas_device.handle)
3995 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003996
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303997 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3998 if (!phy_info)
3999 break;
4000
4001 if (mptsas_get_rphy(phy_info))
4002 break;
4003
4004 mptsas_add_end_device(ioc, phy_info);
4005 break;
4006
4007 case MPTSAS_DEL_DEVICE:
4008 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4009 hot_plug_info->sas_address);
4010 mptsas_del_end_device(ioc, phy_info);
4011 break;
4012
4013 case MPTSAS_DEL_PHYSDISK:
4014
4015 mpt_findImVolumes(ioc);
4016
4017 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304018 ioc, hot_plug_info->phys_disk_num,
4019 hot_plug_info->channel,
4020 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304021 mptsas_del_end_device(ioc, phy_info);
4022 break;
4023
4024 case MPTSAS_ADD_PHYSDISK_REPROBE:
4025
Christoph Hellwige3094442006-02-16 13:25:36 +01004026 if (mptsas_sas_device_pg0(ioc, &sas_device,
4027 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004028 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304029 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4030 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4031 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4032 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004033 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004034 }
4035
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304036 phy_info = mptsas_find_phyinfo_by_sas_address(
4037 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004038
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304039 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304040 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304041 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4042 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004043 break;
4044 }
4045
4046 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304047 if (!starget) {
4048 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4049 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4050 __func__, hot_plug_info->id, __LINE__));
4051 break;
4052 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004053
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304054 vtarget = starget->hostdata;
4055 if (!vtarget) {
4056 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4057 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4058 __func__, hot_plug_info->id, __LINE__));
4059 break;
4060 }
Eric Moore547f9a22006-06-27 14:42:12 -06004061
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304062 mpt_findImVolumes(ioc);
4063
4064 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4065 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4066 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4067 hot_plug_info->phys_disk_num, (unsigned long long)
4068 sas_device.sas_address);
4069
4070 vtarget->id = hot_plug_info->phys_disk_num;
4071 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4072 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4073 mptsas_reprobe_target(starget, 1);
4074 break;
4075
4076 case MPTSAS_DEL_PHYSDISK_REPROBE:
4077
4078 if (mptsas_sas_device_pg0(ioc, &sas_device,
4079 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4080 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4081 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304082 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304083 "%s: fw_id=%d exit at line=%d\n",
4084 ioc->name, __func__,
4085 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004086 break;
4087 }
4088
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304089 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4090 sas_device.sas_address);
4091 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304092 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304093 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4094 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004095 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004096 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004097
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304098 starget = mptsas_get_starget(phy_info);
4099 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304100 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304101 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4102 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004103 break;
4104 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004105
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304106 vtarget = starget->hostdata;
4107 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304108 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304109 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4110 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004111 break;
4112 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304113
4114 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4115 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4116 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4117 __func__, hot_plug_info->id, __LINE__));
4118 break;
4119 }
4120
4121 mpt_findImVolumes(ioc);
4122
4123 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4124 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4125 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4126 hot_plug_info->phys_disk_num, (unsigned long long)
4127 sas_device.sas_address);
4128
4129 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4130 vtarget->id = hot_plug_info->id;
4131 phy_info->attached.phys_disk_num = ~0;
4132 mptsas_reprobe_target(starget, 0);
4133 mptsas_add_device_component_by_fw(ioc,
4134 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004135 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304136
Moore, Ericc73787ee2006-01-26 16:20:06 -07004137 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304138
Moore, Ericc73787ee2006-01-26 16:20:06 -07004139 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304140 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4141 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4142 hot_plug_info->id);
4143 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4144 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004145 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304146
Moore, Ericc73787ee2006-01-26 16:20:06 -07004147 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304148
Moore, Ericc73787ee2006-01-26 16:20:06 -07004149 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304150 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4151 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4152 hot_plug_info->id);
4153 scsi_remove_device(hot_plug_info->sdev);
4154 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004155 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304156
Eric Mooreb506ade2007-01-29 09:45:37 -07004157 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304158
4159 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004160 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304161 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004162 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304163
Moore, Ericbd23e942006-04-17 12:43:04 -06004164 default:
4165 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004166 }
4167
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304168 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004169}
4170
4171static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304172mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004173{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304174 MPT_ADAPTER *ioc;
4175 struct mptsas_hotplug_event hot_plug_info;
4176 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4177 u32 device_info;
4178 u64 sas_address;
4179
4180 ioc = fw_event->ioc;
4181 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4182 fw_event->event_data;
4183 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004184
4185 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304186 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4187 MPI_SAS_DEVICE_INFO_STP_TARGET |
4188 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4189 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004190 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304191 }
4192
4193 if (sas_event_data->ReasonCode ==
4194 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4195 mptbase_sas_persist_operation(ioc,
4196 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4197 mptsas_free_fw_event(ioc, fw_event);
4198 return;
4199 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004200
Moore, Eric4b766472006-03-14 09:14:12 -07004201 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004202 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004203 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304204 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4205 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4206 hot_plug_info.channel = sas_event_data->Bus;
4207 hot_plug_info.id = sas_event_data->TargetID;
4208 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004209 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304210 sizeof(u64));
4211 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4212 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004213 if (sas_event_data->ReasonCode &
4214 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304215 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004216 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304217 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4218 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004219 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304220
Moore, Eric4b766472006-03-14 09:14:12 -07004221 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304222 mptbase_sas_persist_operation(ioc,
4223 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4224 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004225 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304226
Moore, Eric4b766472006-03-14 09:14:12 -07004227 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304228 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004229 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304230 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004231 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304232 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004233 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004234 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004235}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304236
Moore, Ericc73787ee2006-01-26 16:20:06 -07004237static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304238mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004239{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304240 MPT_ADAPTER *ioc;
4241 EVENT_DATA_RAID *raid_event_data;
4242 struct mptsas_hotplug_event hot_plug_info;
4243 int status;
4244 int state;
4245 struct scsi_device *sdev = NULL;
4246 VirtDevice *vdevice = NULL;
4247 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004248
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304249 ioc = fw_event->ioc;
4250 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4251 status = le32_to_cpu(raid_event_data->SettingsStatus);
4252 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004253
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304254 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4255 hot_plug_info.id = raid_event_data->VolumeID;
4256 hot_plug_info.channel = raid_event_data->VolumeBus;
4257 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4258
4259 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4260 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4261 raid_event_data->ReasonCode ==
4262 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4263 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4264 hot_plug_info.id, 0);
4265 hot_plug_info.sdev = sdev;
4266 if (sdev)
4267 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004268 }
4269
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304270 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4271 "ReasonCode=%02x\n", ioc->name, __func__,
4272 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004273
4274 switch (raid_event_data->ReasonCode) {
4275 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304276 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004277 break;
4278 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304279 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004280 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004281 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4282 switch (state) {
4283 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004284 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304285 mpt_raid_phys_disk_pg0(ioc,
4286 raid_event_data->PhysDiskNum, &phys_disk);
4287 hot_plug_info.id = phys_disk.PhysDiskID;
4288 hot_plug_info.channel = phys_disk.PhysDiskBus;
4289 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004290 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304291 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004292 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004293 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4294 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4295 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304296 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004297 break;
4298 default:
4299 break;
4300 }
4301 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004302 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304303 if (!sdev)
4304 break;
4305 vdevice->vtarget->deleted = 1; /* block IO */
4306 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004307 break;
4308 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304309 if (sdev) {
4310 scsi_device_put(sdev);
4311 break;
4312 }
4313 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004314 break;
4315 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304316 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4317 if (!sdev)
4318 break;
4319 vdevice->vtarget->deleted = 1; /* block IO */
4320 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4321 break;
4322 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004323 switch (state) {
4324 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4325 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304326 if (!sdev)
4327 break;
4328 vdevice->vtarget->deleted = 1; /* block IO */
4329 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004330 break;
4331 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4332 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304333 if (sdev) {
4334 scsi_device_put(sdev);
4335 break;
4336 }
4337 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004338 break;
4339 default:
4340 break;
4341 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004342 break;
4343 default:
4344 break;
4345 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304346
4347 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4348 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4349 else
4350 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004351}
4352
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304353/**
4354 * mptsas_issue_tm - send mptsas internal tm request
4355 * @ioc: Pointer to MPT_ADAPTER structure
4356 * @type: Task Management type
4357 * @channel: channel number for task management
4358 * @id: Logical Target ID for reset (if appropriate)
4359 * @lun: Logical unit for reset (if appropriate)
4360 * @task_context: Context for the task to be aborted
4361 * @timeout: timeout for task management control
4362 *
4363 * return 0 on success and -1 on failure:
4364 *
4365 */
4366static int
4367mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4368 int task_context, ulong timeout, u8 *issue_reset)
4369{
4370 MPT_FRAME_HDR *mf;
4371 SCSITaskMgmt_t *pScsiTm;
4372 int retval;
4373 unsigned long timeleft;
4374
4375 *issue_reset = 0;
4376 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4377 if (mf == NULL) {
4378 retval = -1; /* return failure */
4379 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4380 "msg frames!!\n", ioc->name));
4381 goto out;
4382 }
4383
4384 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4385 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4386 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4387 type, timeout, channel, id, (unsigned long long)lun,
4388 task_context));
4389
4390 pScsiTm = (SCSITaskMgmt_t *) mf;
4391 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4392 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4393 pScsiTm->TaskType = type;
4394 pScsiTm->MsgFlags = 0;
4395 pScsiTm->TargetID = id;
4396 pScsiTm->Bus = channel;
4397 pScsiTm->ChainOffset = 0;
4398 pScsiTm->Reserved = 0;
4399 pScsiTm->Reserved1 = 0;
4400 pScsiTm->TaskMsgContext = task_context;
4401 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4402
4403 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4404 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4405 retval = 0;
4406 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4407
4408 /* Now wait for the command to complete */
4409 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4410 timeout*HZ);
4411 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4412 retval = -1; /* return failure */
4413 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4414 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4415 mpt_free_msg_frame(ioc, mf);
4416 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4417 goto out;
4418 *issue_reset = 1;
4419 goto out;
4420 }
4421
4422 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4423 retval = -1; /* return failure */
4424 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4425 "TaskMgmt request: failed with no reply\n", ioc->name));
4426 goto out;
4427 }
4428
4429 out:
4430 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4431 return retval;
4432}
4433
4434/**
4435 * mptsas_broadcast_primative_work - Handle broadcast primitives
4436 * @work: work queue payload containing info describing the event
4437 *
4438 * this will be handled in workqueue context.
4439 */
4440static void
4441mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4442{
4443 MPT_ADAPTER *ioc = fw_event->ioc;
4444 MPT_FRAME_HDR *mf;
4445 VirtDevice *vdevice;
4446 int ii;
4447 struct scsi_cmnd *sc;
4448 SCSITaskMgmtReply_t *pScsiTmReply;
4449 u8 issue_reset;
4450 int task_context;
4451 u8 channel, id;
4452 int lun;
4453 u32 termination_count;
4454 u32 query_count;
4455
4456 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4457 "%s - enter\n", ioc->name, __func__));
4458
4459 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4460 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4461 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4462 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4463 return;
4464 }
4465
4466 issue_reset = 0;
4467 termination_count = 0;
4468 query_count = 0;
4469 mpt_findImVolumes(ioc);
4470 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4471
4472 for (ii = 0; ii < ioc->req_depth; ii++) {
4473 if (ioc->fw_events_off)
4474 goto out;
4475 sc = mptscsih_get_scsi_lookup(ioc, ii);
4476 if (!sc)
4477 continue;
4478 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4479 if (!mf)
4480 continue;
4481 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4482 vdevice = sc->device->hostdata;
4483 if (!vdevice || !vdevice->vtarget)
4484 continue;
4485 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4486 continue; /* skip hidden raid components */
4487 if (vdevice->vtarget->raidVolume)
4488 continue; /* skip hidden raid components */
4489 channel = vdevice->vtarget->channel;
4490 id = vdevice->vtarget->id;
4491 lun = vdevice->lun;
4492 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4493 channel, id, (u64)lun, task_context, 30, &issue_reset))
4494 goto out;
4495 query_count++;
4496 termination_count +=
4497 le32_to_cpu(pScsiTmReply->TerminationCount);
4498 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4499 (pScsiTmReply->ResponseCode ==
4500 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4501 pScsiTmReply->ResponseCode ==
4502 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4503 continue;
4504 if (mptsas_issue_tm(ioc,
4505 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4506 channel, id, (u64)lun, 0, 30, &issue_reset))
4507 goto out;
4508 termination_count +=
4509 le32_to_cpu(pScsiTmReply->TerminationCount);
4510 }
4511
4512 out:
4513 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4514 "%s - exit, query_count = %d termination_count = %d\n",
4515 ioc->name, __func__, query_count, termination_count));
4516
4517 ioc->broadcast_aen_busy = 0;
4518 mpt_clear_taskmgmt_in_progress_flag(ioc);
4519 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4520
4521 if (issue_reset) {
4522 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4523 ioc->name, __func__);
4524 mpt_HardResetHandler(ioc, CAN_SLEEP);
4525 }
4526 mptsas_free_fw_event(ioc, fw_event);
4527}
4528
Eric Mooreb506ade2007-01-29 09:45:37 -07004529/*
4530 * mptsas_send_ir2_event - handle exposing hidden disk when
4531 * an inactive raid volume is added
4532 *
4533 * @ioc: Pointer to MPT_ADAPTER structure
4534 * @ir2_data
4535 *
4536 */
4537static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304538mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004539{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304540 MPT_ADAPTER *ioc;
4541 struct mptsas_hotplug_event hot_plug_info;
4542 MPI_EVENT_DATA_IR2 *ir2_data;
4543 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304544 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004545
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304546 ioc = fw_event->ioc;
4547 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4548 reasonCode = ir2_data->ReasonCode;
4549
4550 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4551 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4552
4553 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4554 hot_plug_info.id = ir2_data->TargetID;
4555 hot_plug_info.channel = ir2_data->Bus;
4556 switch (reasonCode) {
4557 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4558 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4559 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304560 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4561 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4562 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4563 break;
4564 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4565 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4566 mpt_raid_phys_disk_pg0(ioc,
4567 ir2_data->PhysDiskNum, &phys_disk);
4568 hot_plug_info.id = phys_disk.PhysDiskID;
4569 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4570 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304571 default:
4572 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004573 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304574 }
4575 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4576}
Moore, Erice6b2d762006-03-14 09:14:24 -07004577
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004578static int
4579mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4580{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304581 u32 event = le32_to_cpu(reply->Event);
4582 int sz, event_data_sz;
4583 struct fw_event_work *fw_event;
4584 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004585
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304586 /* events turned off due to host reset or driver unloading */
4587 if (ioc->fw_events_off)
4588 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004589
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304590 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004591 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304592 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4593 {
4594 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4595 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4596 if (broadcast_event_data->Primitive !=
4597 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4598 return 0;
4599 if (ioc->broadcast_aen_busy)
4600 return 0;
4601 ioc->broadcast_aen_busy = 1;
4602 break;
4603 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004604 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304605 {
4606 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4607 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4608
4609 if (sas_event_data->ReasonCode ==
4610 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4611 mptsas_target_reset_queue(ioc, sas_event_data);
4612 return 0;
4613 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004614 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304615 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304616 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4617 {
4618 MpiEventDataSasExpanderStatusChange_t *expander_data =
4619 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4620
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304621 if (ioc->old_sas_discovery_protocal)
4622 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304623
4624 if (expander_data->ReasonCode ==
4625 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4626 ioc->device_missing_delay)
4627 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004628 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304629 }
4630 case MPI_EVENT_SAS_DISCOVERY:
4631 {
4632 u32 discovery_status;
4633 EventDataSasDiscovery_t *discovery_data =
4634 (EventDataSasDiscovery_t *)reply->Data;
4635
4636 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4637 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304638 if (ioc->old_sas_discovery_protocal && !discovery_status)
4639 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304640 return 0;
4641 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304642 case MPI_EVENT_INTEGRATED_RAID:
4643 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004644 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304645 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4646 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004647 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004648 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304649 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004650 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004651
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304652 event_data_sz = ((reply->MsgLength * 4) -
4653 offsetof(EventNotificationReply_t, Data));
4654 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4655 fw_event = kzalloc(sz, GFP_ATOMIC);
4656 if (!fw_event) {
4657 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4658 __func__, __LINE__);
4659 return 0;
4660 }
4661 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4662 fw_event->event = event;
4663 fw_event->ioc = ioc;
4664 mptsas_add_fw_event(ioc, fw_event, delay);
4665 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004666}
4667
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304668/* Delete a volume when no longer listed in ioc pg2
4669 */
4670static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4671{
4672 struct scsi_device *sdev;
4673 int i;
4674
4675 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4676 if (!sdev)
4677 return;
4678 if (!ioc->raid_data.pIocPg2)
4679 goto out;
4680 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4681 goto out;
4682 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4683 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4684 goto release_sdev;
4685 out:
4686 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4687 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4688 scsi_remove_device(sdev);
4689 release_sdev:
4690 scsi_device_put(sdev);
4691}
4692
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004693static int
4694mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4695{
4696 struct Scsi_Host *sh;
4697 MPT_SCSI_HOST *hd;
4698 MPT_ADAPTER *ioc;
4699 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004700 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004701 int numSGE = 0;
4702 int scale;
4703 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004704 int error=0;
4705 int r;
4706
4707 r = mpt_attach(pdev,id);
4708 if (r)
4709 return r;
4710
4711 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304712 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004713 ioc->DoneCtx = mptsasDoneCtx;
4714 ioc->TaskCtx = mptsasTaskCtx;
4715 ioc->InternalCtx = mptsasInternalCtx;
4716
4717 /* Added sanity check on readiness of the MPT adapter.
4718 */
4719 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4720 printk(MYIOC_s_WARN_FMT
4721 "Skipping because it's not operational!\n",
4722 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004723 error = -ENODEV;
4724 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004725 }
4726
4727 if (!ioc->active) {
4728 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4729 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004730 error = -ENODEV;
4731 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004732 }
4733
4734 /* Sanity check - ensure at least 1 port is INITIATOR capable
4735 */
4736 ioc_cap = 0;
4737 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4738 if (ioc->pfacts[ii].ProtocolFlags &
4739 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4740 ioc_cap++;
4741 }
4742
4743 if (!ioc_cap) {
4744 printk(MYIOC_s_WARN_FMT
4745 "Skipping ioc=%p because SCSI Initiator mode "
4746 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004747 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004748 }
4749
4750 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4751 if (!sh) {
4752 printk(MYIOC_s_WARN_FMT
4753 "Unable to register controller with SCSI subsystem\n",
4754 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004755 error = -1;
4756 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004757 }
4758
4759 spin_lock_irqsave(&ioc->FreeQlock, flags);
4760
4761 /* Attach the SCSI Host to the IOC structure
4762 */
4763 ioc->sh = sh;
4764
4765 sh->io_port = 0;
4766 sh->n_io_port = 0;
4767 sh->irq = 0;
4768
4769 /* set 16 byte cdb's */
4770 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05304771 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
4772 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07004773 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004774 sh->transportt = mptsas_transport_template;
4775
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004776 /* Required entry.
4777 */
4778 sh->unique_id = ioc->id;
4779
4780 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004781 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004782 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004783 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004784 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004785
4786 /* Verify that we won't exceed the maximum
4787 * number of chain buffers
4788 * We can optimize: ZZ = req_sz/sizeof(SGE)
4789 * For 32bit SGE's:
4790 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4791 * + (req_sz - 64)/sizeof(SGE)
4792 * A slightly different algorithm is required for
4793 * 64bit SGEs.
4794 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304795 scale = ioc->req_sz/ioc->SGE_size;
4796 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004797 numSGE = (scale - 1) *
4798 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304799 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004800 } else {
4801 numSGE = 1 + (scale - 1) *
4802 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304803 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004804 }
4805
4806 if (numSGE < sh->sg_tablesize) {
4807 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304808 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004809 "Resetting sg_tablesize to %d from %d\n",
4810 ioc->name, numSGE, sh->sg_tablesize));
4811 sh->sg_tablesize = numSGE;
4812 }
4813
Eric Mooree7eae9f2007-09-29 10:15:59 -06004814 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004815 hd->ioc = ioc;
4816
4817 /* SCSI needs scsi_cmnd lookup table!
4818 * (with size equal to req_depth*PtrSz!)
4819 */
Eric Mooree8206382007-09-29 10:16:53 -06004820 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4821 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004822 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004823 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004824 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004825 }
Eric Mooree8206382007-09-29 10:16:53 -06004826 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004827
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304828 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004829 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004830
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004831 ioc->sas_data.ptClear = mpt_pt_clear;
4832
Eric Mooredf9e0622007-01-29 09:46:21 -07004833 hd->last_queue_full = 0;
4834 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304835 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4836 mutex_init(&ioc->sas_device_info_mutex);
4837
Eric Mooredf9e0622007-01-29 09:46:21 -07004838 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4839
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004840 if (ioc->sas_data.ptClear==1) {
4841 mptbase_sas_persist_operation(
4842 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4843 }
4844
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004845 error = scsi_add_host(sh, &ioc->pcidev->dev);
4846 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004847 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4848 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004849 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004850 }
4851
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304852 /* older firmware doesn't support expander events */
4853 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4854 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004855 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304856 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004857 return 0;
4858
Eric Moore547f9a22006-06-27 14:42:12 -06004859 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004860
4861 mptscsih_remove(pdev);
4862 return error;
4863}
4864
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304865void
4866mptsas_shutdown(struct pci_dev *pdev)
4867{
4868 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4869
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304870 mptsas_fw_event_off(ioc);
4871 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304872}
4873
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004874static void __devexit mptsas_remove(struct pci_dev *pdev)
4875{
4876 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4877 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004878 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004879
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304880 mptsas_shutdown(pdev);
4881
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304882 mptsas_del_device_components(ioc);
4883
Eric Mooreb506ade2007-01-29 09:45:37 -07004884 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004885 sas_remove_host(ioc->sh);
4886
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004887 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004888 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4889 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004890 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304891 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304892
Eric Moore547f9a22006-06-27 14:42:12 -06004893 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004894 kfree(p);
4895 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004896 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304897 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004898 mptscsih_remove(pdev);
4899}
4900
4901static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004902 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004903 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004904 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004905 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004906 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004907 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004908 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004909 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004910 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004911 PCI_ANY_ID, PCI_ANY_ID },
4912 {0} /* Terminating entry */
4913};
4914MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4915
4916
4917static struct pci_driver mptsas_driver = {
4918 .name = "mptsas",
4919 .id_table = mptsas_pci_table,
4920 .probe = mptsas_probe,
4921 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304922 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004923#ifdef CONFIG_PM
4924 .suspend = mptscsih_suspend,
4925 .resume = mptscsih_resume,
4926#endif
4927};
4928
4929static int __init
4930mptsas_init(void)
4931{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304932 int error;
4933
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004934 show_mptmod_ver(my_NAME, my_VERSION);
4935
4936 mptsas_transport_template =
4937 sas_attach_transport(&mptsas_transport_functions);
4938 if (!mptsas_transport_template)
4939 return -ENODEV;
4940
4941 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304942 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004943 mptsasInternalCtx =
4944 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004945 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304946 mptsasDeviceResetCtx =
4947 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004948
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304949 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4950 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004951
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304952 error = pci_register_driver(&mptsas_driver);
4953 if (error)
4954 sas_release_transport(mptsas_transport_template);
4955
4956 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004957}
4958
4959static void __exit
4960mptsas_exit(void)
4961{
4962 pci_unregister_driver(&mptsas_driver);
4963 sas_release_transport(mptsas_transport_template);
4964
4965 mpt_reset_deregister(mptsasDoneCtx);
4966 mpt_event_deregister(mptsasDoneCtx);
4967
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004968 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004969 mpt_deregister(mptsasInternalCtx);
4970 mpt_deregister(mptsasTaskCtx);
4971 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304972 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004973}
4974
4975module_init(mptsas_init);
4976module_exit(mptsas_exit);