blob: 88a1a6d3bc045d61a8170132a1c74569b0b367c7 [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
Christoph Hellwig0c33b272005-09-09 16:27:19 +020075MODULE_AUTHOR(MODULEAUTHOR);
76MODULE_DESCRIPTION(my_NAME);
77MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070078MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020079
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080static int mpt_pt_clear;
81module_param(mpt_pt_clear, int, 0);
82MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060083 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020084 "(default=MPTSCSIH_PT_CLEAR=0)");
85
Eric Moore793955f2007-01-29 09:42:20 -070086/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
87#define MPTSAS_MAX_LUN (16895)
88static int max_lun = MPTSAS_MAX_LUN;
89module_param(max_lun, int, 0);
90MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
91
Prakash, Sathyaf606f572007-08-14 16:12:53 +053092static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
93static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
95static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053096static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020097
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +053098static void mptsas_firmware_event_work(struct work_struct *work);
99static void mptsas_send_sas_event(struct fw_event_work *fw_event);
100static void mptsas_send_raid_event(struct fw_event_work *fw_event);
101static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
102static void mptsas_parse_device_info(struct sas_identify *identify,
103 struct mptsas_devinfo *device_info);
104static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
105 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
106static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
107 (MPT_ADAPTER *ioc, u64 sas_address);
108static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
109 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
110static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
112static int mptsas_add_end_device(MPT_ADAPTER *ioc,
113 struct mptsas_phyinfo *phy_info);
114static void mptsas_del_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530116static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
117static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
118 (MPT_ADAPTER *ioc, u64 sas_address);
119static void mptsas_expander_delete(MPT_ADAPTER *ioc,
120 struct mptsas_portinfo *port_info, u8 force);
121static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530122static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
123static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530124static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530125static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530126static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200127
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530128static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
129 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200130{
Eric Moore29dd3602007-09-14 18:46:51 -0600131 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
132 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
133 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
134 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
136 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
138 ioc->name, phy_data->Port));
139 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
140 ioc->name, phy_data->PortFlags));
141 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
142 ioc->name, phy_data->PhyFlags));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
144 ioc->name, phy_data->NegotiatedLinkRate));
145 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
146 "Controller PHY Device Info=0x%X\n", ioc->name,
147 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
148 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
149 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200150}
151
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530152static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200153{
154 __le64 sas_address;
155
156 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
157
Eric Moore29dd3602007-09-14 18:46:51 -0600158 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
159 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
160 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
161 "Attached Device Handle=0x%X\n", ioc->name,
162 le16_to_cpu(pg0->AttachedDevHandle)));
163 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
164 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
165 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
166 "Attached PHY Identifier=0x%X\n", ioc->name,
167 pg0->AttachedPhyIdentifier));
168 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
169 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
170 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
171 ioc->name, pg0->ProgrammedLinkRate));
172 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
173 ioc->name, pg0->ChangeCount));
174 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
175 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200176}
177
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530178static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200179{
Eric Moore29dd3602007-09-14 18:46:51 -0600180 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
181 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
182 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
183 ioc->name, pg1->InvalidDwordCount));
184 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
185 "Running Disparity Error Count=0x%x\n", ioc->name,
186 pg1->RunningDisparityErrorCount));
187 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
188 "Loss Dword Synch Count=0x%x\n", ioc->name,
189 pg1->LossDwordSynchCount));
190 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
191 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
192 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200193}
194
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530195static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200196{
197 __le64 sas_address;
198
199 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
200
Eric Moore29dd3602007-09-14 18:46:51 -0600201 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
202 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
203 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
204 ioc->name, le16_to_cpu(pg0->DevHandle)));
205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
206 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
208 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
210 ioc->name, le16_to_cpu(pg0->Slot)));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
212 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
214 ioc->name, pg0->TargetID));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
216 ioc->name, pg0->Bus));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
218 ioc->name, pg0->PhyNum));
219 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
220 ioc->name, le16_to_cpu(pg0->AccessStatus)));
221 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
222 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
223 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
224 ioc->name, le16_to_cpu(pg0->Flags)));
225 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
226 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200227}
228
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530229static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200230{
Eric Moore29dd3602007-09-14 18:46:51 -0600231 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
232 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
233 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
234 ioc->name, pg1->PhysicalPort));
235 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
236 ioc->name, pg1->PhyIdentifier));
237 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
238 ioc->name, pg1->NegotiatedLinkRate));
239 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
240 ioc->name, pg1->ProgrammedLinkRate));
241 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
242 ioc->name, pg1->HwLinkRate));
243 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
244 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
245 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
246 "Attached Device Handle=0x%X\n\n", ioc->name,
247 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200248}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200249
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530250/* inhibit sas firmware event handling */
251static void
252mptsas_fw_event_off(MPT_ADAPTER *ioc)
253{
254 unsigned long flags;
255
256 spin_lock_irqsave(&ioc->fw_event_lock, flags);
257 ioc->fw_events_off = 1;
258 ioc->sas_discovery_quiesce_io = 0;
259 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
260
261}
262
263/* enable sas firmware event handling */
264static void
265mptsas_fw_event_on(MPT_ADAPTER *ioc)
266{
267 unsigned long flags;
268
269 spin_lock_irqsave(&ioc->fw_event_lock, flags);
270 ioc->fw_events_off = 0;
271 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
272}
273
274/* queue a sas firmware event */
275static void
276mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
277 unsigned long delay)
278{
279 unsigned long flags;
280
281 spin_lock_irqsave(&ioc->fw_event_lock, flags);
282 list_add_tail(&fw_event->list, &ioc->fw_event_list);
283 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
284 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
285 ioc->name, __func__, fw_event));
286 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
287 delay);
288 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
289}
290
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530291/* requeue a sas firmware event */
292static void
293mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
294 unsigned long delay)
295{
296 unsigned long flags;
297 spin_lock_irqsave(&ioc->fw_event_lock, flags);
298 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
299 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
300 fw_event->retries++;
301 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
302 msecs_to_jiffies(delay));
303 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
304}
305
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530306/* free memory assoicated to a sas firmware event */
307static void
308mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
309{
310 unsigned long flags;
311
312 spin_lock_irqsave(&ioc->fw_event_lock, flags);
313 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
314 ioc->name, __func__, fw_event));
315 list_del(&fw_event->list);
316 kfree(fw_event);
317 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
318}
319
320/* walk the firmware event queue, and either stop or wait for
321 * outstanding events to complete */
322static void
323mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
324{
325 struct fw_event_work *fw_event, *next;
326 struct mptsas_target_reset_event *target_reset_list, *n;
327 u8 flush_q;
328 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
329
330 /* flush the target_reset_list */
331 if (!list_empty(&hd->target_reset_list)) {
332 list_for_each_entry_safe(target_reset_list, n,
333 &hd->target_reset_list, list) {
334 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
335 "%s: removing target reset for id=%d\n",
336 ioc->name, __func__,
337 target_reset_list->sas_event_data.TargetID));
338 list_del(&target_reset_list->list);
339 kfree(target_reset_list);
340 }
341 }
342
343 if (list_empty(&ioc->fw_event_list) ||
344 !ioc->fw_event_q || in_interrupt())
345 return;
346
347 flush_q = 0;
348 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
349 if (cancel_delayed_work(&fw_event->work))
350 mptsas_free_fw_event(ioc, fw_event);
351 else
352 flush_q = 1;
353 }
354 if (flush_q)
355 flush_workqueue(ioc->fw_event_q);
356}
357
358
Christoph Hellwige3094442006-02-16 13:25:36 +0100359static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
360{
361 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
362 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
363}
364
365static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
366{
367 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
368 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
369}
370
Moore, Erice6b2d762006-03-14 09:14:24 -0700371/*
372 * mptsas_find_portinfo_by_handle
373 *
374 * This function should be called with the sas_topology_mutex already held
375 */
376static struct mptsas_portinfo *
377mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
378{
379 struct mptsas_portinfo *port_info, *rc=NULL;
380 int i;
381
382 list_for_each_entry(port_info, &ioc->sas_topology, list)
383 for (i = 0; i < port_info->num_phys; i++)
384 if (port_info->phy_info[i].identify.handle == handle) {
385 rc = port_info;
386 goto out;
387 }
388 out:
389 return rc;
390}
391
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530392/**
393 * mptsas_find_portinfo_by_sas_address -
394 * @ioc: Pointer to MPT_ADAPTER structure
395 * @handle:
396 *
397 * This function should be called with the sas_topology_mutex already held
398 *
399 **/
400static struct mptsas_portinfo *
401mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
402{
403 struct mptsas_portinfo *port_info, *rc = NULL;
404 int i;
405
406 if (sas_address >= ioc->hba_port_sas_addr &&
407 sas_address < (ioc->hba_port_sas_addr +
408 ioc->hba_port_num_phy))
409 return ioc->hba_port_info;
410
411 mutex_lock(&ioc->sas_topology_mutex);
412 list_for_each_entry(port_info, &ioc->sas_topology, list)
413 for (i = 0; i < port_info->num_phys; i++)
414 if (port_info->phy_info[i].identify.sas_address ==
415 sas_address) {
416 rc = port_info;
417 goto out;
418 }
419 out:
420 mutex_unlock(&ioc->sas_topology_mutex);
421 return rc;
422}
423
Moore, Ericbd23e942006-04-17 12:43:04 -0600424/*
425 * Returns true if there is a scsi end device
426 */
427static inline int
428mptsas_is_end_device(struct mptsas_devinfo * attached)
429{
Eric Moore547f9a22006-06-27 14:42:12 -0600430 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600431 (attached->device_info &
432 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
433 ((attached->device_info &
434 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
435 (attached->device_info &
436 MPI_SAS_DEVICE_INFO_STP_TARGET) |
437 (attached->device_info &
438 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
439 return 1;
440 else
441 return 0;
442}
443
Eric Moore547f9a22006-06-27 14:42:12 -0600444/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600445static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530446mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600447{
448 struct mptsas_portinfo *port_info;
449 struct mptsas_phyinfo *phy_info;
450 u8 i;
451
452 if (!port_details)
453 return;
454
455 port_info = port_details->port_info;
456 phy_info = port_info->phy_info;
457
Eric Moore29dd3602007-09-14 18:46:51 -0600458 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700459 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700460 port_details->num_phys, (unsigned long long)
461 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600462
463 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
464 if(phy_info->port_details != port_details)
465 continue;
466 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530467 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600468 phy_info->port_details = NULL;
469 }
470 kfree(port_details);
471}
472
473static inline struct sas_rphy *
474mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
475{
476 if (phy_info->port_details)
477 return phy_info->port_details->rphy;
478 else
479 return NULL;
480}
481
482static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530483mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600484{
485 if (phy_info->port_details) {
486 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600487 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
488 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600489 }
490
Eric Moore547f9a22006-06-27 14:42:12 -0600491 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600492 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
493 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600494 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
495 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600496 }
Eric Moore547f9a22006-06-27 14:42:12 -0600497}
498
499static inline struct sas_port *
500mptsas_get_port(struct mptsas_phyinfo *phy_info)
501{
502 if (phy_info->port_details)
503 return phy_info->port_details->port;
504 else
505 return NULL;
506}
507
508static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530509mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600510{
511 if (phy_info->port_details)
512 phy_info->port_details->port = port;
513
Eric Moore547f9a22006-06-27 14:42:12 -0600514 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600515 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
516 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600517 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
518 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600519 }
Eric Moore547f9a22006-06-27 14:42:12 -0600520}
521
522static inline struct scsi_target *
523mptsas_get_starget(struct mptsas_phyinfo *phy_info)
524{
525 if (phy_info->port_details)
526 return phy_info->port_details->starget;
527 else
528 return NULL;
529}
530
531static inline void
532mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
533starget)
534{
535 if (phy_info->port_details)
536 phy_info->port_details->starget = starget;
537}
538
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530539/**
540 * mptsas_add_device_component -
541 * @ioc: Pointer to MPT_ADAPTER structure
542 * @channel: fw mapped id's
543 * @id:
544 * @sas_address:
545 * @device_info:
546 *
547 **/
548static void
549mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
550 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
551{
552 struct mptsas_device_info *sas_info, *next;
553 struct scsi_device *sdev;
554 struct scsi_target *starget;
555 struct sas_rphy *rphy;
556
557 /*
558 * Delete all matching devices out of the list
559 */
560 mutex_lock(&ioc->sas_device_info_mutex);
561 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
562 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530563 if (!sas_info->is_logical_volume &&
564 (sas_info->sas_address == sas_address ||
565 (sas_info->fw.channel == channel &&
566 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530567 list_del(&sas_info->list);
568 kfree(sas_info);
569 }
570 }
571
572 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
573 if (!sas_info)
574 goto out;
575
576 /*
577 * Set Firmware mapping
578 */
579 sas_info->fw.id = id;
580 sas_info->fw.channel = channel;
581
582 sas_info->sas_address = sas_address;
583 sas_info->device_info = device_info;
584 sas_info->slot = slot;
585 sas_info->enclosure_logical_id = enclosure_logical_id;
586 INIT_LIST_HEAD(&sas_info->list);
587 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
588
589 /*
590 * Set OS mapping
591 */
592 shost_for_each_device(sdev, ioc->sh) {
593 starget = scsi_target(sdev);
594 rphy = dev_to_rphy(starget->dev.parent);
595 if (rphy->identify.sas_address == sas_address) {
596 sas_info->os.id = starget->id;
597 sas_info->os.channel = starget->channel;
598 }
599 }
600
601 out:
602 mutex_unlock(&ioc->sas_device_info_mutex);
603 return;
604}
605
606/**
607 * mptsas_add_device_component_by_fw -
608 * @ioc: Pointer to MPT_ADAPTER structure
609 * @channel: fw mapped id's
610 * @id:
611 *
612 **/
613static void
614mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
615{
616 struct mptsas_devinfo sas_device;
617 struct mptsas_enclosure enclosure_info;
618 int rc;
619
620 rc = mptsas_sas_device_pg0(ioc, &sas_device,
621 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
622 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
623 (channel << 8) + id);
624 if (rc)
625 return;
626
627 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
628 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
629 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
630 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
631 sas_device.handle_enclosure);
632
633 mptsas_add_device_component(ioc, sas_device.channel,
634 sas_device.id, sas_device.sas_address, sas_device.device_info,
635 sas_device.slot, enclosure_info.enclosure_logical_id);
636}
637
638/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530639 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
640 * each individual device to list
641 * @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;
665 cfg.timeout = 10;
666
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/**
Kashyap, Desai57e98512009-05-29 16:55:09 +0530779 * mptsas_del_device_component_by_os - Once a device has been removed, we
780 * mark the entry in the list as being cached
781 * @ioc: Pointer to MPT_ADAPTER structure
782 * @channel: os mapped id's
783 * @id:
784 *
785 **/
786static void
787mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
788{
789 struct mptsas_device_info *sas_info, *next;
790
791 /*
792 * Set is_cached flag
793 */
794 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
795 list) {
796 if (sas_info->os.channel == channel && sas_info->os.id == id)
797 sas_info->is_cached = 1;
798 }
799}
800
801/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530802 * mptsas_del_device_components - Cleaning the list
803 * @ioc: Pointer to MPT_ADAPTER structure
804 *
805 **/
806static void
807mptsas_del_device_components(MPT_ADAPTER *ioc)
808{
809 struct mptsas_device_info *sas_info, *next;
810
811 mutex_lock(&ioc->sas_device_info_mutex);
812 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
813 list) {
814 list_del(&sas_info->list);
815 kfree(sas_info);
816 }
817 mutex_unlock(&ioc->sas_device_info_mutex);
818}
819
Eric Moore547f9a22006-06-27 14:42:12 -0600820
821/*
822 * mptsas_setup_wide_ports
823 *
824 * Updates for new and existing narrow/wide port configuration
825 * in the sas_topology
826 */
Eric Moore376ac832006-06-29 17:36:26 -0600827static void
Eric Moore547f9a22006-06-27 14:42:12 -0600828mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
829{
830 struct mptsas_portinfo_details * port_details;
831 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
832 u64 sas_address;
833 int i, j;
834
835 mutex_lock(&ioc->sas_topology_mutex);
836
837 phy_info = port_info->phy_info;
838 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
839 if (phy_info->attached.handle)
840 continue;
841 port_details = phy_info->port_details;
842 if (!port_details)
843 continue;
844 if (port_details->num_phys < 2)
845 continue;
846 /*
847 * Removing a phy from a port, letting the last
848 * phy be removed by firmware events.
849 */
Eric Moore29dd3602007-09-14 18:46:51 -0600850 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
851 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700852 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600853 port_details->num_phys--;
854 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
855 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
856 sas_port_delete_phy(port_details->port, phy_info->phy);
857 phy_info->port_details = NULL;
858 }
859
860 /*
861 * Populate and refresh the tree
862 */
863 phy_info = port_info->phy_info;
864 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
865 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600866 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
867 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600868 if (!sas_address)
869 continue;
870 port_details = phy_info->port_details;
871 /*
872 * Forming a port
873 */
874 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530875 port_details = kzalloc(sizeof(struct
876 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600877 if (!port_details)
878 goto out;
879 port_details->num_phys = 1;
880 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600881 if (phy_info->phy_id < 64 )
882 port_details->phy_bitmask |=
883 (1 << phy_info->phy_id);
884 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600885 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700886 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600887 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600888 phy_info->port_details = port_details;
889 }
890
891 if (i == port_info->num_phys - 1)
892 continue;
893 phy_info_cmp = &port_info->phy_info[i + 1];
894 for (j = i + 1 ; j < port_info->num_phys ; j++,
895 phy_info_cmp++) {
896 if (!phy_info_cmp->attached.sas_address)
897 continue;
898 if (sas_address != phy_info_cmp->attached.sas_address)
899 continue;
900 if (phy_info_cmp->port_details == port_details )
901 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600902 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700903 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600904 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700905 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600906 if (phy_info_cmp->port_details) {
907 port_details->rphy =
908 mptsas_get_rphy(phy_info_cmp);
909 port_details->port =
910 mptsas_get_port(phy_info_cmp);
911 port_details->starget =
912 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600913 port_details->num_phys =
914 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600915 if (!phy_info_cmp->port_details->num_phys)
916 kfree(phy_info_cmp->port_details);
917 } else
918 phy_info_cmp->sas_port_add_phy=1;
919 /*
920 * Adding a phy to a port
921 */
922 phy_info_cmp->port_details = port_details;
923 if (phy_info_cmp->phy_id < 64 )
924 port_details->phy_bitmask |=
925 (1 << phy_info_cmp->phy_id);
926 port_details->num_phys++;
927 }
928 }
929
930 out:
931
Eric Moore547f9a22006-06-27 14:42:12 -0600932 for (i = 0; i < port_info->num_phys; i++) {
933 port_details = port_info->phy_info[i].port_details;
934 if (!port_details)
935 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600936 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700937 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700938 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700939 port_details, i, port_details->num_phys,
940 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600941 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
942 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600943 }
Eric Moore29dd3602007-09-14 18:46:51 -0600944 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600945 mutex_unlock(&ioc->sas_topology_mutex);
946}
947
Eric Mooredf9e0622007-01-29 09:46:21 -0700948/**
949 * csmisas_find_vtarget
950 *
951 * @ioc
952 * @volume_id
953 * @volume_bus
954 *
955 **/
956static VirtTarget *
957mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600958{
Eric Mooredf9e0622007-01-29 09:46:21 -0700959 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600960 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700961 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600962
Eric Mooredf9e0622007-01-29 09:46:21 -0700963 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530964 vdevice = sdev->hostdata;
965 if ((vdevice == NULL) ||
966 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700967 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530968 if ((vdevice->vtarget->tflags &
969 MPT_TARGET_FLAGS_RAID_COMPONENT ||
970 vdevice->vtarget->raidVolume))
971 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600972 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530973 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600974 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600975 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700976 return vtarget;
977}
978
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530979static void
980mptsas_queue_device_delete(MPT_ADAPTER *ioc,
981 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
982{
983 struct fw_event_work *fw_event;
984 int sz;
985
986 sz = offsetof(struct fw_event_work, event_data) +
987 sizeof(MpiEventDataSasDeviceStatusChange_t);
988 fw_event = kzalloc(sz, GFP_ATOMIC);
989 if (!fw_event) {
990 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
991 ioc->name, __func__, __LINE__);
992 return;
993 }
994 memcpy(fw_event->event_data, sas_event_data,
995 sizeof(MpiEventDataSasDeviceStatusChange_t));
996 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
997 fw_event->ioc = ioc;
998 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
999}
1000
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301001static void
1002mptsas_queue_rescan(MPT_ADAPTER *ioc)
1003{
1004 struct fw_event_work *fw_event;
1005 int sz;
1006
1007 sz = offsetof(struct fw_event_work, event_data);
1008 fw_event = kzalloc(sz, GFP_ATOMIC);
1009 if (!fw_event) {
1010 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1011 ioc->name, __func__, __LINE__);
1012 return;
1013 }
1014 fw_event->event = -1;
1015 fw_event->ioc = ioc;
1016 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1017}
1018
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301019
Eric Mooredf9e0622007-01-29 09:46:21 -07001020/**
1021 * mptsas_target_reset
1022 *
1023 * Issues TARGET_RESET to end device using handshaking method
1024 *
1025 * @ioc
1026 * @channel
1027 * @id
1028 *
1029 * Returns (1) success
1030 * (0) failure
1031 *
1032 **/
1033static int
1034mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1035{
1036 MPT_FRAME_HDR *mf;
1037 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301038 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1039 return 0;
1040
Eric Mooredf9e0622007-01-29 09:46:21 -07001041
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301042 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1043 if (mf == NULL) {
1044 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301045 "%s, no msg frames @%d!!\n", ioc->name,
1046 __func__, __LINE__));
1047 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001048 }
1049
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301050 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1051 ioc->name, mf));
1052
Eric Mooredf9e0622007-01-29 09:46:21 -07001053 /* Format the Request
1054 */
1055 pScsiTm = (SCSITaskMgmt_t *) mf;
1056 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1057 pScsiTm->TargetID = id;
1058 pScsiTm->Bus = channel;
1059 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1060 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1061 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1062
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301063 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001064
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301065 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1066 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1067 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1068
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301069 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001070
1071 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301072
1073 out_fail:
1074
1075 mpt_clear_taskmgmt_in_progress_flag(ioc);
1076 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001077}
1078
1079/**
1080 * mptsas_target_reset_queue
1081 *
1082 * Receive request for TARGET_RESET after recieving an firmware
1083 * event NOT_RESPONDING_EVENT, then put command in link list
1084 * and queue if task_queue already in use.
1085 *
1086 * @ioc
1087 * @sas_event_data
1088 *
1089 **/
1090static void
1091mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1092 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1093{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001094 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001095 VirtTarget *vtarget = NULL;
1096 struct mptsas_target_reset_event *target_reset_list;
1097 u8 id, channel;
1098
1099 id = sas_event_data->TargetID;
1100 channel = sas_event_data->Bus;
1101
1102 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
1103 return;
1104
1105 vtarget->deleted = 1; /* block IO */
1106
Kashyap, Desai2f187862009-05-29 16:52:37 +05301107 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001108 GFP_ATOMIC);
1109 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301110 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1111 "%s, failed to allocate mem @%d..!!\n",
1112 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001113 return;
1114 }
1115
1116 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1117 sizeof(*sas_event_data));
1118 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1119
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301120 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001121
1122 if (mptsas_target_reset(ioc, channel, id)) {
1123 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001124 }
1125}
1126
1127/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301128 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
1129 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
1130 * from upper layers. then send next TARGET_RESET in the queue.
1131 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001132 *
1133 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301134static int
1135mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001136{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001137 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001138 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001139 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301140 struct mptsas_target_reset_event *target_reset_list;
1141 SCSITaskMgmtReply_t *pScsiTmReply;
1142
1143 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1144 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1145
1146 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1147 if (pScsiTmReply) {
1148 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1149 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1150 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1151 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1152 "term_cmnds = %d\n", ioc->name,
1153 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1154 pScsiTmReply->TaskType,
1155 le16_to_cpu(pScsiTmReply->IOCStatus),
1156 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1157 pScsiTmReply->ResponseCode,
1158 le32_to_cpu(pScsiTmReply->TerminationCount)));
1159
1160 if (pScsiTmReply->ResponseCode)
1161 mptscsih_taskmgmt_response_code(ioc,
1162 pScsiTmReply->ResponseCode);
1163 }
1164
1165 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1166 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1167 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1168 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1169 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1170 memcpy(ioc->taskmgmt_cmds.reply, mr,
1171 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1172 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1173 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1174 complete(&ioc->taskmgmt_cmds.done);
1175 return 1;
1176 }
1177 return 0;
1178 }
1179
1180 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001181
1182 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301183 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001184
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301185 target_reset_list = list_entry(head->next,
1186 struct mptsas_target_reset_event, list);
1187
1188 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1189 "TaskMgmt: completed (%d seconds)\n",
1190 ioc->name, jiffies_to_msecs(jiffies -
1191 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001192
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301193 id = pScsiTmReply->TargetID;
1194 channel = pScsiTmReply->Bus;
1195 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001196
1197 /*
1198 * retry target reset
1199 */
1200 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301201 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001202 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301203 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001204 }
1205
1206 /*
1207 * enable work queue to remove device from upper layers
1208 */
1209 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301210 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1211 mptsas_queue_device_delete(ioc,
1212 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301213
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301214
Eric Mooredf9e0622007-01-29 09:46:21 -07001215 /*
1216 * issue target reset to next device in the queue
1217 */
1218
1219 head = &hd->target_reset_list;
1220 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301221 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001222
1223 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1224 list);
1225
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301226 id = target_reset_list->sas_event_data.TargetID;
1227 channel = target_reset_list->sas_event_data.Bus;
1228 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001229
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301230 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001231 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001232
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301233 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001234}
1235
1236/**
1237 * mptscsih_ioc_reset
1238 *
1239 * @ioc
1240 * @reset_phase
1241 *
1242 **/
1243static int
1244mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1245{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001246 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001247 int rc;
1248
1249 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301250 if ((ioc->bus_type != SAS) || (!rc))
1251 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001252
Eric Mooree7eae9f2007-09-29 10:15:59 -06001253 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001254 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001255 goto out;
1256
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301257 switch (reset_phase) {
1258 case MPT_IOC_SETUP_RESET:
1259 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1260 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1261 mptsas_fw_event_off(ioc);
1262 break;
1263 case MPT_IOC_PRE_RESET:
1264 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1265 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1266 break;
1267 case MPT_IOC_POST_RESET:
1268 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1269 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1270 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1271 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1272 complete(&ioc->sas_mgmt.done);
1273 }
1274 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301275 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301276 mptsas_fw_event_on(ioc);
1277 break;
1278 default:
1279 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001280 }
1281
1282 out:
1283 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001284}
1285
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301286
1287/**
1288 * enum device_state -
1289 * @DEVICE_RETRY: need to retry the TUR
1290 * @DEVICE_ERROR: TUR return error, don't add device
1291 * @DEVICE_READY: device can be added
1292 *
1293 */
1294enum device_state{
1295 DEVICE_RETRY,
1296 DEVICE_ERROR,
1297 DEVICE_READY,
1298};
1299
Christoph Hellwige3094442006-02-16 13:25:36 +01001300static int
Moore, Eric52435432006-03-14 09:14:15 -07001301mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001302 u32 form, u32 form_specific)
1303{
1304 ConfigExtendedPageHeader_t hdr;
1305 CONFIGPARMS cfg;
1306 SasEnclosurePage0_t *buffer;
1307 dma_addr_t dma_handle;
1308 int error;
1309 __le64 le_identifier;
1310
1311 memset(&hdr, 0, sizeof(hdr));
1312 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1313 hdr.PageNumber = 0;
1314 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1315 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1316
1317 cfg.cfghdr.ehdr = &hdr;
1318 cfg.physAddr = -1;
1319 cfg.pageAddr = form + form_specific;
1320 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1321 cfg.dir = 0; /* read */
1322 cfg.timeout = 10;
1323
1324 error = mpt_config(ioc, &cfg);
1325 if (error)
1326 goto out;
1327 if (!hdr.ExtPageLength) {
1328 error = -ENXIO;
1329 goto out;
1330 }
1331
1332 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1333 &dma_handle);
1334 if (!buffer) {
1335 error = -ENOMEM;
1336 goto out;
1337 }
1338
1339 cfg.physAddr = dma_handle;
1340 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1341
1342 error = mpt_config(ioc, &cfg);
1343 if (error)
1344 goto out_free_consistent;
1345
1346 /* save config data */
1347 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1348 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1349 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1350 enclosure->flags = le16_to_cpu(buffer->Flags);
1351 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1352 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1353 enclosure->start_id = buffer->StartTargetID;
1354 enclosure->start_channel = buffer->StartBus;
1355 enclosure->sep_id = buffer->SEPTargetID;
1356 enclosure->sep_channel = buffer->SEPBus;
1357
1358 out_free_consistent:
1359 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1360 buffer, dma_handle);
1361 out:
1362 return error;
1363}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001364
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301365/**
1366 * mptsas_add_end_device - report a new end device to sas transport layer
1367 * @ioc: Pointer to MPT_ADAPTER structure
1368 * @phy_info: decribes attached device
1369 *
1370 * return (0) success (1) failure
1371 *
1372 **/
1373static int
1374mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1375{
1376 struct sas_rphy *rphy;
1377 struct sas_port *port;
1378 struct sas_identify identify;
1379 char *ds = NULL;
1380 u8 fw_id;
1381
1382 if (!phy_info) {
1383 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1384 "%s: exit at line=%d\n", ioc->name,
1385 __func__, __LINE__));
1386 return 1;
1387 }
1388
1389 fw_id = phy_info->attached.id;
1390
1391 if (mptsas_get_rphy(phy_info)) {
1392 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1393 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1394 __func__, fw_id, __LINE__));
1395 return 2;
1396 }
1397
1398 port = mptsas_get_port(phy_info);
1399 if (!port) {
1400 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1401 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1402 __func__, fw_id, __LINE__));
1403 return 3;
1404 }
1405
1406 if (phy_info->attached.device_info &
1407 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1408 ds = "ssp";
1409 if (phy_info->attached.device_info &
1410 MPI_SAS_DEVICE_INFO_STP_TARGET)
1411 ds = "stp";
1412 if (phy_info->attached.device_info &
1413 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1414 ds = "sata";
1415
1416 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1417 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1418 phy_info->attached.channel, phy_info->attached.id,
1419 phy_info->attached.phy_id, (unsigned long long)
1420 phy_info->attached.sas_address);
1421
1422 mptsas_parse_device_info(&identify, &phy_info->attached);
1423 rphy = sas_end_device_alloc(port);
1424 if (!rphy) {
1425 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1426 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1427 __func__, fw_id, __LINE__));
1428 return 5; /* non-fatal: an rphy can be added later */
1429 }
1430
1431 rphy->identify = identify;
1432 if (sas_rphy_add(rphy)) {
1433 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1434 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1435 __func__, fw_id, __LINE__));
1436 sas_rphy_free(rphy);
1437 return 6;
1438 }
1439 mptsas_set_rphy(ioc, phy_info, rphy);
1440 return 0;
1441}
1442
1443/**
1444 * mptsas_del_end_device - report a deleted end device to sas transport
1445 * layer
1446 * @ioc: Pointer to MPT_ADAPTER structure
1447 * @phy_info: decribes attached device
1448 *
1449 **/
1450static void
1451mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1452{
1453 struct sas_rphy *rphy;
1454 struct sas_port *port;
1455 struct mptsas_portinfo *port_info;
1456 struct mptsas_phyinfo *phy_info_parent;
1457 int i;
1458 char *ds = NULL;
1459 u8 fw_id;
1460 u64 sas_address;
1461
1462 if (!phy_info)
1463 return;
1464
1465 fw_id = phy_info->attached.id;
1466 sas_address = phy_info->attached.sas_address;
1467
1468 if (!phy_info->port_details) {
1469 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1470 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1471 __func__, fw_id, __LINE__));
1472 return;
1473 }
1474 rphy = mptsas_get_rphy(phy_info);
1475 if (!rphy) {
1476 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1477 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1478 __func__, fw_id, __LINE__));
1479 return;
1480 }
1481
1482 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1483 || phy_info->attached.device_info
1484 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1485 || phy_info->attached.device_info
1486 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1487 ds = "initiator";
1488 if (phy_info->attached.device_info &
1489 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1490 ds = "ssp";
1491 if (phy_info->attached.device_info &
1492 MPI_SAS_DEVICE_INFO_STP_TARGET)
1493 ds = "stp";
1494 if (phy_info->attached.device_info &
1495 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1496 ds = "sata";
1497
1498 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1499 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1500 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1501 phy_info->attached.id, phy_info->attached.phy_id,
1502 (unsigned long long) sas_address);
1503
1504 port = mptsas_get_port(phy_info);
1505 if (!port) {
1506 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1507 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1508 __func__, fw_id, __LINE__));
1509 return;
1510 }
1511 port_info = phy_info->portinfo;
1512 phy_info_parent = port_info->phy_info;
1513 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1514 if (!phy_info_parent->phy)
1515 continue;
1516 if (phy_info_parent->attached.sas_address !=
1517 sas_address)
1518 continue;
1519 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1520 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1521 ioc->name, phy_info_parent->phy_id,
1522 phy_info_parent->phy);
1523 sas_port_delete_phy(port, phy_info_parent->phy);
1524 }
1525
1526 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1527 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1528 port->port_identifier, (unsigned long long)sas_address);
1529 sas_port_delete(port);
1530 mptsas_set_port(ioc, phy_info, NULL);
1531 mptsas_port_delete(ioc, phy_info->port_details);
1532}
1533
1534struct mptsas_phyinfo *
1535mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1536 struct mptsas_devinfo *sas_device)
1537{
1538 struct mptsas_phyinfo *phy_info;
1539 struct mptsas_portinfo *port_info;
1540 int i;
1541
1542 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1543 sas_device->sas_address);
1544 if (!phy_info)
1545 goto out;
1546 port_info = phy_info->portinfo;
1547 if (!port_info)
1548 goto out;
1549 mutex_lock(&ioc->sas_topology_mutex);
1550 for (i = 0; i < port_info->num_phys; i++) {
1551 if (port_info->phy_info[i].attached.sas_address !=
1552 sas_device->sas_address)
1553 continue;
1554 port_info->phy_info[i].attached.channel = sas_device->channel;
1555 port_info->phy_info[i].attached.id = sas_device->id;
1556 port_info->phy_info[i].attached.sas_address =
1557 sas_device->sas_address;
1558 port_info->phy_info[i].attached.handle = sas_device->handle;
1559 port_info->phy_info[i].attached.handle_parent =
1560 sas_device->handle_parent;
1561 port_info->phy_info[i].attached.handle_enclosure =
1562 sas_device->handle_enclosure;
1563 }
1564 mutex_unlock(&ioc->sas_topology_mutex);
1565 out:
1566 return phy_info;
1567}
1568
1569/**
1570 * mptsas_firmware_event_work - work thread for processing fw events
1571 * @work: work queue payload containing info describing the event
1572 * Context: user
1573 *
1574 */
1575static void
1576mptsas_firmware_event_work(struct work_struct *work)
1577{
1578 struct fw_event_work *fw_event =
1579 container_of(work, struct fw_event_work, work.work);
1580 MPT_ADAPTER *ioc = fw_event->ioc;
1581
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301582 /* special rescan topology handling */
1583 if (fw_event->event == -1) {
1584 if (ioc->in_rescan) {
1585 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1586 "%s: rescan ignored as it is in progress\n",
1587 ioc->name, __func__));
1588 return;
1589 }
1590 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1591 "reset\n", ioc->name, __func__));
1592 ioc->in_rescan = 1;
1593 mptsas_not_responding_devices(ioc);
1594 mptsas_scan_sas_topology(ioc);
1595 ioc->in_rescan = 0;
1596 mptsas_free_fw_event(ioc, fw_event);
1597 return;
1598 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301599
1600 /* events handling turned off during host reset */
1601 if (ioc->fw_events_off) {
1602 mptsas_free_fw_event(ioc, fw_event);
1603 return;
1604 }
1605
1606 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1607 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1608 (fw_event->event & 0xFF)));
1609
1610 switch (fw_event->event) {
1611 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1612 mptsas_send_sas_event(fw_event);
1613 break;
1614 case MPI_EVENT_INTEGRATED_RAID:
1615 mptsas_send_raid_event(fw_event);
1616 break;
1617 case MPI_EVENT_IR2:
1618 mptsas_send_ir2_event(fw_event);
1619 break;
1620 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1621 mptbase_sas_persist_operation(ioc,
1622 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1623 mptsas_free_fw_event(ioc, fw_event);
1624 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301625 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1626 mptsas_broadcast_primative_work(fw_event);
1627 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301628 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1629 mptsas_send_expander_event(fw_event);
1630 break;
1631 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1632 mptsas_send_link_status_event(fw_event);
1633 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301634 case MPI_EVENT_QUEUE_FULL:
1635 mptsas_handle_queue_full_event(fw_event);
1636 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301637 }
1638}
1639
1640
1641
James Bottomleyf013db32006-03-18 14:54:36 -06001642static int
1643mptsas_slave_configure(struct scsi_device *sdev)
1644{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301645 struct Scsi_Host *host = sdev->host;
1646 MPT_SCSI_HOST *hd = shost_priv(host);
1647 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301648 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001649
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301650 if (vdevice->vtarget->deleted) {
1651 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1652 vdevice->vtarget->deleted = 0;
1653 }
1654
1655 /*
1656 * RAID volumes placed beyond the last expected port.
1657 * Ignore sending sas mode pages in that case..
1658 */
1659 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1660 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001661 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301662 }
James Bottomleyf013db32006-03-18 14:54:36 -06001663
James Bottomleye8bf3942006-07-11 17:49:34 -04001664 sas_read_port_mode_page(sdev);
1665
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301666 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1667
James Bottomleye8bf3942006-07-11 17:49:34 -04001668 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001669 return mptscsih_slave_configure(sdev);
1670}
1671
Eric Moore547f9a22006-06-27 14:42:12 -06001672static int
1673mptsas_target_alloc(struct scsi_target *starget)
1674{
1675 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001676 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001677 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001678 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001679 struct sas_rphy *rphy;
1680 struct mptsas_portinfo *p;
1681 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001682 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001683
1684 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1685 if (!vtarget)
1686 return -ENOMEM;
1687
1688 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001689 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001690 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1691 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001692 channel = 0;
1693
Eric Moore793955f2007-01-29 09:42:20 -07001694 /*
1695 * RAID volumes placed beyond the last expected port.
1696 */
1697 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301698 if (!ioc->raid_data.pIocPg2) {
1699 kfree(vtarget);
1700 return -ENXIO;
1701 }
1702 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1703 if (id == ioc->raid_data.pIocPg2->
1704 RaidVolume[i].VolumeID) {
1705 channel = ioc->raid_data.pIocPg2->
1706 RaidVolume[i].VolumeBus;
1707 }
1708 }
1709 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001710 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001711 }
Eric Moore547f9a22006-06-27 14:42:12 -06001712
1713 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001714 mutex_lock(&ioc->sas_topology_mutex);
1715 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001716 for (i = 0; i < p->num_phys; i++) {
1717 if (p->phy_info[i].attached.sas_address !=
1718 rphy->identify.sas_address)
1719 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001720 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001721 channel = p->phy_info[i].attached.channel;
1722 mptsas_set_starget(&p->phy_info[i], starget);
1723
1724 /*
1725 * Exposing hidden raid components
1726 */
Eric Mooree80b0022007-09-14 18:49:03 -06001727 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1728 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001729 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001730 vtarget->tflags |=
1731 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001732 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001733 }
Eric Mooree80b0022007-09-14 18:49:03 -06001734 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001735 goto out;
1736 }
1737 }
Eric Mooree80b0022007-09-14 18:49:03 -06001738 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001739
1740 kfree(vtarget);
1741 return -ENXIO;
1742
1743 out:
Eric Moore793955f2007-01-29 09:42:20 -07001744 vtarget->id = id;
1745 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001746 starget->hostdata = vtarget;
1747 return 0;
1748}
1749
1750static void
1751mptsas_target_destroy(struct scsi_target *starget)
1752{
1753 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001754 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001755 struct sas_rphy *rphy;
1756 struct mptsas_portinfo *p;
1757 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301758 MPT_ADAPTER *ioc = hd->ioc;
1759 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001760
1761 if (!starget->hostdata)
1762 return;
1763
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301764 vtarget = starget->hostdata;
1765
Kashyap, Desai57e98512009-05-29 16:55:09 +05301766 mptsas_del_device_component_by_os(ioc, starget->channel,
1767 starget->id);
1768
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301769
James Bottomleye8bf3942006-07-11 17:49:34 -04001770 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001771 goto out;
1772
1773 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001774 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001775 for (i = 0; i < p->num_phys; i++) {
1776 if (p->phy_info[i].attached.sas_address !=
1777 rphy->identify.sas_address)
1778 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301779
1780 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1781 "delete device: fw_channel %d, fw_id %d, phy %d, "
1782 "sas_addr 0x%llx\n", ioc->name,
1783 p->phy_info[i].attached.channel,
1784 p->phy_info[i].attached.id,
1785 p->phy_info[i].attached.phy_id, (unsigned long long)
1786 p->phy_info[i].attached.sas_address);
1787
Eric Moore547f9a22006-06-27 14:42:12 -06001788 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001789 }
1790 }
1791
1792 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301793 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001794 kfree(starget->hostdata);
1795 starget->hostdata = NULL;
1796}
1797
1798
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001799static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001800mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001801{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001802 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001803 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001804 struct sas_rphy *rphy;
1805 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001806 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001807 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001808 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001809 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001810
Eric Moorea69de502007-09-14 18:48:19 -06001811 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1812 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001813 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001814 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001815 return -ENOMEM;
1816 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001817 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001818 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001819
James Bottomleye8bf3942006-07-11 17:49:34 -04001820 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001821 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001822
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001823 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001824 mutex_lock(&ioc->sas_topology_mutex);
1825 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001826 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001827 if (p->phy_info[i].attached.sas_address !=
1828 rphy->identify.sas_address)
1829 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001830 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001831 /*
1832 * Exposing hidden raid components
1833 */
Eric Mooree80b0022007-09-14 18:49:03 -06001834 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001835 p->phy_info[i].attached.channel,
1836 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001837 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001838 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001839 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001840 }
1841 }
Eric Mooree80b0022007-09-14 18:49:03 -06001842 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001843
Eric Moorea69de502007-09-14 18:48:19 -06001844 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001845 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001846
1847 out:
Eric Moorea69de502007-09-14 18:48:19 -06001848 vdevice->vtarget->num_luns++;
1849 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001850 return 0;
1851}
1852
Eric Moore547f9a22006-06-27 14:42:12 -06001853static int
1854mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001855{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301856 MPT_SCSI_HOST *hd;
1857 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001858 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001859
Eric Moorea69de502007-09-14 18:48:19 -06001860 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001861 SCpnt->result = DID_NO_CONNECT << 16;
1862 done(SCpnt);
1863 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001864 }
Eric Moore547f9a22006-06-27 14:42:12 -06001865
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301866 hd = shost_priv(SCpnt->device->host);
1867 ioc = hd->ioc;
1868
1869 if (ioc->sas_discovery_quiesce_io)
1870 return SCSI_MLQUEUE_HOST_BUSY;
1871
Eric Moore793955f2007-01-29 09:42:20 -07001872// scsi_print_command(SCpnt);
1873
Eric Moore547f9a22006-06-27 14:42:12 -06001874 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001875}
1876
Eric Moore547f9a22006-06-27 14:42:12 -06001877
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001878static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001879 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001880 .proc_name = "mptsas",
1881 .proc_info = mptscsih_proc_info,
1882 .name = "MPT SPI Host",
1883 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001884 .queuecommand = mptsas_qcmd,
1885 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001886 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001887 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001888 .target_destroy = mptsas_target_destroy,
1889 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001890 .change_queue_depth = mptscsih_change_queue_depth,
1891 .eh_abort_handler = mptscsih_abort,
1892 .eh_device_reset_handler = mptscsih_dev_reset,
1893 .eh_bus_reset_handler = mptscsih_bus_reset,
1894 .eh_host_reset_handler = mptscsih_host_reset,
1895 .bios_param = mptscsih_bios_param,
1896 .can_queue = MPT_FC_CAN_QUEUE,
1897 .this_id = -1,
1898 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1899 .max_sectors = 8192,
1900 .cmd_per_lun = 7,
1901 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301902 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001903};
1904
Christoph Hellwigb5141122005-10-28 22:07:41 +02001905static int mptsas_get_linkerrors(struct sas_phy *phy)
1906{
1907 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1908 ConfigExtendedPageHeader_t hdr;
1909 CONFIGPARMS cfg;
1910 SasPhyPage1_t *buffer;
1911 dma_addr_t dma_handle;
1912 int error;
1913
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001914 /* FIXME: only have link errors on local phys */
1915 if (!scsi_is_sas_phy_local(phy))
1916 return -EINVAL;
1917
Christoph Hellwigb5141122005-10-28 22:07:41 +02001918 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1919 hdr.ExtPageLength = 0;
1920 hdr.PageNumber = 1 /* page number 1*/;
1921 hdr.Reserved1 = 0;
1922 hdr.Reserved2 = 0;
1923 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1924 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1925
1926 cfg.cfghdr.ehdr = &hdr;
1927 cfg.physAddr = -1;
1928 cfg.pageAddr = phy->identify.phy_identifier;
1929 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1930 cfg.dir = 0; /* read */
1931 cfg.timeout = 10;
1932
1933 error = mpt_config(ioc, &cfg);
1934 if (error)
1935 return error;
1936 if (!hdr.ExtPageLength)
1937 return -ENXIO;
1938
1939 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1940 &dma_handle);
1941 if (!buffer)
1942 return -ENOMEM;
1943
1944 cfg.physAddr = dma_handle;
1945 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1946
1947 error = mpt_config(ioc, &cfg);
1948 if (error)
1949 goto out_free_consistent;
1950
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301951 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001952
1953 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1954 phy->running_disparity_error_count =
1955 le32_to_cpu(buffer->RunningDisparityErrorCount);
1956 phy->loss_of_dword_sync_count =
1957 le32_to_cpu(buffer->LossDwordSynchCount);
1958 phy->phy_reset_problem_count =
1959 le32_to_cpu(buffer->PhyResetProblemCount);
1960
1961 out_free_consistent:
1962 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1963 buffer, dma_handle);
1964 return error;
1965}
1966
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001967static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1968 MPT_FRAME_HDR *reply)
1969{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301970 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001971 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301972 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001973 memcpy(ioc->sas_mgmt.reply, reply,
1974 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1975 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301976
1977 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1978 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1979 complete(&ioc->sas_mgmt.done);
1980 return 1;
1981 }
1982 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001983}
1984
1985static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1986{
1987 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1988 SasIoUnitControlRequest_t *req;
1989 SasIoUnitControlReply_t *reply;
1990 MPT_FRAME_HDR *mf;
1991 MPIHeader_t *hdr;
1992 unsigned long timeleft;
1993 int error = -ERESTARTSYS;
1994
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001995 /* FIXME: fusion doesn't allow non-local phy reset */
1996 if (!scsi_is_sas_phy_local(phy))
1997 return -EINVAL;
1998
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001999 /* not implemented for expanders */
2000 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2001 return -ENXIO;
2002
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002003 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002004 goto out;
2005
2006 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2007 if (!mf) {
2008 error = -ENOMEM;
2009 goto out_unlock;
2010 }
2011
2012 hdr = (MPIHeader_t *) mf;
2013 req = (SasIoUnitControlRequest_t *)mf;
2014 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2015 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2016 req->MsgContext = hdr->MsgContext;
2017 req->Operation = hard_reset ?
2018 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2019 req->PhyNum = phy->identify.phy_identifier;
2020
Kashyap, Desai2f187862009-05-29 16:52:37 +05302021 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002022 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2023
2024 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2025 10 * HZ);
2026 if (!timeleft) {
2027 /* On timeout reset the board */
2028 mpt_free_msg_frame(ioc, mf);
2029 mpt_HardResetHandler(ioc, CAN_SLEEP);
2030 error = -ETIMEDOUT;
2031 goto out_unlock;
2032 }
2033
2034 /* a reply frame is expected */
2035 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302036 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002037 error = -ENXIO;
2038 goto out_unlock;
2039 }
2040
2041 /* process the completed Reply Message Frame */
2042 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2043 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002044 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002045 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002046 error = -ENXIO;
2047 goto out_unlock;
2048 }
2049
2050 error = 0;
2051
2052 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302053 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002054 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002055 out:
2056 return error;
2057}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002058
Christoph Hellwige3094442006-02-16 13:25:36 +01002059static int
2060mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2061{
2062 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2063 int i, error;
2064 struct mptsas_portinfo *p;
2065 struct mptsas_enclosure enclosure_info;
2066 u64 enclosure_handle;
2067
2068 mutex_lock(&ioc->sas_topology_mutex);
2069 list_for_each_entry(p, &ioc->sas_topology, list) {
2070 for (i = 0; i < p->num_phys; i++) {
2071 if (p->phy_info[i].attached.sas_address ==
2072 rphy->identify.sas_address) {
2073 enclosure_handle = p->phy_info[i].
2074 attached.handle_enclosure;
2075 goto found_info;
2076 }
2077 }
2078 }
2079 mutex_unlock(&ioc->sas_topology_mutex);
2080 return -ENXIO;
2081
2082 found_info:
2083 mutex_unlock(&ioc->sas_topology_mutex);
2084 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002085 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002086 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2087 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2088 if (!error)
2089 *identifier = enclosure_info.enclosure_logical_id;
2090 return error;
2091}
2092
2093static int
2094mptsas_get_bay_identifier(struct sas_rphy *rphy)
2095{
2096 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2097 struct mptsas_portinfo *p;
2098 int i, rc;
2099
2100 mutex_lock(&ioc->sas_topology_mutex);
2101 list_for_each_entry(p, &ioc->sas_topology, list) {
2102 for (i = 0; i < p->num_phys; i++) {
2103 if (p->phy_info[i].attached.sas_address ==
2104 rphy->identify.sas_address) {
2105 rc = p->phy_info[i].attached.slot;
2106 goto out;
2107 }
2108 }
2109 }
2110 rc = -ENXIO;
2111 out:
2112 mutex_unlock(&ioc->sas_topology_mutex);
2113 return rc;
2114}
2115
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002116static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2117 struct request *req)
2118{
2119 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2120 MPT_FRAME_HDR *mf;
2121 SmpPassthroughRequest_t *smpreq;
2122 struct request *rsp = req->next_rq;
2123 int ret;
2124 int flagsLength;
2125 unsigned long timeleft;
2126 char *psge;
2127 dma_addr_t dma_addr_in = 0;
2128 dma_addr_t dma_addr_out = 0;
2129 u64 sas_address = 0;
2130
2131 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002132 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002133 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002134 return -EINVAL;
2135 }
2136
2137 /* do we need to support multiple segments? */
2138 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002139 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002140 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06002141 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002142 return -EINVAL;
2143 }
2144
2145 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2146 if (ret)
2147 goto out;
2148
2149 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2150 if (!mf) {
2151 ret = -ENOMEM;
2152 goto out_unlock;
2153 }
2154
2155 smpreq = (SmpPassthroughRequest_t *)mf;
2156 memset(smpreq, 0, sizeof(*smpreq));
2157
2158 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
2159 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2160
2161 if (rphy)
2162 sas_address = rphy->identify.sas_address;
2163 else {
2164 struct mptsas_portinfo *port_info;
2165
2166 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302167 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002168 if (port_info && port_info->phy_info)
2169 sas_address =
2170 port_info->phy_info[0].phy->identify.sas_address;
2171 mutex_unlock(&ioc->sas_topology_mutex);
2172 }
2173
2174 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2175
2176 psge = (char *)
2177 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2178
2179 /* request */
2180 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2181 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302182 MPI_SGE_FLAGS_DIRECTION)
2183 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002184 flagsLength |= (req->data_len - 4);
2185
2186 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
2187 req->data_len, PCI_DMA_BIDIRECTIONAL);
2188 if (!dma_addr_out)
2189 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302190 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302191 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002192
2193 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302194 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2195 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2196 MPI_SGE_FLAGS_IOC_TO_HOST |
2197 MPI_SGE_FLAGS_END_OF_BUFFER;
2198
2199 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002200 flagsLength |= rsp->data_len + 4;
2201 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
2202 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
2203 if (!dma_addr_in)
2204 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302205 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002206
Kashyap, Desai2f187862009-05-29 16:52:37 +05302207 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002208 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2209
2210 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2211 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002212 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002213 /* On timeout reset the board */
2214 mpt_HardResetHandler(ioc, CAN_SLEEP);
2215 ret = -ETIMEDOUT;
2216 goto unmap;
2217 }
2218 mf = NULL;
2219
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302220 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002221 SmpPassthroughReply_t *smprep;
2222
2223 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2224 memcpy(req->sense, smprep, sizeof(*smprep));
2225 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09002226 req->data_len = 0;
2227 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002228 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302229 printk(MYIOC_s_ERR_FMT
2230 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002231 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002232 ret = -ENXIO;
2233 }
2234unmap:
2235 if (dma_addr_out)
2236 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
2237 PCI_DMA_BIDIRECTIONAL);
2238 if (dma_addr_in)
2239 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
2240 PCI_DMA_BIDIRECTIONAL);
2241put_mf:
2242 if (mf)
2243 mpt_free_msg_frame(ioc, mf);
2244out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302245 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002246 mutex_unlock(&ioc->sas_mgmt.mutex);
2247out:
2248 return ret;
2249}
2250
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002251static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002252 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002253 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2254 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002255 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002256 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002257};
2258
2259static struct scsi_transport_template *mptsas_transport_template;
2260
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002261static int
2262mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2263{
2264 ConfigExtendedPageHeader_t hdr;
2265 CONFIGPARMS cfg;
2266 SasIOUnitPage0_t *buffer;
2267 dma_addr_t dma_handle;
2268 int error, i;
2269
2270 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2271 hdr.ExtPageLength = 0;
2272 hdr.PageNumber = 0;
2273 hdr.Reserved1 = 0;
2274 hdr.Reserved2 = 0;
2275 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2276 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2277
2278 cfg.cfghdr.ehdr = &hdr;
2279 cfg.physAddr = -1;
2280 cfg.pageAddr = 0;
2281 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2282 cfg.dir = 0; /* read */
2283 cfg.timeout = 10;
2284
2285 error = mpt_config(ioc, &cfg);
2286 if (error)
2287 goto out;
2288 if (!hdr.ExtPageLength) {
2289 error = -ENXIO;
2290 goto out;
2291 }
2292
2293 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2294 &dma_handle);
2295 if (!buffer) {
2296 error = -ENOMEM;
2297 goto out;
2298 }
2299
2300 cfg.physAddr = dma_handle;
2301 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2302
2303 error = mpt_config(ioc, &cfg);
2304 if (error)
2305 goto out_free_consistent;
2306
2307 port_info->num_phys = buffer->NumPhys;
2308 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302309 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002310 if (!port_info->phy_info) {
2311 error = -ENOMEM;
2312 goto out_free_consistent;
2313 }
2314
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302315 ioc->nvdata_version_persistent =
2316 le16_to_cpu(buffer->NvdataVersionPersistent);
2317 ioc->nvdata_version_default =
2318 le16_to_cpu(buffer->NvdataVersionDefault);
2319
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002320 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302321 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002322 port_info->phy_info[i].phy_id = i;
2323 port_info->phy_info[i].port_id =
2324 buffer->PhyData[i].Port;
2325 port_info->phy_info[i].negotiated_link_rate =
2326 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002327 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002328 port_info->phy_info[i].handle =
2329 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002330 }
2331
2332 out_free_consistent:
2333 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2334 buffer, dma_handle);
2335 out:
2336 return error;
2337}
2338
2339static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302340mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2341{
2342 ConfigExtendedPageHeader_t hdr;
2343 CONFIGPARMS cfg;
2344 SasIOUnitPage1_t *buffer;
2345 dma_addr_t dma_handle;
2346 int error;
2347 u16 device_missing_delay;
2348
2349 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2350 memset(&cfg, 0, sizeof(CONFIGPARMS));
2351
2352 cfg.cfghdr.ehdr = &hdr;
2353 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2354 cfg.timeout = 10;
2355 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2356 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2357 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2358 cfg.cfghdr.ehdr->PageNumber = 1;
2359
2360 error = mpt_config(ioc, &cfg);
2361 if (error)
2362 goto out;
2363 if (!hdr.ExtPageLength) {
2364 error = -ENXIO;
2365 goto out;
2366 }
2367
2368 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2369 &dma_handle);
2370 if (!buffer) {
2371 error = -ENOMEM;
2372 goto out;
2373 }
2374
2375 cfg.physAddr = dma_handle;
2376 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2377
2378 error = mpt_config(ioc, &cfg);
2379 if (error)
2380 goto out_free_consistent;
2381
2382 ioc->io_missing_delay =
2383 le16_to_cpu(buffer->IODeviceMissingDelay);
2384 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2385 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2386 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2387 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2388
2389 out_free_consistent:
2390 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2391 buffer, dma_handle);
2392 out:
2393 return error;
2394}
2395
2396static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002397mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2398 u32 form, u32 form_specific)
2399{
2400 ConfigExtendedPageHeader_t hdr;
2401 CONFIGPARMS cfg;
2402 SasPhyPage0_t *buffer;
2403 dma_addr_t dma_handle;
2404 int error;
2405
2406 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2407 hdr.ExtPageLength = 0;
2408 hdr.PageNumber = 0;
2409 hdr.Reserved1 = 0;
2410 hdr.Reserved2 = 0;
2411 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2412 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2413
2414 cfg.cfghdr.ehdr = &hdr;
2415 cfg.dir = 0; /* read */
2416 cfg.timeout = 10;
2417
2418 /* Get Phy Pg 0 for each Phy. */
2419 cfg.physAddr = -1;
2420 cfg.pageAddr = form + form_specific;
2421 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2422
2423 error = mpt_config(ioc, &cfg);
2424 if (error)
2425 goto out;
2426
2427 if (!hdr.ExtPageLength) {
2428 error = -ENXIO;
2429 goto out;
2430 }
2431
2432 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2433 &dma_handle);
2434 if (!buffer) {
2435 error = -ENOMEM;
2436 goto out;
2437 }
2438
2439 cfg.physAddr = dma_handle;
2440 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2441
2442 error = mpt_config(ioc, &cfg);
2443 if (error)
2444 goto out_free_consistent;
2445
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302446 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002447
2448 phy_info->hw_link_rate = buffer->HwLinkRate;
2449 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2450 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2451 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2452
2453 out_free_consistent:
2454 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2455 buffer, dma_handle);
2456 out:
2457 return error;
2458}
2459
2460static int
2461mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2462 u32 form, u32 form_specific)
2463{
2464 ConfigExtendedPageHeader_t hdr;
2465 CONFIGPARMS cfg;
2466 SasDevicePage0_t *buffer;
2467 dma_addr_t dma_handle;
2468 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002469 int error=0;
2470
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002471 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2472 hdr.ExtPageLength = 0;
2473 hdr.PageNumber = 0;
2474 hdr.Reserved1 = 0;
2475 hdr.Reserved2 = 0;
2476 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2477 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2478
2479 cfg.cfghdr.ehdr = &hdr;
2480 cfg.pageAddr = form + form_specific;
2481 cfg.physAddr = -1;
2482 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2483 cfg.dir = 0; /* read */
2484 cfg.timeout = 10;
2485
Moore, Ericdb9c9172006-03-14 09:14:18 -07002486 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002487 error = mpt_config(ioc, &cfg);
2488 if (error)
2489 goto out;
2490 if (!hdr.ExtPageLength) {
2491 error = -ENXIO;
2492 goto out;
2493 }
2494
2495 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2496 &dma_handle);
2497 if (!buffer) {
2498 error = -ENOMEM;
2499 goto out;
2500 }
2501
2502 cfg.physAddr = dma_handle;
2503 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2504
2505 error = mpt_config(ioc, &cfg);
2506 if (error)
2507 goto out_free_consistent;
2508
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302509 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002510
Kashyap, Desai2f187862009-05-29 16:52:37 +05302511 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002512 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002513 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002514 device_info->handle_enclosure =
2515 le16_to_cpu(buffer->EnclosureHandle);
2516 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002517 device_info->phy_id = buffer->PhyNum;
2518 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002519 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002520 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002521 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002522 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2523 device_info->sas_address = le64_to_cpu(sas_address);
2524 device_info->device_info =
2525 le32_to_cpu(buffer->DeviceInfo);
2526
2527 out_free_consistent:
2528 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2529 buffer, dma_handle);
2530 out:
2531 return error;
2532}
2533
2534static int
2535mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2536 u32 form, u32 form_specific)
2537{
2538 ConfigExtendedPageHeader_t hdr;
2539 CONFIGPARMS cfg;
2540 SasExpanderPage0_t *buffer;
2541 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002542 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302543 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002544
Kashyap, Desai2f187862009-05-29 16:52:37 +05302545 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002546 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2547 hdr.ExtPageLength = 0;
2548 hdr.PageNumber = 0;
2549 hdr.Reserved1 = 0;
2550 hdr.Reserved2 = 0;
2551 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2552 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2553
2554 cfg.cfghdr.ehdr = &hdr;
2555 cfg.physAddr = -1;
2556 cfg.pageAddr = form + form_specific;
2557 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2558 cfg.dir = 0; /* read */
2559 cfg.timeout = 10;
2560
Moore, Ericdb9c9172006-03-14 09:14:18 -07002561 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002562 error = mpt_config(ioc, &cfg);
2563 if (error)
2564 goto out;
2565
2566 if (!hdr.ExtPageLength) {
2567 error = -ENXIO;
2568 goto out;
2569 }
2570
2571 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2572 &dma_handle);
2573 if (!buffer) {
2574 error = -ENOMEM;
2575 goto out;
2576 }
2577
2578 cfg.physAddr = dma_handle;
2579 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2580
2581 error = mpt_config(ioc, &cfg);
2582 if (error)
2583 goto out_free_consistent;
2584
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002585 if (!buffer->NumPhys) {
2586 error = -ENODEV;
2587 goto out_free_consistent;
2588 }
2589
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002590 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302591 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002592 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302593 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002594 if (!port_info->phy_info) {
2595 error = -ENOMEM;
2596 goto out_free_consistent;
2597 }
2598
Kashyap, Desai2f187862009-05-29 16:52:37 +05302599 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002600 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002601 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002602 port_info->phy_info[i].handle =
2603 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302604 port_info->phy_info[i].identify.sas_address =
2605 le64_to_cpu(sas_address);
2606 port_info->phy_info[i].identify.handle_parent =
2607 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002608 }
Eric Moore547f9a22006-06-27 14:42:12 -06002609
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002610 out_free_consistent:
2611 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2612 buffer, dma_handle);
2613 out:
2614 return error;
2615}
2616
2617static int
2618mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2619 u32 form, u32 form_specific)
2620{
2621 ConfigExtendedPageHeader_t hdr;
2622 CONFIGPARMS cfg;
2623 SasExpanderPage1_t *buffer;
2624 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002625 int error=0;
2626
Kashyap, Desai2f187862009-05-29 16:52:37 +05302627 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002628 hdr.ExtPageLength = 0;
2629 hdr.PageNumber = 1;
2630 hdr.Reserved1 = 0;
2631 hdr.Reserved2 = 0;
2632 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2633 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2634
2635 cfg.cfghdr.ehdr = &hdr;
2636 cfg.physAddr = -1;
2637 cfg.pageAddr = form + form_specific;
2638 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2639 cfg.dir = 0; /* read */
2640 cfg.timeout = 10;
2641
2642 error = mpt_config(ioc, &cfg);
2643 if (error)
2644 goto out;
2645
2646 if (!hdr.ExtPageLength) {
2647 error = -ENXIO;
2648 goto out;
2649 }
2650
2651 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2652 &dma_handle);
2653 if (!buffer) {
2654 error = -ENOMEM;
2655 goto out;
2656 }
2657
2658 cfg.physAddr = dma_handle;
2659 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2660
2661 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302662
2663 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2664 error = -ENODEV;
2665 goto out;
2666 }
2667
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002668 if (error)
2669 goto out_free_consistent;
2670
2671
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302672 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002673
2674 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002675 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002676 phy_info->port_id = buffer->PhysicalPort;
2677 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2678 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2679 phy_info->hw_link_rate = buffer->HwLinkRate;
2680 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2681 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2682
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002683 out_free_consistent:
2684 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2685 buffer, dma_handle);
2686 out:
2687 return error;
2688}
2689
2690static void
2691mptsas_parse_device_info(struct sas_identify *identify,
2692 struct mptsas_devinfo *device_info)
2693{
2694 u16 protocols;
2695
2696 identify->sas_address = device_info->sas_address;
2697 identify->phy_identifier = device_info->phy_id;
2698
2699 /*
2700 * Fill in Phy Initiator Port Protocol.
2701 * Bits 6:3, more than one bit can be set, fall through cases.
2702 */
2703 protocols = device_info->device_info & 0x78;
2704 identify->initiator_port_protocols = 0;
2705 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2706 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2707 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2708 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2709 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2710 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2711 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2712 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2713
2714 /*
2715 * Fill in Phy Target Port Protocol.
2716 * Bits 10:7, more than one bit can be set, fall through cases.
2717 */
2718 protocols = device_info->device_info & 0x780;
2719 identify->target_port_protocols = 0;
2720 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2721 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2722 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2723 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2724 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2725 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2726 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2727 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2728
2729 /*
2730 * Fill in Attached device type.
2731 */
2732 switch (device_info->device_info &
2733 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2734 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2735 identify->device_type = SAS_PHY_UNUSED;
2736 break;
2737 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2738 identify->device_type = SAS_END_DEVICE;
2739 break;
2740 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2741 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2742 break;
2743 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2744 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2745 break;
2746 }
2747}
2748
2749static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002750 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002751{
Moore, Erice6b2d762006-03-14 09:14:24 -07002752 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002753 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002754 struct sas_port *port;
2755 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002756
Eric Moore547f9a22006-06-27 14:42:12 -06002757 if (!dev) {
2758 error = -ENODEV;
2759 goto out;
2760 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002761
2762 if (!phy_info->phy) {
2763 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002764 if (!phy) {
2765 error = -ENOMEM;
2766 goto out;
2767 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002768 } else
2769 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002770
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002771 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002772
2773 /*
2774 * Set Negotiated link rate.
2775 */
2776 switch (phy_info->negotiated_link_rate) {
2777 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002778 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002779 break;
2780 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002781 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002782 break;
2783 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002784 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002785 break;
2786 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002787 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002788 break;
2789 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2790 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2791 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002792 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002793 break;
2794 }
2795
2796 /*
2797 * Set Max hardware link rate.
2798 */
2799 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2800 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002801 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002802 break;
2803 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002804 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002805 break;
2806 default:
2807 break;
2808 }
2809
2810 /*
2811 * Set Max programmed link rate.
2812 */
2813 switch (phy_info->programmed_link_rate &
2814 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2815 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002816 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002817 break;
2818 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002819 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002820 break;
2821 default:
2822 break;
2823 }
2824
2825 /*
2826 * Set Min hardware link rate.
2827 */
2828 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2829 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002830 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002831 break;
2832 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002833 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002834 break;
2835 default:
2836 break;
2837 }
2838
2839 /*
2840 * Set Min programmed link rate.
2841 */
2842 switch (phy_info->programmed_link_rate &
2843 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2844 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002845 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002846 break;
2847 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002848 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002849 break;
2850 default:
2851 break;
2852 }
2853
Moore, Erice6b2d762006-03-14 09:14:24 -07002854 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002855
Moore, Erice6b2d762006-03-14 09:14:24 -07002856 error = sas_phy_add(phy);
2857 if (error) {
2858 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002859 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002860 }
2861 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002862 }
2863
Eric Moore547f9a22006-06-27 14:42:12 -06002864 if (!phy_info->attached.handle ||
2865 !phy_info->port_details)
2866 goto out;
2867
2868 port = mptsas_get_port(phy_info);
2869 ioc = phy_to_ioc(phy_info->phy);
2870
2871 if (phy_info->sas_port_add_phy) {
2872
2873 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002874 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002875 if (!port) {
2876 error = -ENOMEM;
2877 goto out;
2878 }
2879 error = sas_port_add(port);
2880 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302881 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002882 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002883 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002884 goto out;
2885 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302886 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302887 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
2888 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
2889 ioc->name, port->port_identifier,
2890 (unsigned long long)phy_info->
2891 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06002892 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302893 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2894 "sas_port_add_phy: phy_id=%d\n",
2895 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002896 sas_port_add_phy(port, phy_info->phy);
2897 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302898 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
2899 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
2900 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06002901 }
Eric Moore547f9a22006-06-27 14:42:12 -06002902 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002903
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002904 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002905 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002906 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002907
James Bottomley2686de22006-06-30 12:54:02 -05002908 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002909 /*
2910 * Let the hotplug_work thread handle processing
2911 * the adding/removing of devices that occur
2912 * after start of day.
2913 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302914 if (mptsas_is_end_device(&phy_info->attached) &&
2915 phy_info->attached.handle_parent) {
2916 goto out;
2917 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002918
James Bottomleyf013db32006-03-18 14:54:36 -06002919 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002920 if (scsi_is_host_device(parent)) {
2921 struct mptsas_portinfo *port_info;
2922 int i;
2923
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302924 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002925
2926 for (i = 0; i < port_info->num_phys; i++)
2927 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002928 identify.sas_address) {
2929 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002930 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002931 }
James Bottomley2686de22006-06-30 12:54:02 -05002932
2933 } else if (scsi_is_sas_rphy(parent)) {
2934 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2935 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002936 parent_rphy->identify.sas_address) {
2937 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002938 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002939 }
James Bottomley2686de22006-06-30 12:54:02 -05002940 }
2941
James Bottomleyf013db32006-03-18 14:54:36 -06002942 switch (identify.device_type) {
2943 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002944 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002945 break;
2946 case SAS_EDGE_EXPANDER_DEVICE:
2947 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002948 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002949 break;
2950 default:
2951 rphy = NULL;
2952 break;
2953 }
Eric Moore547f9a22006-06-27 14:42:12 -06002954 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302955 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002956 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002957 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002958 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002959 }
2960
Eric Moore547f9a22006-06-27 14:42:12 -06002961 rphy->identify = identify;
2962 error = sas_rphy_add(rphy);
2963 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302964 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002965 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002966 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002967 sas_rphy_free(rphy);
2968 goto out;
2969 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302970 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002971 }
2972
Eric Moore547f9a22006-06-27 14:42:12 -06002973 out:
2974 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002975}
2976
2977static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002978mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002979{
Moore, Erice6b2d762006-03-14 09:14:24 -07002980 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002981 int error = -ENOMEM, i;
2982
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302983 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002984 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002985 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002986
Moore, Erice6b2d762006-03-14 09:14:24 -07002987 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002988 if (error)
2989 goto out_free_port_info;
2990
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302991 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002992 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302993 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002994 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302995 ioc->hba_port_info = port_info = hba;
2996 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002997 list_add_tail(&port_info->list, &ioc->sas_topology);
2998 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002999 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003000 port_info->phy_info[i].negotiated_link_rate =
3001 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003002 port_info->phy_info[i].handle =
3003 hba->phy_info[i].handle;
3004 port_info->phy_info[i].port_id =
3005 hba->phy_info[i].port_id;
3006 }
Eric Moore547f9a22006-06-27 14:42:12 -06003007 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003008 kfree(hba);
3009 hba = NULL;
3010 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003011 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303012#if defined(CPQ_CIM)
3013 ioc->num_ports = port_info->num_phys;
3014#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003015 for (i = 0; i < port_info->num_phys; i++) {
3016 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3017 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3018 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303019 port_info->phy_info[i].identify.handle =
3020 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003021 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003022 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3023 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303024 port_info->phy_info[i].identify.handle);
3025 if (!ioc->hba_port_sas_addr)
3026 ioc->hba_port_sas_addr =
3027 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003028 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003029 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003030 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003031 mptsas_sas_device_pg0(ioc,
3032 &port_info->phy_info[i].attached,
3033 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3034 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3035 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003036 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003037
Eric Moore547f9a22006-06-27 14:42:12 -06003038 mptsas_setup_wide_ports(ioc, port_info);
3039
3040 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003041 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003042 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003043
3044 return 0;
3045
3046 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003047 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003048 out:
3049 return error;
3050}
3051
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303052static void
3053mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003054{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303055 struct mptsas_portinfo *parent;
3056 struct device *parent_dev;
3057 struct sas_rphy *rphy;
3058 int i;
3059 u64 sas_address; /* expander sas address */
3060 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003061
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303062 handle = port_info->phy_info[0].handle;
3063 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003064 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003065 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303066 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3067 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003068
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303069 mptsas_sas_device_pg0(ioc,
3070 &port_info->phy_info[i].identify,
3071 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3072 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3073 port_info->phy_info[i].identify.handle);
3074 port_info->phy_info[i].identify.phy_id =
3075 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003076
3077 if (port_info->phy_info[i].attached.handle) {
3078 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303079 &port_info->phy_info[i].attached,
3080 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3081 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3082 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003083 port_info->phy_info[i].attached.phy_id =
3084 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003085 }
Eric Moore547f9a22006-06-27 14:42:12 -06003086 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003087
Moore, Erice6b2d762006-03-14 09:14:24 -07003088 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303089 parent = mptsas_find_portinfo_by_handle(ioc,
3090 port_info->phy_info[0].identify.handle_parent);
3091 if (!parent) {
3092 mutex_unlock(&ioc->sas_topology_mutex);
3093 return;
3094 }
3095 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3096 i++) {
3097 if (parent->phy_info[i].attached.sas_address == sas_address) {
3098 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3099 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003100 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003101 }
3102 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303103
3104 mptsas_setup_wide_ports(ioc, port_info);
3105 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3106 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3107 ioc->sas_index, 0);
3108}
3109
3110static void
3111mptsas_expander_event_add(MPT_ADAPTER *ioc,
3112 MpiEventDataSasExpanderStatusChange_t *expander_data)
3113{
3114 struct mptsas_portinfo *port_info;
3115 int i;
3116 __le64 sas_address;
3117
3118 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3119 if (!port_info)
3120 BUG();
3121 port_info->num_phys = (expander_data->NumPhys) ?
3122 expander_data->NumPhys : 1;
3123 port_info->phy_info = kcalloc(port_info->num_phys,
3124 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3125 if (!port_info->phy_info)
3126 BUG();
3127 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3128 for (i = 0; i < port_info->num_phys; i++) {
3129 port_info->phy_info[i].portinfo = port_info;
3130 port_info->phy_info[i].handle =
3131 le16_to_cpu(expander_data->DevHandle);
3132 port_info->phy_info[i].identify.sas_address =
3133 le64_to_cpu(sas_address);
3134 port_info->phy_info[i].identify.handle_parent =
3135 le16_to_cpu(expander_data->ParentDevHandle);
3136 }
3137
3138 mutex_lock(&ioc->sas_topology_mutex);
3139 list_add_tail(&port_info->list, &ioc->sas_topology);
3140 mutex_unlock(&ioc->sas_topology_mutex);
3141
3142 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3143 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3144 (unsigned long long)sas_address);
3145
3146 mptsas_expander_refresh(ioc, port_info);
3147}
3148
3149/**
3150 * mptsas_delete_expander_siblings - remove siblings attached to expander
3151 * @ioc: Pointer to MPT_ADAPTER structure
3152 * @parent: the parent port_info object
3153 * @expander: the expander port_info object
3154 **/
3155static void
3156mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3157 *parent, struct mptsas_portinfo *expander)
3158{
3159 struct mptsas_phyinfo *phy_info;
3160 struct mptsas_portinfo *port_info;
3161 struct sas_rphy *rphy;
3162 int i;
3163
3164 phy_info = expander->phy_info;
3165 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3166 rphy = mptsas_get_rphy(phy_info);
3167 if (!rphy)
3168 continue;
3169 if (rphy->identify.device_type == SAS_END_DEVICE)
3170 mptsas_del_end_device(ioc, phy_info);
3171 }
3172
3173 phy_info = expander->phy_info;
3174 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3175 rphy = mptsas_get_rphy(phy_info);
3176 if (!rphy)
3177 continue;
3178 if (rphy->identify.device_type ==
3179 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3180 rphy->identify.device_type ==
3181 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3182 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3183 rphy->identify.sas_address);
3184 if (!port_info)
3185 continue;
3186 if (port_info == parent) /* backlink rphy */
3187 continue;
3188 /*
3189 Delete this expander even if the expdevpage is exists
3190 because the parent expander is already deleted
3191 */
3192 mptsas_expander_delete(ioc, port_info, 1);
3193 }
3194 }
3195}
3196
3197
3198/**
3199 * mptsas_expander_delete - remove this expander
3200 * @ioc: Pointer to MPT_ADAPTER structure
3201 * @port_info: expander port_info struct
3202 * @force: Flag to forcefully delete the expander
3203 *
3204 **/
3205
3206static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3207 struct mptsas_portinfo *port_info, u8 force)
3208{
3209
3210 struct mptsas_portinfo *parent;
3211 int i;
3212 u64 expander_sas_address;
3213 struct mptsas_phyinfo *phy_info;
3214 struct mptsas_portinfo buffer;
3215 struct mptsas_portinfo_details *port_details;
3216 struct sas_port *port;
3217
3218 if (!port_info)
3219 return;
3220
3221 /* see if expander is still there before deleting */
3222 mptsas_sas_expander_pg0(ioc, &buffer,
3223 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3224 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3225 port_info->phy_info[0].identify.handle);
3226
3227 if (buffer.num_phys) {
3228 kfree(buffer.phy_info);
3229 if (!force)
3230 return;
3231 }
3232
3233
3234 /*
3235 * Obtain the port_info instance to the parent port
3236 */
3237 port_details = NULL;
3238 expander_sas_address =
3239 port_info->phy_info[0].identify.sas_address;
3240 parent = mptsas_find_portinfo_by_handle(ioc,
3241 port_info->phy_info[0].identify.handle_parent);
3242 mptsas_delete_expander_siblings(ioc, parent, port_info);
3243 if (!parent)
3244 goto out;
3245
3246 /*
3247 * Delete rphys in the parent that point
3248 * to this expander.
3249 */
3250 phy_info = parent->phy_info;
3251 port = NULL;
3252 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3253 if (!phy_info->phy)
3254 continue;
3255 if (phy_info->attached.sas_address !=
3256 expander_sas_address)
3257 continue;
3258 if (!port) {
3259 port = mptsas_get_port(phy_info);
3260 port_details = phy_info->port_details;
3261 }
3262 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3263 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3264 phy_info->phy_id, phy_info->phy);
3265 sas_port_delete_phy(port, phy_info->phy);
3266 }
3267 if (port) {
3268 dev_printk(KERN_DEBUG, &port->dev,
3269 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3270 ioc->name, port->port_identifier,
3271 (unsigned long long)expander_sas_address);
3272 sas_port_delete(port);
3273 mptsas_port_delete(ioc, port_details);
3274 }
3275 out:
3276
3277 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3278 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3279 (unsigned long long)expander_sas_address);
3280
3281 /*
3282 * free link
3283 */
3284 list_del(&port_info->list);
3285 kfree(port_info->phy_info);
3286 kfree(port_info);
3287}
3288
3289
3290/**
3291 * mptsas_send_expander_event - expanders events
3292 * @ioc: Pointer to MPT_ADAPTER structure
3293 * @expander_data: event data
3294 *
3295 *
3296 * This function handles adding, removing, and refreshing
3297 * device handles within the expander objects.
3298 */
3299static void
3300mptsas_send_expander_event(struct fw_event_work *fw_event)
3301{
3302 MPT_ADAPTER *ioc;
3303 MpiEventDataSasExpanderStatusChange_t *expander_data;
3304 struct mptsas_portinfo *port_info;
3305 __le64 sas_address;
3306 int i;
3307
3308 ioc = fw_event->ioc;
3309 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3310 fw_event->event_data;
3311 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3312 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3313
3314 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3315 if (port_info) {
3316 for (i = 0; i < port_info->num_phys; i++) {
3317 port_info->phy_info[i].portinfo = port_info;
3318 port_info->phy_info[i].handle =
3319 le16_to_cpu(expander_data->DevHandle);
3320 port_info->phy_info[i].identify.sas_address =
3321 le64_to_cpu(sas_address);
3322 port_info->phy_info[i].identify.handle_parent =
3323 le16_to_cpu(expander_data->ParentDevHandle);
3324 }
3325 mptsas_expander_refresh(ioc, port_info);
3326 } else if (!port_info && expander_data->NumPhys)
3327 mptsas_expander_event_add(ioc, expander_data);
3328 } else if (expander_data->ReasonCode ==
3329 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3330 mptsas_expander_delete(ioc, port_info, 0);
3331
3332 mptsas_free_fw_event(ioc, fw_event);
3333}
3334
3335
3336/**
3337 * mptsas_expander_add -
3338 * @ioc: Pointer to MPT_ADAPTER structure
3339 * @handle:
3340 *
3341 */
3342struct mptsas_portinfo *
3343mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3344{
3345 struct mptsas_portinfo buffer, *port_info;
3346 int i;
3347
3348 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3349 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3350 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3351 return NULL;
3352
3353 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3354 if (!port_info) {
3355 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3356 "%s: exit at line=%d\n", ioc->name,
3357 __func__, __LINE__));
3358 return NULL;
3359 }
3360 port_info->num_phys = buffer.num_phys;
3361 port_info->phy_info = buffer.phy_info;
3362 for (i = 0; i < port_info->num_phys; i++)
3363 port_info->phy_info[i].portinfo = port_info;
3364 mutex_lock(&ioc->sas_topology_mutex);
3365 list_add_tail(&port_info->list, &ioc->sas_topology);
3366 mutex_unlock(&ioc->sas_topology_mutex);
3367 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3368 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3369 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3370 mptsas_expander_refresh(ioc, port_info);
3371 return port_info;
3372}
3373
3374static void
3375mptsas_send_link_status_event(struct fw_event_work *fw_event)
3376{
3377 MPT_ADAPTER *ioc;
3378 MpiEventDataSasPhyLinkStatus_t *link_data;
3379 struct mptsas_portinfo *port_info;
3380 struct mptsas_phyinfo *phy_info = NULL;
3381 __le64 sas_address;
3382 u8 phy_num;
3383 u8 link_rate;
3384
3385 ioc = fw_event->ioc;
3386 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3387
3388 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3389 sas_address = le64_to_cpu(sas_address);
3390 link_rate = link_data->LinkRates >> 4;
3391 phy_num = link_data->PhyNum;
3392
3393 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3394 if (port_info) {
3395 phy_info = &port_info->phy_info[phy_num];
3396 if (phy_info)
3397 phy_info->negotiated_link_rate = link_rate;
3398 }
3399
3400 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3401 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3402
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303403 if (!port_info) {
3404 if (ioc->old_sas_discovery_protocal) {
3405 port_info = mptsas_expander_add(ioc,
3406 le16_to_cpu(link_data->DevHandle));
3407 if (port_info)
3408 goto out;
3409 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303410 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303411 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303412
3413 if (port_info == ioc->hba_port_info)
3414 mptsas_probe_hba_phys(ioc);
3415 else
3416 mptsas_expander_refresh(ioc, port_info);
3417 } else if (phy_info && phy_info->phy) {
3418 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3419 phy_info->phy->negotiated_linkrate =
3420 SAS_PHY_DISABLED;
3421 else if (link_rate ==
3422 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3423 phy_info->phy->negotiated_linkrate =
3424 SAS_LINK_RATE_FAILED;
3425 else
3426 phy_info->phy->negotiated_linkrate =
3427 SAS_LINK_RATE_UNKNOWN;
3428 }
3429 out:
3430 mptsas_free_fw_event(ioc, fw_event);
3431}
3432
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303433static void
3434mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3435{
3436 struct mptsas_portinfo buffer, *port_info;
3437 struct mptsas_device_info *sas_info;
3438 struct mptsas_devinfo sas_device;
3439 u32 handle;
3440 VirtTarget *vtarget = NULL;
3441 struct mptsas_phyinfo *phy_info;
3442 u8 found_expander;
3443 int retval, retry_count;
3444 unsigned long flags;
3445
3446 mpt_findImVolumes(ioc);
3447
3448 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3449 if (ioc->ioc_reset_in_progress) {
3450 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3451 "%s: exiting due to a parallel reset \n", ioc->name,
3452 __func__));
3453 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3454 return;
3455 }
3456 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3457
3458 /* devices, logical volumes */
3459 mutex_lock(&ioc->sas_device_info_mutex);
3460 redo_device_scan:
3461 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303462 if (sas_info->is_cached)
3463 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303464 if (!sas_info->is_logical_volume) {
3465 sas_device.handle = 0;
3466 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303467retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303468 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303469 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3470 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3471 (sas_info->fw.channel << 8) +
3472 sas_info->fw.id);
3473
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303474 if (sas_device.handle)
3475 continue;
3476 if (retval == -EBUSY) {
3477 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3478 if (ioc->ioc_reset_in_progress) {
3479 dfailprintk(ioc,
3480 printk(MYIOC_s_DEBUG_FMT
3481 "%s: exiting due to reset\n",
3482 ioc->name, __func__));
3483 spin_unlock_irqrestore
3484 (&ioc->taskmgmt_lock, flags);
3485 mutex_unlock(&ioc->
3486 sas_device_info_mutex);
3487 return;
3488 }
3489 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3490 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303491 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303492
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303493 if (retval && (retval != -ENODEV)) {
3494 if (retry_count < 10) {
3495 retry_count++;
3496 goto retry_page;
3497 } else {
3498 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3499 "%s: Config page retry exceeded retry "
3500 "count deleting device 0x%llx\n",
3501 ioc->name, __func__,
3502 sas_info->sas_address));
3503 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303504 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303505
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303506 /* delete device */
3507 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303508 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303509
3510 if (vtarget)
3511 vtarget->deleted = 1;
3512
3513 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3514 sas_info->sas_address);
3515
3516 if (phy_info) {
3517 mptsas_del_end_device(ioc, phy_info);
3518 goto redo_device_scan;
3519 }
3520 } else
3521 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303522 }
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303523 mutex_lock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303524
3525 /* expanders */
3526 mutex_lock(&ioc->sas_topology_mutex);
3527 redo_expander_scan:
3528 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3529
3530 if (port_info->phy_info &&
3531 (!(port_info->phy_info[0].identify.device_info &
3532 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3533 continue;
3534 found_expander = 0;
3535 handle = 0xFFFF;
3536 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3537 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3538 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3539 !found_expander) {
3540
3541 handle = buffer.phy_info[0].handle;
3542 if (buffer.phy_info[0].identify.sas_address ==
3543 port_info->phy_info[0].identify.sas_address) {
3544 found_expander = 1;
3545 }
3546 kfree(buffer.phy_info);
3547 }
3548
3549 if (!found_expander) {
3550 mptsas_expander_delete(ioc, port_info, 0);
3551 goto redo_expander_scan;
3552 }
3553 }
3554 mutex_lock(&ioc->sas_topology_mutex);
3555}
3556
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303557/**
3558 * mptsas_probe_expanders - adding expanders
3559 * @ioc: Pointer to MPT_ADAPTER structure
3560 *
3561 **/
3562static void
3563mptsas_probe_expanders(MPT_ADAPTER *ioc)
3564{
3565 struct mptsas_portinfo buffer, *port_info;
3566 u32 handle;
3567 int i;
3568
3569 handle = 0xFFFF;
3570 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3571 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3572 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3573
3574 handle = buffer.phy_info[0].handle;
3575 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3576 buffer.phy_info[0].identify.sas_address);
3577
3578 if (port_info) {
3579 /* refreshing handles */
3580 for (i = 0; i < buffer.num_phys; i++) {
3581 port_info->phy_info[i].handle = handle;
3582 port_info->phy_info[i].identify.handle_parent =
3583 buffer.phy_info[0].identify.handle_parent;
3584 }
3585 mptsas_expander_refresh(ioc, port_info);
3586 kfree(buffer.phy_info);
3587 continue;
3588 }
3589
3590 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3591 if (!port_info) {
3592 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3593 "%s: exit at line=%d\n", ioc->name,
3594 __func__, __LINE__));
3595 return;
3596 }
3597 port_info->num_phys = buffer.num_phys;
3598 port_info->phy_info = buffer.phy_info;
3599 for (i = 0; i < port_info->num_phys; i++)
3600 port_info->phy_info[i].portinfo = port_info;
3601 mutex_lock(&ioc->sas_topology_mutex);
3602 list_add_tail(&port_info->list, &ioc->sas_topology);
3603 mutex_unlock(&ioc->sas_topology_mutex);
3604 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3605 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3606 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3607 mptsas_expander_refresh(ioc, port_info);
3608 }
3609}
3610
3611static void
3612mptsas_probe_devices(MPT_ADAPTER *ioc)
3613{
3614 u16 handle;
3615 struct mptsas_devinfo sas_device;
3616 struct mptsas_phyinfo *phy_info;
3617
3618 handle = 0xFFFF;
3619 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3620 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3621
3622 handle = sas_device.handle;
3623
3624 if ((sas_device.device_info &
3625 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3626 MPI_SAS_DEVICE_INFO_STP_TARGET |
3627 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3628 continue;
3629
3630 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3631 if (!phy_info)
3632 continue;
3633
3634 if (mptsas_get_rphy(phy_info))
3635 continue;
3636
3637 mptsas_add_end_device(ioc, phy_info);
3638 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003639}
3640
Kashyap, Desai2f187862009-05-29 16:52:37 +05303641/**
3642 * mptsas_scan_sas_topology -
3643 * @ioc: Pointer to MPT_ADAPTER structure
3644 * @sas_address:
3645 *
3646 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003647static void
3648mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3649{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303650 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003651 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003652
Moore, Erice6b2d762006-03-14 09:14:24 -07003653 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303654 mptsas_probe_expanders(ioc);
3655 mptsas_probe_devices(ioc);
3656
Moore, Ericf44e5462006-03-14 09:14:21 -07003657 /*
3658 Reporting RAID volumes.
3659 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303660 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3661 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3662 return;
Eric Moore793955f2007-01-29 09:42:20 -07003663 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303664 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3665 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3666 if (sdev) {
3667 scsi_device_put(sdev);
3668 continue;
3669 }
3670 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3671 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3672 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003673 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003674 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3675 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003676}
3677
Kashyap, Desai57e98512009-05-29 16:55:09 +05303678
3679static void
3680mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3681{
3682 MPT_ADAPTER *ioc;
3683 EventDataQueueFull_t *qfull_data;
3684 struct mptsas_device_info *sas_info;
3685 struct scsi_device *sdev;
3686 int depth;
3687 int id = -1;
3688 int channel = -1;
3689 int fw_id, fw_channel;
3690 u16 current_depth;
3691
3692
3693 ioc = fw_event->ioc;
3694 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3695 fw_id = qfull_data->TargetID;
3696 fw_channel = qfull_data->Bus;
3697 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3698
3699 /* if hidden raid component, look for the volume id */
3700 mutex_lock(&ioc->sas_device_info_mutex);
3701 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3702 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3703 list) {
3704 if (sas_info->is_cached ||
3705 sas_info->is_logical_volume)
3706 continue;
3707 if (sas_info->is_hidden_raid_component &&
3708 (sas_info->fw.channel == fw_channel &&
3709 sas_info->fw.id == fw_id)) {
3710 id = sas_info->volume_id;
3711 channel = MPTSAS_RAID_CHANNEL;
3712 goto out;
3713 }
3714 }
3715 } else {
3716 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3717 list) {
3718 if (sas_info->is_cached ||
3719 sas_info->is_hidden_raid_component ||
3720 sas_info->is_logical_volume)
3721 continue;
3722 if (sas_info->fw.channel == fw_channel &&
3723 sas_info->fw.id == fw_id) {
3724 id = sas_info->os.id;
3725 channel = sas_info->os.channel;
3726 goto out;
3727 }
3728 }
3729
3730 }
3731
3732 out:
3733 mutex_unlock(&ioc->sas_device_info_mutex);
3734
3735 if (id != -1) {
3736 shost_for_each_device(sdev, ioc->sh) {
3737 if (sdev->id == id && sdev->channel == channel) {
3738 if (current_depth > sdev->queue_depth) {
3739 sdev_printk(KERN_INFO, sdev,
3740 "strange observation, the queue "
3741 "depth is (%d) meanwhile fw queue "
3742 "depth (%d)\n", sdev->queue_depth,
3743 current_depth);
3744 continue;
3745 }
3746 depth = scsi_track_queue_full(sdev,
3747 current_depth - 1);
3748 if (depth > 0)
3749 sdev_printk(KERN_INFO, sdev,
3750 "Queue depth reduced to (%d)\n",
3751 depth);
3752 else if (depth < 0)
3753 sdev_printk(KERN_INFO, sdev,
3754 "Tagged Command Queueing is being "
3755 "disabled\n");
3756 else if (depth == 0)
3757 sdev_printk(KERN_INFO, sdev,
3758 "Queue depth not changed yet\n");
3759 }
3760 }
3761 }
3762
3763 mptsas_free_fw_event(ioc, fw_event);
3764}
3765
3766
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003767static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003768mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003769{
3770 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003771 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003772 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003773
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003774 mutex_lock(&ioc->sas_topology_mutex);
3775 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3776 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003777 if (!mptsas_is_end_device(
3778 &port_info->phy_info[i].attached))
3779 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003780 if (port_info->phy_info[i].attached.sas_address
3781 != sas_address)
3782 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003783 phy_info = &port_info->phy_info[i];
3784 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003785 }
3786 }
3787 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003788 return phy_info;
3789}
3790
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303791/**
3792 * mptsas_find_phyinfo_by_phys_disk_num -
3793 * @ioc: Pointer to MPT_ADAPTER structure
3794 * @phys_disk_num:
3795 * @channel:
3796 * @id:
3797 *
3798 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003799static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303800mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3801 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003802{
Eric Mooreb506ade2007-01-29 09:45:37 -07003803 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303804 struct mptsas_portinfo *port_info;
3805 RaidPhysDiskPage1_t *phys_disk = NULL;
3806 int num_paths;
3807 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003808 int i;
3809
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303810 phy_info = NULL;
3811 if (!ioc->raid_data.pIocPg3)
3812 return NULL;
3813 /* dual port support */
3814 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
3815 if (!num_paths)
3816 goto out;
3817 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
3818 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
3819 if (!phys_disk)
3820 goto out;
3821 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
3822 for (i = 0; i < num_paths; i++) {
3823 if ((phys_disk->Path[i].Flags & 1) != 0)
3824 /* entry no longer valid */
3825 continue;
3826 if ((id == phys_disk->Path[i].PhysDiskID) &&
3827 (channel == phys_disk->Path[i].PhysDiskBus)) {
3828 memcpy(&sas_address, &phys_disk->Path[i].WWID,
3829 sizeof(u64));
3830 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3831 sas_address);
3832 goto out;
3833 }
3834 }
3835
3836 out:
3837 kfree(phys_disk);
3838 if (phy_info)
3839 return phy_info;
3840
3841 /*
3842 * Extra code to handle RAID0 case, where the sas_address is not updated
3843 * in phys_disk_page_1 when hotswapped
3844 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003845 mutex_lock(&ioc->sas_topology_mutex);
3846 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303847 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07003848 if (!mptsas_is_end_device(
3849 &port_info->phy_info[i].attached))
3850 continue;
3851 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3852 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303853 if ((port_info->phy_info[i].attached.phys_disk_num ==
3854 phys_disk_num) &&
3855 (port_info->phy_info[i].attached.id == id) &&
3856 (port_info->phy_info[i].attached.channel ==
3857 channel))
3858 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06003859 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003860 }
3861 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003862 return phy_info;
3863}
3864
3865static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003866mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3867{
Eric Mooref99be432007-01-04 20:46:54 -07003868 int rc;
3869
Moore, Ericf44e5462006-03-14 09:14:21 -07003870 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003871 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003872}
3873
3874static void
3875mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3876{
3877 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3878 mptsas_reprobe_lun);
3879}
3880
Eric Mooreb506ade2007-01-29 09:45:37 -07003881static void
3882mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3883{
3884 CONFIGPARMS cfg;
3885 ConfigPageHeader_t hdr;
3886 dma_addr_t dma_handle;
3887 pRaidVolumePage0_t buffer = NULL;
3888 RaidPhysDiskPage0_t phys_disk;
3889 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303890 struct mptsas_phyinfo *phy_info;
3891 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003892
3893 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3894 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3895 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3896 cfg.pageAddr = (channel << 8) + id;
3897 cfg.cfghdr.hdr = &hdr;
3898 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3899
3900 if (mpt_config(ioc, &cfg) != 0)
3901 goto out;
3902
3903 if (!hdr.PageLength)
3904 goto out;
3905
3906 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3907 &dma_handle);
3908
3909 if (!buffer)
3910 goto out;
3911
3912 cfg.physAddr = dma_handle;
3913 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3914
3915 if (mpt_config(ioc, &cfg) != 0)
3916 goto out;
3917
3918 if (!(buffer->VolumeStatus.Flags &
3919 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3920 goto out;
3921
3922 if (!buffer->NumPhysDisks)
3923 goto out;
3924
3925 for (i = 0; i < buffer->NumPhysDisks; i++) {
3926
3927 if (mpt_raid_phys_disk_pg0(ioc,
3928 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3929 continue;
3930
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303931 if (mptsas_sas_device_pg0(ioc, &sas_device,
3932 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3933 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3934 (phys_disk.PhysDiskBus << 8) +
3935 phys_disk.PhysDiskID))
3936 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003937
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303938 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3939 sas_device.sas_address);
3940 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003941 }
3942
3943 out:
3944 if (buffer)
3945 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3946 dma_handle);
3947}
Moore, Erice6b2d762006-03-14 09:14:24 -07003948/*
3949 * Work queue thread to handle SAS hotplug events
3950 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003951static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303952mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3953 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003954{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003955 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003956 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003957 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003958 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303959 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003960
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303961 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003962
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303963 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003964
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303965 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003966 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003967
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303968 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3969 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3970 hot_plug_info->id) {
3971 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3972 "to add hidden disk - target_id matchs "
3973 "volume_id\n", ioc->name);
3974 mptsas_free_fw_event(ioc, fw_event);
3975 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003976 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003977 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303978 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003979
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003980 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303981 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3982 mptsas_sas_device_pg0(ioc, &sas_device,
3983 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3984 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3985 (hot_plug_info->channel << 8) +
3986 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003987
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303988 if (!sas_device.handle)
3989 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003990
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303991 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3992 if (!phy_info)
3993 break;
3994
3995 if (mptsas_get_rphy(phy_info))
3996 break;
3997
3998 mptsas_add_end_device(ioc, phy_info);
3999 break;
4000
4001 case MPTSAS_DEL_DEVICE:
4002 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4003 hot_plug_info->sas_address);
4004 mptsas_del_end_device(ioc, phy_info);
4005 break;
4006
4007 case MPTSAS_DEL_PHYSDISK:
4008
4009 mpt_findImVolumes(ioc);
4010
4011 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304012 ioc, hot_plug_info->phys_disk_num,
4013 hot_plug_info->channel,
4014 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304015 mptsas_del_end_device(ioc, phy_info);
4016 break;
4017
4018 case MPTSAS_ADD_PHYSDISK_REPROBE:
4019
Christoph Hellwige3094442006-02-16 13:25:36 +01004020 if (mptsas_sas_device_pg0(ioc, &sas_device,
4021 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004022 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304023 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4024 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4025 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4026 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004027 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004028 }
4029
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304030 phy_info = mptsas_find_phyinfo_by_sas_address(
4031 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004032
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304033 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304034 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304035 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4036 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004037 break;
4038 }
4039
4040 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304041 if (!starget) {
4042 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4043 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4044 __func__, hot_plug_info->id, __LINE__));
4045 break;
4046 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004047
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304048 vtarget = starget->hostdata;
4049 if (!vtarget) {
4050 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4051 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4052 __func__, hot_plug_info->id, __LINE__));
4053 break;
4054 }
Eric Moore547f9a22006-06-27 14:42:12 -06004055
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304056 mpt_findImVolumes(ioc);
4057
4058 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4059 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4060 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4061 hot_plug_info->phys_disk_num, (unsigned long long)
4062 sas_device.sas_address);
4063
4064 vtarget->id = hot_plug_info->phys_disk_num;
4065 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4066 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4067 mptsas_reprobe_target(starget, 1);
4068 break;
4069
4070 case MPTSAS_DEL_PHYSDISK_REPROBE:
4071
4072 if (mptsas_sas_device_pg0(ioc, &sas_device,
4073 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4074 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4075 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304076 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304077 "%s: fw_id=%d exit at line=%d\n",
4078 ioc->name, __func__,
4079 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004080 break;
4081 }
4082
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304083 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4084 sas_device.sas_address);
4085 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304086 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304087 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4088 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004089 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004090 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004091
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304092 starget = mptsas_get_starget(phy_info);
4093 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304094 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304095 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4096 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004097 break;
4098 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004099
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304100 vtarget = starget->hostdata;
4101 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304102 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304103 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4104 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004105 break;
4106 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304107
4108 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4109 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4110 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4111 __func__, hot_plug_info->id, __LINE__));
4112 break;
4113 }
4114
4115 mpt_findImVolumes(ioc);
4116
4117 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4118 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4119 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4120 hot_plug_info->phys_disk_num, (unsigned long long)
4121 sas_device.sas_address);
4122
4123 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4124 vtarget->id = hot_plug_info->id;
4125 phy_info->attached.phys_disk_num = ~0;
4126 mptsas_reprobe_target(starget, 0);
4127 mptsas_add_device_component_by_fw(ioc,
4128 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004129 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304130
Moore, Ericc73787ee2006-01-26 16:20:06 -07004131 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304132
Moore, Ericc73787ee2006-01-26 16:20:06 -07004133 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304134 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4135 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4136 hot_plug_info->id);
4137 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4138 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004139 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304140
Moore, Ericc73787ee2006-01-26 16:20:06 -07004141 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304142
Moore, Ericc73787ee2006-01-26 16:20:06 -07004143 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304144 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4145 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4146 hot_plug_info->id);
4147 scsi_remove_device(hot_plug_info->sdev);
4148 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004149 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304150
Eric Mooreb506ade2007-01-29 09:45:37 -07004151 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304152
4153 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004154 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304155 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004156 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304157
Moore, Ericbd23e942006-04-17 12:43:04 -06004158 default:
4159 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004160 }
4161
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304162 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004163}
4164
4165static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304166mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004167{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304168 MPT_ADAPTER *ioc;
4169 struct mptsas_hotplug_event hot_plug_info;
4170 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4171 u32 device_info;
4172 u64 sas_address;
4173
4174 ioc = fw_event->ioc;
4175 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4176 fw_event->event_data;
4177 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004178
4179 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304180 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4181 MPI_SAS_DEVICE_INFO_STP_TARGET |
4182 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4183 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004184 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304185 }
4186
4187 if (sas_event_data->ReasonCode ==
4188 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4189 mptbase_sas_persist_operation(ioc,
4190 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4191 mptsas_free_fw_event(ioc, fw_event);
4192 return;
4193 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004194
Moore, Eric4b766472006-03-14 09:14:12 -07004195 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004196 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004197 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304198 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4199 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4200 hot_plug_info.channel = sas_event_data->Bus;
4201 hot_plug_info.id = sas_event_data->TargetID;
4202 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004203 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304204 sizeof(u64));
4205 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4206 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004207 if (sas_event_data->ReasonCode &
4208 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304209 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004210 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304211 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4212 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004213 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304214
Moore, Eric4b766472006-03-14 09:14:12 -07004215 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304216 mptbase_sas_persist_operation(ioc,
4217 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4218 mptsas_free_fw_event(ioc, fw_event);
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_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304222 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004223 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304224 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004225 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304226 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004227 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004228 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004229}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304230
Moore, Ericc73787ee2006-01-26 16:20:06 -07004231static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304232mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004233{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304234 MPT_ADAPTER *ioc;
4235 EVENT_DATA_RAID *raid_event_data;
4236 struct mptsas_hotplug_event hot_plug_info;
4237 int status;
4238 int state;
4239 struct scsi_device *sdev = NULL;
4240 VirtDevice *vdevice = NULL;
4241 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004242
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304243 ioc = fw_event->ioc;
4244 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4245 status = le32_to_cpu(raid_event_data->SettingsStatus);
4246 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004247
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304248 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4249 hot_plug_info.id = raid_event_data->VolumeID;
4250 hot_plug_info.channel = raid_event_data->VolumeBus;
4251 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4252
4253 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4254 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4255 raid_event_data->ReasonCode ==
4256 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4257 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4258 hot_plug_info.id, 0);
4259 hot_plug_info.sdev = sdev;
4260 if (sdev)
4261 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004262 }
4263
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304264 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4265 "ReasonCode=%02x\n", ioc->name, __func__,
4266 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004267
4268 switch (raid_event_data->ReasonCode) {
4269 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304270 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004271 break;
4272 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304273 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004274 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004275 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4276 switch (state) {
4277 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004278 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304279 mpt_raid_phys_disk_pg0(ioc,
4280 raid_event_data->PhysDiskNum, &phys_disk);
4281 hot_plug_info.id = phys_disk.PhysDiskID;
4282 hot_plug_info.channel = phys_disk.PhysDiskBus;
4283 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004284 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304285 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004286 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004287 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4288 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4289 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304290 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004291 break;
4292 default:
4293 break;
4294 }
4295 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004296 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304297 if (!sdev)
4298 break;
4299 vdevice->vtarget->deleted = 1; /* block IO */
4300 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004301 break;
4302 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304303 if (sdev) {
4304 scsi_device_put(sdev);
4305 break;
4306 }
4307 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004308 break;
4309 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304310 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4311 if (!sdev)
4312 break;
4313 vdevice->vtarget->deleted = 1; /* block IO */
4314 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4315 break;
4316 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004317 switch (state) {
4318 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4319 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304320 if (!sdev)
4321 break;
4322 vdevice->vtarget->deleted = 1; /* block IO */
4323 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004324 break;
4325 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4326 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304327 if (sdev) {
4328 scsi_device_put(sdev);
4329 break;
4330 }
4331 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004332 break;
4333 default:
4334 break;
4335 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004336 break;
4337 default:
4338 break;
4339 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304340
4341 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4342 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4343 else
4344 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004345}
4346
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304347/**
4348 * mptsas_issue_tm - send mptsas internal tm request
4349 * @ioc: Pointer to MPT_ADAPTER structure
4350 * @type: Task Management type
4351 * @channel: channel number for task management
4352 * @id: Logical Target ID for reset (if appropriate)
4353 * @lun: Logical unit for reset (if appropriate)
4354 * @task_context: Context for the task to be aborted
4355 * @timeout: timeout for task management control
4356 *
4357 * return 0 on success and -1 on failure:
4358 *
4359 */
4360static int
4361mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4362 int task_context, ulong timeout, u8 *issue_reset)
4363{
4364 MPT_FRAME_HDR *mf;
4365 SCSITaskMgmt_t *pScsiTm;
4366 int retval;
4367 unsigned long timeleft;
4368
4369 *issue_reset = 0;
4370 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4371 if (mf == NULL) {
4372 retval = -1; /* return failure */
4373 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4374 "msg frames!!\n", ioc->name));
4375 goto out;
4376 }
4377
4378 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4379 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4380 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4381 type, timeout, channel, id, (unsigned long long)lun,
4382 task_context));
4383
4384 pScsiTm = (SCSITaskMgmt_t *) mf;
4385 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4386 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4387 pScsiTm->TaskType = type;
4388 pScsiTm->MsgFlags = 0;
4389 pScsiTm->TargetID = id;
4390 pScsiTm->Bus = channel;
4391 pScsiTm->ChainOffset = 0;
4392 pScsiTm->Reserved = 0;
4393 pScsiTm->Reserved1 = 0;
4394 pScsiTm->TaskMsgContext = task_context;
4395 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4396
4397 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4398 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4399 retval = 0;
4400 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4401
4402 /* Now wait for the command to complete */
4403 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4404 timeout*HZ);
4405 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4406 retval = -1; /* return failure */
4407 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4408 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4409 mpt_free_msg_frame(ioc, mf);
4410 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4411 goto out;
4412 *issue_reset = 1;
4413 goto out;
4414 }
4415
4416 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4417 retval = -1; /* return failure */
4418 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4419 "TaskMgmt request: failed with no reply\n", ioc->name));
4420 goto out;
4421 }
4422
4423 out:
4424 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4425 return retval;
4426}
4427
4428/**
4429 * mptsas_broadcast_primative_work - Handle broadcast primitives
4430 * @work: work queue payload containing info describing the event
4431 *
4432 * this will be handled in workqueue context.
4433 */
4434static void
4435mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4436{
4437 MPT_ADAPTER *ioc = fw_event->ioc;
4438 MPT_FRAME_HDR *mf;
4439 VirtDevice *vdevice;
4440 int ii;
4441 struct scsi_cmnd *sc;
4442 SCSITaskMgmtReply_t *pScsiTmReply;
4443 u8 issue_reset;
4444 int task_context;
4445 u8 channel, id;
4446 int lun;
4447 u32 termination_count;
4448 u32 query_count;
4449
4450 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4451 "%s - enter\n", ioc->name, __func__));
4452
4453 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4454 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4455 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4456 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4457 return;
4458 }
4459
4460 issue_reset = 0;
4461 termination_count = 0;
4462 query_count = 0;
4463 mpt_findImVolumes(ioc);
4464 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4465
4466 for (ii = 0; ii < ioc->req_depth; ii++) {
4467 if (ioc->fw_events_off)
4468 goto out;
4469 sc = mptscsih_get_scsi_lookup(ioc, ii);
4470 if (!sc)
4471 continue;
4472 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4473 if (!mf)
4474 continue;
4475 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4476 vdevice = sc->device->hostdata;
4477 if (!vdevice || !vdevice->vtarget)
4478 continue;
4479 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4480 continue; /* skip hidden raid components */
4481 if (vdevice->vtarget->raidVolume)
4482 continue; /* skip hidden raid components */
4483 channel = vdevice->vtarget->channel;
4484 id = vdevice->vtarget->id;
4485 lun = vdevice->lun;
4486 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4487 channel, id, (u64)lun, task_context, 30, &issue_reset))
4488 goto out;
4489 query_count++;
4490 termination_count +=
4491 le32_to_cpu(pScsiTmReply->TerminationCount);
4492 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4493 (pScsiTmReply->ResponseCode ==
4494 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4495 pScsiTmReply->ResponseCode ==
4496 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4497 continue;
4498 if (mptsas_issue_tm(ioc,
4499 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4500 channel, id, (u64)lun, 0, 30, &issue_reset))
4501 goto out;
4502 termination_count +=
4503 le32_to_cpu(pScsiTmReply->TerminationCount);
4504 }
4505
4506 out:
4507 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4508 "%s - exit, query_count = %d termination_count = %d\n",
4509 ioc->name, __func__, query_count, termination_count));
4510
4511 ioc->broadcast_aen_busy = 0;
4512 mpt_clear_taskmgmt_in_progress_flag(ioc);
4513 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4514
4515 if (issue_reset) {
4516 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4517 ioc->name, __func__);
4518 mpt_HardResetHandler(ioc, CAN_SLEEP);
4519 }
4520 mptsas_free_fw_event(ioc, fw_event);
4521}
4522
Eric Mooreb506ade2007-01-29 09:45:37 -07004523/*
4524 * mptsas_send_ir2_event - handle exposing hidden disk when
4525 * an inactive raid volume is added
4526 *
4527 * @ioc: Pointer to MPT_ADAPTER structure
4528 * @ir2_data
4529 *
4530 */
4531static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304532mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004533{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304534 MPT_ADAPTER *ioc;
4535 struct mptsas_hotplug_event hot_plug_info;
4536 MPI_EVENT_DATA_IR2 *ir2_data;
4537 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304538 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004539
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304540 ioc = fw_event->ioc;
4541 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4542 reasonCode = ir2_data->ReasonCode;
4543
4544 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4545 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4546
4547 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4548 hot_plug_info.id = ir2_data->TargetID;
4549 hot_plug_info.channel = ir2_data->Bus;
4550 switch (reasonCode) {
4551 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4552 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4553 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304554 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4555 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4556 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4557 break;
4558 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4559 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4560 mpt_raid_phys_disk_pg0(ioc,
4561 ir2_data->PhysDiskNum, &phys_disk);
4562 hot_plug_info.id = phys_disk.PhysDiskID;
4563 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4564 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304565 default:
4566 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004567 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304568 }
4569 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4570}
Moore, Erice6b2d762006-03-14 09:14:24 -07004571
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004572static int
4573mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4574{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304575 u32 event = le32_to_cpu(reply->Event);
4576 int sz, event_data_sz;
4577 struct fw_event_work *fw_event;
4578 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004579
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304580 /* events turned off due to host reset or driver unloading */
4581 if (ioc->fw_events_off)
4582 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004583
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304584 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004585 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304586 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4587 {
4588 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4589 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4590 if (broadcast_event_data->Primitive !=
4591 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4592 return 0;
4593 if (ioc->broadcast_aen_busy)
4594 return 0;
4595 ioc->broadcast_aen_busy = 1;
4596 break;
4597 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004598 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304599 {
4600 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4601 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4602
4603 if (sas_event_data->ReasonCode ==
4604 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4605 mptsas_target_reset_queue(ioc, sas_event_data);
4606 return 0;
4607 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004608 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304609 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304610 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4611 {
4612 MpiEventDataSasExpanderStatusChange_t *expander_data =
4613 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4614
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304615 if (ioc->old_sas_discovery_protocal)
4616 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304617
4618 if (expander_data->ReasonCode ==
4619 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4620 ioc->device_missing_delay)
4621 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004622 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304623 }
4624 case MPI_EVENT_SAS_DISCOVERY:
4625 {
4626 u32 discovery_status;
4627 EventDataSasDiscovery_t *discovery_data =
4628 (EventDataSasDiscovery_t *)reply->Data;
4629
4630 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4631 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304632 if (ioc->old_sas_discovery_protocal && !discovery_status)
4633 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304634 return 0;
4635 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304636 case MPI_EVENT_INTEGRATED_RAID:
4637 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004638 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304639 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4640 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004641 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004642 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304643 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004644 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004645
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304646 event_data_sz = ((reply->MsgLength * 4) -
4647 offsetof(EventNotificationReply_t, Data));
4648 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4649 fw_event = kzalloc(sz, GFP_ATOMIC);
4650 if (!fw_event) {
4651 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4652 __func__, __LINE__);
4653 return 0;
4654 }
4655 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4656 fw_event->event = event;
4657 fw_event->ioc = ioc;
4658 mptsas_add_fw_event(ioc, fw_event, delay);
4659 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004660}
4661
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304662/* Delete a volume when no longer listed in ioc pg2
4663 */
4664static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4665{
4666 struct scsi_device *sdev;
4667 int i;
4668
4669 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4670 if (!sdev)
4671 return;
4672 if (!ioc->raid_data.pIocPg2)
4673 goto out;
4674 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4675 goto out;
4676 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4677 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4678 goto release_sdev;
4679 out:
4680 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4681 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4682 scsi_remove_device(sdev);
4683 release_sdev:
4684 scsi_device_put(sdev);
4685}
4686
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004687static int
4688mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4689{
4690 struct Scsi_Host *sh;
4691 MPT_SCSI_HOST *hd;
4692 MPT_ADAPTER *ioc;
4693 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004694 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004695 int numSGE = 0;
4696 int scale;
4697 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004698 int error=0;
4699 int r;
4700
4701 r = mpt_attach(pdev,id);
4702 if (r)
4703 return r;
4704
4705 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304706 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004707 ioc->DoneCtx = mptsasDoneCtx;
4708 ioc->TaskCtx = mptsasTaskCtx;
4709 ioc->InternalCtx = mptsasInternalCtx;
4710
4711 /* Added sanity check on readiness of the MPT adapter.
4712 */
4713 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4714 printk(MYIOC_s_WARN_FMT
4715 "Skipping because it's not operational!\n",
4716 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004717 error = -ENODEV;
4718 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004719 }
4720
4721 if (!ioc->active) {
4722 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4723 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004724 error = -ENODEV;
4725 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004726 }
4727
4728 /* Sanity check - ensure at least 1 port is INITIATOR capable
4729 */
4730 ioc_cap = 0;
4731 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4732 if (ioc->pfacts[ii].ProtocolFlags &
4733 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4734 ioc_cap++;
4735 }
4736
4737 if (!ioc_cap) {
4738 printk(MYIOC_s_WARN_FMT
4739 "Skipping ioc=%p because SCSI Initiator mode "
4740 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004741 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004742 }
4743
4744 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4745 if (!sh) {
4746 printk(MYIOC_s_WARN_FMT
4747 "Unable to register controller with SCSI subsystem\n",
4748 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004749 error = -1;
4750 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004751 }
4752
4753 spin_lock_irqsave(&ioc->FreeQlock, flags);
4754
4755 /* Attach the SCSI Host to the IOC structure
4756 */
4757 ioc->sh = sh;
4758
4759 sh->io_port = 0;
4760 sh->n_io_port = 0;
4761 sh->irq = 0;
4762
4763 /* set 16 byte cdb's */
4764 sh->max_cmd_len = 16;
4765
Eric Moore793955f2007-01-29 09:42:20 -07004766 sh->max_id = ioc->pfacts[0].PortSCSIID;
4767 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004768
4769 sh->transportt = mptsas_transport_template;
4770
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004771 /* Required entry.
4772 */
4773 sh->unique_id = ioc->id;
4774
4775 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004776 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004777 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004778 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004779 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004780
4781 /* Verify that we won't exceed the maximum
4782 * number of chain buffers
4783 * We can optimize: ZZ = req_sz/sizeof(SGE)
4784 * For 32bit SGE's:
4785 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4786 * + (req_sz - 64)/sizeof(SGE)
4787 * A slightly different algorithm is required for
4788 * 64bit SGEs.
4789 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304790 scale = ioc->req_sz/ioc->SGE_size;
4791 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004792 numSGE = (scale - 1) *
4793 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304794 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004795 } else {
4796 numSGE = 1 + (scale - 1) *
4797 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304798 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004799 }
4800
4801 if (numSGE < sh->sg_tablesize) {
4802 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304803 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004804 "Resetting sg_tablesize to %d from %d\n",
4805 ioc->name, numSGE, sh->sg_tablesize));
4806 sh->sg_tablesize = numSGE;
4807 }
4808
Eric Mooree7eae9f2007-09-29 10:15:59 -06004809 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004810 hd->ioc = ioc;
4811
4812 /* SCSI needs scsi_cmnd lookup table!
4813 * (with size equal to req_depth*PtrSz!)
4814 */
Eric Mooree8206382007-09-29 10:16:53 -06004815 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4816 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004817 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004818 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004819 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004820 }
Eric Mooree8206382007-09-29 10:16:53 -06004821 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004822
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304823 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004824 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004825
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004826 /* Clear the TM flags
4827 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004828 hd->abortSCpnt = NULL;
4829
4830 /* Clear the pointer used to store
4831 * single-threaded commands, i.e., those
4832 * issued during a bus scan, dv and
4833 * configuration pages.
4834 */
4835 hd->cmdPtr = NULL;
4836
4837 /* Initialize this SCSI Hosts' timers
4838 * To use, set the timer expires field
4839 * and add_timer
4840 */
4841 init_timer(&hd->timer);
4842 hd->timer.data = (unsigned long) hd;
4843 hd->timer.function = mptscsih_timer_expired;
4844
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004845 ioc->sas_data.ptClear = mpt_pt_clear;
4846
Eric Mooredf9e0622007-01-29 09:46:21 -07004847 hd->last_queue_full = 0;
4848 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304849 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4850 mutex_init(&ioc->sas_device_info_mutex);
4851
Eric Mooredf9e0622007-01-29 09:46:21 -07004852 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4853
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004854 if (ioc->sas_data.ptClear==1) {
4855 mptbase_sas_persist_operation(
4856 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4857 }
4858
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004859 error = scsi_add_host(sh, &ioc->pcidev->dev);
4860 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004861 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4862 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004863 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004864 }
4865
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304866 /* older firmware doesn't support expander events */
4867 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4868 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004869 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304870 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004871 return 0;
4872
Eric Moore547f9a22006-06-27 14:42:12 -06004873 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004874
4875 mptscsih_remove(pdev);
4876 return error;
4877}
4878
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304879void
4880mptsas_shutdown(struct pci_dev *pdev)
4881{
4882 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4883
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304884 mptsas_fw_event_off(ioc);
4885 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304886}
4887
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004888static void __devexit mptsas_remove(struct pci_dev *pdev)
4889{
4890 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4891 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004892 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004893
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304894 mptsas_shutdown(pdev);
4895
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304896 mptsas_del_device_components(ioc);
4897
Eric Mooreb506ade2007-01-29 09:45:37 -07004898 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004899 sas_remove_host(ioc->sh);
4900
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004901 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004902 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4903 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004904 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304905 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304906
Eric Moore547f9a22006-06-27 14:42:12 -06004907 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004908 kfree(p);
4909 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004910 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304911 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004912 mptscsih_remove(pdev);
4913}
4914
4915static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004916 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004917 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004918 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004919 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004920 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004921 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004922 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004923 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004924 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004925 PCI_ANY_ID, PCI_ANY_ID },
4926 {0} /* Terminating entry */
4927};
4928MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4929
4930
4931static struct pci_driver mptsas_driver = {
4932 .name = "mptsas",
4933 .id_table = mptsas_pci_table,
4934 .probe = mptsas_probe,
4935 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304936 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004937#ifdef CONFIG_PM
4938 .suspend = mptscsih_suspend,
4939 .resume = mptscsih_resume,
4940#endif
4941};
4942
4943static int __init
4944mptsas_init(void)
4945{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304946 int error;
4947
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004948 show_mptmod_ver(my_NAME, my_VERSION);
4949
4950 mptsas_transport_template =
4951 sas_attach_transport(&mptsas_transport_functions);
4952 if (!mptsas_transport_template)
4953 return -ENODEV;
4954
4955 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304956 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004957 mptsasInternalCtx =
4958 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004959 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304960 mptsasDeviceResetCtx =
4961 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004962
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304963 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4964 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004965
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304966 error = pci_register_driver(&mptsas_driver);
4967 if (error)
4968 sas_release_transport(mptsas_transport_template);
4969
4970 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004971}
4972
4973static void __exit
4974mptsas_exit(void)
4975{
4976 pci_unregister_driver(&mptsas_driver);
4977 sas_release_transport(mptsas_transport_template);
4978
4979 mpt_reset_deregister(mptsasDoneCtx);
4980 mpt_event_deregister(mptsasDoneCtx);
4981
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004982 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004983 mpt_deregister(mptsasInternalCtx);
4984 mpt_deregister(mptsasTaskCtx);
4985 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304986 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004987}
4988
4989module_init(mptsas_init);
4990module_exit(mptsas_exit);