blob: 55ff25244af44a1f2c51002ce8c78fe3b3b699e1 [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/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000639 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530640 * @ioc: Pointer to MPT_ADAPTER structure
641 * @channel: fw mapped id's
642 * @id:
643 *
644 **/
645static void
646mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
647 struct scsi_target *starget)
648{
649 CONFIGPARMS cfg;
650 ConfigPageHeader_t hdr;
651 dma_addr_t dma_handle;
652 pRaidVolumePage0_t buffer = NULL;
653 int i;
654 RaidPhysDiskPage0_t phys_disk;
655 struct mptsas_device_info *sas_info, *next;
656
657 memset(&cfg, 0 , sizeof(CONFIGPARMS));
658 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
659 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
660 /* assumption that all volumes on channel = 0 */
661 cfg.pageAddr = starget->id;
662 cfg.cfghdr.hdr = &hdr;
663 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
664 cfg.timeout = 10;
665
666 if (mpt_config(ioc, &cfg) != 0)
667 goto out;
668
669 if (!hdr.PageLength)
670 goto out;
671
672 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
673 &dma_handle);
674
675 if (!buffer)
676 goto out;
677
678 cfg.physAddr = dma_handle;
679 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
680
681 if (mpt_config(ioc, &cfg) != 0)
682 goto out;
683
684 if (!buffer->NumPhysDisks)
685 goto out;
686
687 /*
688 * Adding entry for hidden components
689 */
690 for (i = 0; i < buffer->NumPhysDisks; i++) {
691
692 if (mpt_raid_phys_disk_pg0(ioc,
693 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
694 continue;
695
696 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
697 phys_disk.PhysDiskID);
698
Kashyap, Desai57e98512009-05-29 16:55:09 +0530699 mutex_lock(&ioc->sas_device_info_mutex);
700 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
701 list) {
702 if (!sas_info->is_logical_volume &&
703 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
704 sas_info->fw.id == phys_disk.PhysDiskID)) {
705 sas_info->is_hidden_raid_component = 1;
706 sas_info->volume_id = starget->id;
707 }
708 }
709 mutex_unlock(&ioc->sas_device_info_mutex);
710
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530711 }
712
713 /*
714 * Delete all matching devices out of the list
715 */
716 mutex_lock(&ioc->sas_device_info_mutex);
717 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
718 list) {
719 if (sas_info->is_logical_volume && sas_info->fw.id ==
720 starget->id) {
721 list_del(&sas_info->list);
722 kfree(sas_info);
723 }
724 }
725
726 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
727 if (sas_info) {
728 sas_info->fw.id = starget->id;
729 sas_info->os.id = starget->id;
730 sas_info->os.channel = starget->channel;
731 sas_info->is_logical_volume = 1;
732 INIT_LIST_HEAD(&sas_info->list);
733 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
734 }
735 mutex_unlock(&ioc->sas_device_info_mutex);
736
737 out:
738 if (buffer)
739 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
740 dma_handle);
741}
742
743/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530744 * mptsas_add_device_component_starget -
745 * @ioc: Pointer to MPT_ADAPTER structure
746 * @starget:
747 *
748 **/
749static void
750mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
751 struct scsi_target *starget)
752{
753 VirtTarget *vtarget;
754 struct sas_rphy *rphy;
755 struct mptsas_phyinfo *phy_info = NULL;
756 struct mptsas_enclosure enclosure_info;
757
758 rphy = dev_to_rphy(starget->dev.parent);
759 vtarget = starget->hostdata;
760 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
761 rphy->identify.sas_address);
762 if (!phy_info)
763 return;
764
765 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
766 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
767 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
768 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
769 phy_info->attached.handle_enclosure);
770
771 mptsas_add_device_component(ioc, phy_info->attached.channel,
772 phy_info->attached.id, phy_info->attached.sas_address,
773 phy_info->attached.device_info,
774 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
775}
776
777/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000778 * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
Kashyap, Desai57e98512009-05-29 16:55:09 +0530779 * @ioc: Pointer to MPT_ADAPTER structure
780 * @channel: os mapped id's
781 * @id:
782 *
783 **/
784static void
785mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
786{
787 struct mptsas_device_info *sas_info, *next;
788
789 /*
790 * Set is_cached flag
791 */
792 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
793 list) {
794 if (sas_info->os.channel == channel && sas_info->os.id == id)
795 sas_info->is_cached = 1;
796 }
797}
798
799/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530800 * mptsas_del_device_components - Cleaning the list
801 * @ioc: Pointer to MPT_ADAPTER structure
802 *
803 **/
804static void
805mptsas_del_device_components(MPT_ADAPTER *ioc)
806{
807 struct mptsas_device_info *sas_info, *next;
808
809 mutex_lock(&ioc->sas_device_info_mutex);
810 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
811 list) {
812 list_del(&sas_info->list);
813 kfree(sas_info);
814 }
815 mutex_unlock(&ioc->sas_device_info_mutex);
816}
817
Eric Moore547f9a22006-06-27 14:42:12 -0600818
819/*
820 * mptsas_setup_wide_ports
821 *
822 * Updates for new and existing narrow/wide port configuration
823 * in the sas_topology
824 */
Eric Moore376ac832006-06-29 17:36:26 -0600825static void
Eric Moore547f9a22006-06-27 14:42:12 -0600826mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
827{
828 struct mptsas_portinfo_details * port_details;
829 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
830 u64 sas_address;
831 int i, j;
832
833 mutex_lock(&ioc->sas_topology_mutex);
834
835 phy_info = port_info->phy_info;
836 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
837 if (phy_info->attached.handle)
838 continue;
839 port_details = phy_info->port_details;
840 if (!port_details)
841 continue;
842 if (port_details->num_phys < 2)
843 continue;
844 /*
845 * Removing a phy from a port, letting the last
846 * phy be removed by firmware events.
847 */
Eric Moore29dd3602007-09-14 18:46:51 -0600848 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
849 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700850 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600851 port_details->num_phys--;
852 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
853 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
854 sas_port_delete_phy(port_details->port, phy_info->phy);
855 phy_info->port_details = NULL;
856 }
857
858 /*
859 * Populate and refresh the tree
860 */
861 phy_info = port_info->phy_info;
862 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
863 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600864 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
865 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600866 if (!sas_address)
867 continue;
868 port_details = phy_info->port_details;
869 /*
870 * Forming a port
871 */
872 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530873 port_details = kzalloc(sizeof(struct
874 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600875 if (!port_details)
876 goto out;
877 port_details->num_phys = 1;
878 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600879 if (phy_info->phy_id < 64 )
880 port_details->phy_bitmask |=
881 (1 << phy_info->phy_id);
882 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600883 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700884 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600885 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600886 phy_info->port_details = port_details;
887 }
888
889 if (i == port_info->num_phys - 1)
890 continue;
891 phy_info_cmp = &port_info->phy_info[i + 1];
892 for (j = i + 1 ; j < port_info->num_phys ; j++,
893 phy_info_cmp++) {
894 if (!phy_info_cmp->attached.sas_address)
895 continue;
896 if (sas_address != phy_info_cmp->attached.sas_address)
897 continue;
898 if (phy_info_cmp->port_details == port_details )
899 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600900 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700901 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600902 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700903 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600904 if (phy_info_cmp->port_details) {
905 port_details->rphy =
906 mptsas_get_rphy(phy_info_cmp);
907 port_details->port =
908 mptsas_get_port(phy_info_cmp);
909 port_details->starget =
910 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600911 port_details->num_phys =
912 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600913 if (!phy_info_cmp->port_details->num_phys)
914 kfree(phy_info_cmp->port_details);
915 } else
916 phy_info_cmp->sas_port_add_phy=1;
917 /*
918 * Adding a phy to a port
919 */
920 phy_info_cmp->port_details = port_details;
921 if (phy_info_cmp->phy_id < 64 )
922 port_details->phy_bitmask |=
923 (1 << phy_info_cmp->phy_id);
924 port_details->num_phys++;
925 }
926 }
927
928 out:
929
Eric Moore547f9a22006-06-27 14:42:12 -0600930 for (i = 0; i < port_info->num_phys; i++) {
931 port_details = port_info->phy_info[i].port_details;
932 if (!port_details)
933 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600934 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700935 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700936 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700937 port_details, i, port_details->num_phys,
938 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600939 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
940 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600941 }
Eric Moore29dd3602007-09-14 18:46:51 -0600942 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600943 mutex_unlock(&ioc->sas_topology_mutex);
944}
945
Eric Mooredf9e0622007-01-29 09:46:21 -0700946/**
947 * csmisas_find_vtarget
948 *
949 * @ioc
950 * @volume_id
951 * @volume_bus
952 *
953 **/
954static VirtTarget *
955mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600956{
Eric Mooredf9e0622007-01-29 09:46:21 -0700957 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600958 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700959 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600960
Eric Mooredf9e0622007-01-29 09:46:21 -0700961 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530962 vdevice = sdev->hostdata;
963 if ((vdevice == NULL) ||
964 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700965 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530966 if ((vdevice->vtarget->tflags &
967 MPT_TARGET_FLAGS_RAID_COMPONENT ||
968 vdevice->vtarget->raidVolume))
969 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600970 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530971 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600972 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600973 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700974 return vtarget;
975}
976
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530977static void
978mptsas_queue_device_delete(MPT_ADAPTER *ioc,
979 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
980{
981 struct fw_event_work *fw_event;
982 int sz;
983
984 sz = offsetof(struct fw_event_work, event_data) +
985 sizeof(MpiEventDataSasDeviceStatusChange_t);
986 fw_event = kzalloc(sz, GFP_ATOMIC);
987 if (!fw_event) {
988 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
989 ioc->name, __func__, __LINE__);
990 return;
991 }
992 memcpy(fw_event->event_data, sas_event_data,
993 sizeof(MpiEventDataSasDeviceStatusChange_t));
994 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
995 fw_event->ioc = ioc;
996 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
997}
998
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530999static void
1000mptsas_queue_rescan(MPT_ADAPTER *ioc)
1001{
1002 struct fw_event_work *fw_event;
1003 int sz;
1004
1005 sz = offsetof(struct fw_event_work, event_data);
1006 fw_event = kzalloc(sz, GFP_ATOMIC);
1007 if (!fw_event) {
1008 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1009 ioc->name, __func__, __LINE__);
1010 return;
1011 }
1012 fw_event->event = -1;
1013 fw_event->ioc = ioc;
1014 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1015}
1016
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301017
Eric Mooredf9e0622007-01-29 09:46:21 -07001018/**
1019 * mptsas_target_reset
1020 *
1021 * Issues TARGET_RESET to end device using handshaking method
1022 *
1023 * @ioc
1024 * @channel
1025 * @id
1026 *
1027 * Returns (1) success
1028 * (0) failure
1029 *
1030 **/
1031static int
1032mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1033{
1034 MPT_FRAME_HDR *mf;
1035 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301036 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1037 return 0;
1038
Eric Mooredf9e0622007-01-29 09:46:21 -07001039
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301040 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1041 if (mf == NULL) {
1042 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301043 "%s, no msg frames @%d!!\n", ioc->name,
1044 __func__, __LINE__));
1045 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001046 }
1047
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301048 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1049 ioc->name, mf));
1050
Eric Mooredf9e0622007-01-29 09:46:21 -07001051 /* Format the Request
1052 */
1053 pScsiTm = (SCSITaskMgmt_t *) mf;
1054 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1055 pScsiTm->TargetID = id;
1056 pScsiTm->Bus = channel;
1057 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1058 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1059 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1060
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301061 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001062
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301063 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1064 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1065 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1066
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301067 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001068
1069 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301070
1071 out_fail:
1072
1073 mpt_clear_taskmgmt_in_progress_flag(ioc);
1074 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001075}
1076
1077/**
1078 * mptsas_target_reset_queue
1079 *
1080 * Receive request for TARGET_RESET after recieving an firmware
1081 * event NOT_RESPONDING_EVENT, then put command in link list
1082 * and queue if task_queue already in use.
1083 *
1084 * @ioc
1085 * @sas_event_data
1086 *
1087 **/
1088static void
1089mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1090 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1091{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001092 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001093 VirtTarget *vtarget = NULL;
1094 struct mptsas_target_reset_event *target_reset_list;
1095 u8 id, channel;
1096
1097 id = sas_event_data->TargetID;
1098 channel = sas_event_data->Bus;
1099
1100 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
1101 return;
1102
1103 vtarget->deleted = 1; /* block IO */
1104
Kashyap, Desai2f187862009-05-29 16:52:37 +05301105 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001106 GFP_ATOMIC);
1107 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301108 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1109 "%s, failed to allocate mem @%d..!!\n",
1110 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001111 return;
1112 }
1113
1114 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1115 sizeof(*sas_event_data));
1116 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1117
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301118 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001119
1120 if (mptsas_target_reset(ioc, channel, id)) {
1121 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001122 }
1123}
1124
1125/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001126 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301127 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001128 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001129 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1130 * queue to finish off removing device from upper layers. then send next
1131 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001132 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301133static int
1134mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001135{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001136 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001137 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001138 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301139 struct mptsas_target_reset_event *target_reset_list;
1140 SCSITaskMgmtReply_t *pScsiTmReply;
1141
1142 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1143 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1144
1145 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1146 if (pScsiTmReply) {
1147 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1148 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1149 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1150 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1151 "term_cmnds = %d\n", ioc->name,
1152 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1153 pScsiTmReply->TaskType,
1154 le16_to_cpu(pScsiTmReply->IOCStatus),
1155 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1156 pScsiTmReply->ResponseCode,
1157 le32_to_cpu(pScsiTmReply->TerminationCount)));
1158
1159 if (pScsiTmReply->ResponseCode)
1160 mptscsih_taskmgmt_response_code(ioc,
1161 pScsiTmReply->ResponseCode);
1162 }
1163
1164 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1165 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1166 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1167 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1168 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1169 memcpy(ioc->taskmgmt_cmds.reply, mr,
1170 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1171 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1172 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1173 complete(&ioc->taskmgmt_cmds.done);
1174 return 1;
1175 }
1176 return 0;
1177 }
1178
1179 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001180
1181 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301182 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001183
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301184 target_reset_list = list_entry(head->next,
1185 struct mptsas_target_reset_event, list);
1186
1187 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1188 "TaskMgmt: completed (%d seconds)\n",
1189 ioc->name, jiffies_to_msecs(jiffies -
1190 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001191
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301192 id = pScsiTmReply->TargetID;
1193 channel = pScsiTmReply->Bus;
1194 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001195
1196 /*
1197 * retry target reset
1198 */
1199 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301200 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001201 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301202 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001203 }
1204
1205 /*
1206 * enable work queue to remove device from upper layers
1207 */
1208 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301209 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1210 mptsas_queue_device_delete(ioc,
1211 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301212
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301213
Eric Mooredf9e0622007-01-29 09:46:21 -07001214 /*
1215 * issue target reset to next device in the queue
1216 */
1217
1218 head = &hd->target_reset_list;
1219 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301220 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001221
1222 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1223 list);
1224
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301225 id = target_reset_list->sas_event_data.TargetID;
1226 channel = target_reset_list->sas_event_data.Bus;
1227 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001228
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301229 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001230 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001231
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301232 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001233}
1234
1235/**
1236 * mptscsih_ioc_reset
1237 *
1238 * @ioc
1239 * @reset_phase
1240 *
1241 **/
1242static int
1243mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1244{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001245 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001246 int rc;
1247
1248 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301249 if ((ioc->bus_type != SAS) || (!rc))
1250 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001251
Eric Mooree7eae9f2007-09-29 10:15:59 -06001252 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001253 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001254 goto out;
1255
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301256 switch (reset_phase) {
1257 case MPT_IOC_SETUP_RESET:
1258 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1259 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1260 mptsas_fw_event_off(ioc);
1261 break;
1262 case MPT_IOC_PRE_RESET:
1263 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1264 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1265 break;
1266 case MPT_IOC_POST_RESET:
1267 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1268 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1269 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1270 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1271 complete(&ioc->sas_mgmt.done);
1272 }
1273 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301274 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301275 mptsas_fw_event_on(ioc);
1276 break;
1277 default:
1278 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001279 }
1280
1281 out:
1282 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001283}
1284
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301285
1286/**
1287 * enum device_state -
1288 * @DEVICE_RETRY: need to retry the TUR
1289 * @DEVICE_ERROR: TUR return error, don't add device
1290 * @DEVICE_READY: device can be added
1291 *
1292 */
1293enum device_state{
1294 DEVICE_RETRY,
1295 DEVICE_ERROR,
1296 DEVICE_READY,
1297};
1298
Christoph Hellwige3094442006-02-16 13:25:36 +01001299static int
Moore, Eric52435432006-03-14 09:14:15 -07001300mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001301 u32 form, u32 form_specific)
1302{
1303 ConfigExtendedPageHeader_t hdr;
1304 CONFIGPARMS cfg;
1305 SasEnclosurePage0_t *buffer;
1306 dma_addr_t dma_handle;
1307 int error;
1308 __le64 le_identifier;
1309
1310 memset(&hdr, 0, sizeof(hdr));
1311 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1312 hdr.PageNumber = 0;
1313 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1314 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1315
1316 cfg.cfghdr.ehdr = &hdr;
1317 cfg.physAddr = -1;
1318 cfg.pageAddr = form + form_specific;
1319 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1320 cfg.dir = 0; /* read */
1321 cfg.timeout = 10;
1322
1323 error = mpt_config(ioc, &cfg);
1324 if (error)
1325 goto out;
1326 if (!hdr.ExtPageLength) {
1327 error = -ENXIO;
1328 goto out;
1329 }
1330
1331 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1332 &dma_handle);
1333 if (!buffer) {
1334 error = -ENOMEM;
1335 goto out;
1336 }
1337
1338 cfg.physAddr = dma_handle;
1339 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1340
1341 error = mpt_config(ioc, &cfg);
1342 if (error)
1343 goto out_free_consistent;
1344
1345 /* save config data */
1346 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1347 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1348 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1349 enclosure->flags = le16_to_cpu(buffer->Flags);
1350 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1351 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1352 enclosure->start_id = buffer->StartTargetID;
1353 enclosure->start_channel = buffer->StartBus;
1354 enclosure->sep_id = buffer->SEPTargetID;
1355 enclosure->sep_channel = buffer->SEPBus;
1356
1357 out_free_consistent:
1358 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1359 buffer, dma_handle);
1360 out:
1361 return error;
1362}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001363
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301364/**
1365 * mptsas_add_end_device - report a new end device to sas transport layer
1366 * @ioc: Pointer to MPT_ADAPTER structure
1367 * @phy_info: decribes attached device
1368 *
1369 * return (0) success (1) failure
1370 *
1371 **/
1372static int
1373mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1374{
1375 struct sas_rphy *rphy;
1376 struct sas_port *port;
1377 struct sas_identify identify;
1378 char *ds = NULL;
1379 u8 fw_id;
1380
1381 if (!phy_info) {
1382 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1383 "%s: exit at line=%d\n", ioc->name,
1384 __func__, __LINE__));
1385 return 1;
1386 }
1387
1388 fw_id = phy_info->attached.id;
1389
1390 if (mptsas_get_rphy(phy_info)) {
1391 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1392 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1393 __func__, fw_id, __LINE__));
1394 return 2;
1395 }
1396
1397 port = mptsas_get_port(phy_info);
1398 if (!port) {
1399 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1400 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1401 __func__, fw_id, __LINE__));
1402 return 3;
1403 }
1404
1405 if (phy_info->attached.device_info &
1406 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1407 ds = "ssp";
1408 if (phy_info->attached.device_info &
1409 MPI_SAS_DEVICE_INFO_STP_TARGET)
1410 ds = "stp";
1411 if (phy_info->attached.device_info &
1412 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1413 ds = "sata";
1414
1415 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1416 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1417 phy_info->attached.channel, phy_info->attached.id,
1418 phy_info->attached.phy_id, (unsigned long long)
1419 phy_info->attached.sas_address);
1420
1421 mptsas_parse_device_info(&identify, &phy_info->attached);
1422 rphy = sas_end_device_alloc(port);
1423 if (!rphy) {
1424 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1425 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1426 __func__, fw_id, __LINE__));
1427 return 5; /* non-fatal: an rphy can be added later */
1428 }
1429
1430 rphy->identify = identify;
1431 if (sas_rphy_add(rphy)) {
1432 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1433 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1434 __func__, fw_id, __LINE__));
1435 sas_rphy_free(rphy);
1436 return 6;
1437 }
1438 mptsas_set_rphy(ioc, phy_info, rphy);
1439 return 0;
1440}
1441
1442/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001443 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301444 * @ioc: Pointer to MPT_ADAPTER structure
1445 * @phy_info: decribes attached device
1446 *
1447 **/
1448static void
1449mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1450{
1451 struct sas_rphy *rphy;
1452 struct sas_port *port;
1453 struct mptsas_portinfo *port_info;
1454 struct mptsas_phyinfo *phy_info_parent;
1455 int i;
1456 char *ds = NULL;
1457 u8 fw_id;
1458 u64 sas_address;
1459
1460 if (!phy_info)
1461 return;
1462
1463 fw_id = phy_info->attached.id;
1464 sas_address = phy_info->attached.sas_address;
1465
1466 if (!phy_info->port_details) {
1467 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1468 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1469 __func__, fw_id, __LINE__));
1470 return;
1471 }
1472 rphy = mptsas_get_rphy(phy_info);
1473 if (!rphy) {
1474 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1475 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1476 __func__, fw_id, __LINE__));
1477 return;
1478 }
1479
1480 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1481 || phy_info->attached.device_info
1482 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1483 || phy_info->attached.device_info
1484 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1485 ds = "initiator";
1486 if (phy_info->attached.device_info &
1487 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1488 ds = "ssp";
1489 if (phy_info->attached.device_info &
1490 MPI_SAS_DEVICE_INFO_STP_TARGET)
1491 ds = "stp";
1492 if (phy_info->attached.device_info &
1493 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1494 ds = "sata";
1495
1496 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1497 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1498 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1499 phy_info->attached.id, phy_info->attached.phy_id,
1500 (unsigned long long) sas_address);
1501
1502 port = mptsas_get_port(phy_info);
1503 if (!port) {
1504 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1505 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1506 __func__, fw_id, __LINE__));
1507 return;
1508 }
1509 port_info = phy_info->portinfo;
1510 phy_info_parent = port_info->phy_info;
1511 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1512 if (!phy_info_parent->phy)
1513 continue;
1514 if (phy_info_parent->attached.sas_address !=
1515 sas_address)
1516 continue;
1517 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1518 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1519 ioc->name, phy_info_parent->phy_id,
1520 phy_info_parent->phy);
1521 sas_port_delete_phy(port, phy_info_parent->phy);
1522 }
1523
1524 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1525 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1526 port->port_identifier, (unsigned long long)sas_address);
1527 sas_port_delete(port);
1528 mptsas_set_port(ioc, phy_info, NULL);
1529 mptsas_port_delete(ioc, phy_info->port_details);
1530}
1531
1532struct mptsas_phyinfo *
1533mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1534 struct mptsas_devinfo *sas_device)
1535{
1536 struct mptsas_phyinfo *phy_info;
1537 struct mptsas_portinfo *port_info;
1538 int i;
1539
1540 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1541 sas_device->sas_address);
1542 if (!phy_info)
1543 goto out;
1544 port_info = phy_info->portinfo;
1545 if (!port_info)
1546 goto out;
1547 mutex_lock(&ioc->sas_topology_mutex);
1548 for (i = 0; i < port_info->num_phys; i++) {
1549 if (port_info->phy_info[i].attached.sas_address !=
1550 sas_device->sas_address)
1551 continue;
1552 port_info->phy_info[i].attached.channel = sas_device->channel;
1553 port_info->phy_info[i].attached.id = sas_device->id;
1554 port_info->phy_info[i].attached.sas_address =
1555 sas_device->sas_address;
1556 port_info->phy_info[i].attached.handle = sas_device->handle;
1557 port_info->phy_info[i].attached.handle_parent =
1558 sas_device->handle_parent;
1559 port_info->phy_info[i].attached.handle_enclosure =
1560 sas_device->handle_enclosure;
1561 }
1562 mutex_unlock(&ioc->sas_topology_mutex);
1563 out:
1564 return phy_info;
1565}
1566
1567/**
1568 * mptsas_firmware_event_work - work thread for processing fw events
1569 * @work: work queue payload containing info describing the event
1570 * Context: user
1571 *
1572 */
1573static void
1574mptsas_firmware_event_work(struct work_struct *work)
1575{
1576 struct fw_event_work *fw_event =
1577 container_of(work, struct fw_event_work, work.work);
1578 MPT_ADAPTER *ioc = fw_event->ioc;
1579
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301580 /* special rescan topology handling */
1581 if (fw_event->event == -1) {
1582 if (ioc->in_rescan) {
1583 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1584 "%s: rescan ignored as it is in progress\n",
1585 ioc->name, __func__));
1586 return;
1587 }
1588 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1589 "reset\n", ioc->name, __func__));
1590 ioc->in_rescan = 1;
1591 mptsas_not_responding_devices(ioc);
1592 mptsas_scan_sas_topology(ioc);
1593 ioc->in_rescan = 0;
1594 mptsas_free_fw_event(ioc, fw_event);
1595 return;
1596 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301597
1598 /* events handling turned off during host reset */
1599 if (ioc->fw_events_off) {
1600 mptsas_free_fw_event(ioc, fw_event);
1601 return;
1602 }
1603
1604 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1605 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1606 (fw_event->event & 0xFF)));
1607
1608 switch (fw_event->event) {
1609 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1610 mptsas_send_sas_event(fw_event);
1611 break;
1612 case MPI_EVENT_INTEGRATED_RAID:
1613 mptsas_send_raid_event(fw_event);
1614 break;
1615 case MPI_EVENT_IR2:
1616 mptsas_send_ir2_event(fw_event);
1617 break;
1618 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1619 mptbase_sas_persist_operation(ioc,
1620 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1621 mptsas_free_fw_event(ioc, fw_event);
1622 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301623 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1624 mptsas_broadcast_primative_work(fw_event);
1625 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301626 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1627 mptsas_send_expander_event(fw_event);
1628 break;
1629 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1630 mptsas_send_link_status_event(fw_event);
1631 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301632 case MPI_EVENT_QUEUE_FULL:
1633 mptsas_handle_queue_full_event(fw_event);
1634 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301635 }
1636}
1637
1638
1639
James Bottomleyf013db32006-03-18 14:54:36 -06001640static int
1641mptsas_slave_configure(struct scsi_device *sdev)
1642{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301643 struct Scsi_Host *host = sdev->host;
1644 MPT_SCSI_HOST *hd = shost_priv(host);
1645 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301646 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001647
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301648 if (vdevice->vtarget->deleted) {
1649 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1650 vdevice->vtarget->deleted = 0;
1651 }
1652
1653 /*
1654 * RAID volumes placed beyond the last expected port.
1655 * Ignore sending sas mode pages in that case..
1656 */
1657 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1658 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001659 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301660 }
James Bottomleyf013db32006-03-18 14:54:36 -06001661
James Bottomleye8bf3942006-07-11 17:49:34 -04001662 sas_read_port_mode_page(sdev);
1663
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301664 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1665
James Bottomleye8bf3942006-07-11 17:49:34 -04001666 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001667 return mptscsih_slave_configure(sdev);
1668}
1669
Eric Moore547f9a22006-06-27 14:42:12 -06001670static int
1671mptsas_target_alloc(struct scsi_target *starget)
1672{
1673 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001674 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001675 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001676 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001677 struct sas_rphy *rphy;
1678 struct mptsas_portinfo *p;
1679 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001680 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001681
1682 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1683 if (!vtarget)
1684 return -ENOMEM;
1685
1686 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001687 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001688 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1689 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001690 channel = 0;
1691
Eric Moore793955f2007-01-29 09:42:20 -07001692 /*
1693 * RAID volumes placed beyond the last expected port.
1694 */
1695 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301696 if (!ioc->raid_data.pIocPg2) {
1697 kfree(vtarget);
1698 return -ENXIO;
1699 }
1700 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1701 if (id == ioc->raid_data.pIocPg2->
1702 RaidVolume[i].VolumeID) {
1703 channel = ioc->raid_data.pIocPg2->
1704 RaidVolume[i].VolumeBus;
1705 }
1706 }
1707 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001708 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001709 }
Eric Moore547f9a22006-06-27 14:42:12 -06001710
1711 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001712 mutex_lock(&ioc->sas_topology_mutex);
1713 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001714 for (i = 0; i < p->num_phys; i++) {
1715 if (p->phy_info[i].attached.sas_address !=
1716 rphy->identify.sas_address)
1717 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001718 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001719 channel = p->phy_info[i].attached.channel;
1720 mptsas_set_starget(&p->phy_info[i], starget);
1721
1722 /*
1723 * Exposing hidden raid components
1724 */
Eric Mooree80b0022007-09-14 18:49:03 -06001725 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1726 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001727 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001728 vtarget->tflags |=
1729 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001730 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001731 }
Eric Mooree80b0022007-09-14 18:49:03 -06001732 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001733 goto out;
1734 }
1735 }
Eric Mooree80b0022007-09-14 18:49:03 -06001736 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001737
1738 kfree(vtarget);
1739 return -ENXIO;
1740
1741 out:
Eric Moore793955f2007-01-29 09:42:20 -07001742 vtarget->id = id;
1743 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001744 starget->hostdata = vtarget;
1745 return 0;
1746}
1747
1748static void
1749mptsas_target_destroy(struct scsi_target *starget)
1750{
1751 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001752 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001753 struct sas_rphy *rphy;
1754 struct mptsas_portinfo *p;
1755 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301756 MPT_ADAPTER *ioc = hd->ioc;
1757 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001758
1759 if (!starget->hostdata)
1760 return;
1761
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301762 vtarget = starget->hostdata;
1763
Kashyap, Desai57e98512009-05-29 16:55:09 +05301764 mptsas_del_device_component_by_os(ioc, starget->channel,
1765 starget->id);
1766
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301767
James Bottomleye8bf3942006-07-11 17:49:34 -04001768 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001769 goto out;
1770
1771 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001772 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001773 for (i = 0; i < p->num_phys; i++) {
1774 if (p->phy_info[i].attached.sas_address !=
1775 rphy->identify.sas_address)
1776 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301777
1778 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1779 "delete device: fw_channel %d, fw_id %d, phy %d, "
1780 "sas_addr 0x%llx\n", ioc->name,
1781 p->phy_info[i].attached.channel,
1782 p->phy_info[i].attached.id,
1783 p->phy_info[i].attached.phy_id, (unsigned long long)
1784 p->phy_info[i].attached.sas_address);
1785
Eric Moore547f9a22006-06-27 14:42:12 -06001786 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001787 }
1788 }
1789
1790 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301791 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001792 kfree(starget->hostdata);
1793 starget->hostdata = NULL;
1794}
1795
1796
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001797static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001798mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001799{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001800 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001801 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001802 struct sas_rphy *rphy;
1803 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001804 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001805 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001806 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001807 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001808
Eric Moorea69de502007-09-14 18:48:19 -06001809 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1810 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001811 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001812 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001813 return -ENOMEM;
1814 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001815 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001816 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001817
James Bottomleye8bf3942006-07-11 17:49:34 -04001818 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001819 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001820
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001821 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001822 mutex_lock(&ioc->sas_topology_mutex);
1823 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001824 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001825 if (p->phy_info[i].attached.sas_address !=
1826 rphy->identify.sas_address)
1827 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001828 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001829 /*
1830 * Exposing hidden raid components
1831 */
Eric Mooree80b0022007-09-14 18:49:03 -06001832 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001833 p->phy_info[i].attached.channel,
1834 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001835 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001836 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001837 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001838 }
1839 }
Eric Mooree80b0022007-09-14 18:49:03 -06001840 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001841
Eric Moorea69de502007-09-14 18:48:19 -06001842 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001843 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001844
1845 out:
Eric Moorea69de502007-09-14 18:48:19 -06001846 vdevice->vtarget->num_luns++;
1847 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001848 return 0;
1849}
1850
Eric Moore547f9a22006-06-27 14:42:12 -06001851static int
1852mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001853{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301854 MPT_SCSI_HOST *hd;
1855 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001856 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001857
Eric Moorea69de502007-09-14 18:48:19 -06001858 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001859 SCpnt->result = DID_NO_CONNECT << 16;
1860 done(SCpnt);
1861 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001862 }
Eric Moore547f9a22006-06-27 14:42:12 -06001863
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301864 hd = shost_priv(SCpnt->device->host);
1865 ioc = hd->ioc;
1866
1867 if (ioc->sas_discovery_quiesce_io)
1868 return SCSI_MLQUEUE_HOST_BUSY;
1869
Eric Moore793955f2007-01-29 09:42:20 -07001870// scsi_print_command(SCpnt);
1871
Eric Moore547f9a22006-06-27 14:42:12 -06001872 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001873}
1874
Eric Moore547f9a22006-06-27 14:42:12 -06001875
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001876static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001877 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001878 .proc_name = "mptsas",
1879 .proc_info = mptscsih_proc_info,
1880 .name = "MPT SPI Host",
1881 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001882 .queuecommand = mptsas_qcmd,
1883 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001884 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001885 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001886 .target_destroy = mptsas_target_destroy,
1887 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001888 .change_queue_depth = mptscsih_change_queue_depth,
1889 .eh_abort_handler = mptscsih_abort,
1890 .eh_device_reset_handler = mptscsih_dev_reset,
1891 .eh_bus_reset_handler = mptscsih_bus_reset,
1892 .eh_host_reset_handler = mptscsih_host_reset,
1893 .bios_param = mptscsih_bios_param,
1894 .can_queue = MPT_FC_CAN_QUEUE,
1895 .this_id = -1,
1896 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1897 .max_sectors = 8192,
1898 .cmd_per_lun = 7,
1899 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301900 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001901};
1902
Christoph Hellwigb5141122005-10-28 22:07:41 +02001903static int mptsas_get_linkerrors(struct sas_phy *phy)
1904{
1905 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1906 ConfigExtendedPageHeader_t hdr;
1907 CONFIGPARMS cfg;
1908 SasPhyPage1_t *buffer;
1909 dma_addr_t dma_handle;
1910 int error;
1911
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001912 /* FIXME: only have link errors on local phys */
1913 if (!scsi_is_sas_phy_local(phy))
1914 return -EINVAL;
1915
Christoph Hellwigb5141122005-10-28 22:07:41 +02001916 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1917 hdr.ExtPageLength = 0;
1918 hdr.PageNumber = 1 /* page number 1*/;
1919 hdr.Reserved1 = 0;
1920 hdr.Reserved2 = 0;
1921 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1922 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1923
1924 cfg.cfghdr.ehdr = &hdr;
1925 cfg.physAddr = -1;
1926 cfg.pageAddr = phy->identify.phy_identifier;
1927 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1928 cfg.dir = 0; /* read */
1929 cfg.timeout = 10;
1930
1931 error = mpt_config(ioc, &cfg);
1932 if (error)
1933 return error;
1934 if (!hdr.ExtPageLength)
1935 return -ENXIO;
1936
1937 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1938 &dma_handle);
1939 if (!buffer)
1940 return -ENOMEM;
1941
1942 cfg.physAddr = dma_handle;
1943 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1944
1945 error = mpt_config(ioc, &cfg);
1946 if (error)
1947 goto out_free_consistent;
1948
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301949 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001950
1951 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1952 phy->running_disparity_error_count =
1953 le32_to_cpu(buffer->RunningDisparityErrorCount);
1954 phy->loss_of_dword_sync_count =
1955 le32_to_cpu(buffer->LossDwordSynchCount);
1956 phy->phy_reset_problem_count =
1957 le32_to_cpu(buffer->PhyResetProblemCount);
1958
1959 out_free_consistent:
1960 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1961 buffer, dma_handle);
1962 return error;
1963}
1964
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001965static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1966 MPT_FRAME_HDR *reply)
1967{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301968 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001969 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301970 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001971 memcpy(ioc->sas_mgmt.reply, reply,
1972 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1973 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301974
1975 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1976 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1977 complete(&ioc->sas_mgmt.done);
1978 return 1;
1979 }
1980 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001981}
1982
1983static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1984{
1985 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1986 SasIoUnitControlRequest_t *req;
1987 SasIoUnitControlReply_t *reply;
1988 MPT_FRAME_HDR *mf;
1989 MPIHeader_t *hdr;
1990 unsigned long timeleft;
1991 int error = -ERESTARTSYS;
1992
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001993 /* FIXME: fusion doesn't allow non-local phy reset */
1994 if (!scsi_is_sas_phy_local(phy))
1995 return -EINVAL;
1996
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001997 /* not implemented for expanders */
1998 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1999 return -ENXIO;
2000
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002001 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002002 goto out;
2003
2004 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2005 if (!mf) {
2006 error = -ENOMEM;
2007 goto out_unlock;
2008 }
2009
2010 hdr = (MPIHeader_t *) mf;
2011 req = (SasIoUnitControlRequest_t *)mf;
2012 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2013 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2014 req->MsgContext = hdr->MsgContext;
2015 req->Operation = hard_reset ?
2016 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2017 req->PhyNum = phy->identify.phy_identifier;
2018
Kashyap, Desai2f187862009-05-29 16:52:37 +05302019 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002020 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2021
2022 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2023 10 * HZ);
2024 if (!timeleft) {
2025 /* On timeout reset the board */
2026 mpt_free_msg_frame(ioc, mf);
2027 mpt_HardResetHandler(ioc, CAN_SLEEP);
2028 error = -ETIMEDOUT;
2029 goto out_unlock;
2030 }
2031
2032 /* a reply frame is expected */
2033 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302034 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002035 error = -ENXIO;
2036 goto out_unlock;
2037 }
2038
2039 /* process the completed Reply Message Frame */
2040 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2041 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002042 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002043 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002044 error = -ENXIO;
2045 goto out_unlock;
2046 }
2047
2048 error = 0;
2049
2050 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302051 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002052 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002053 out:
2054 return error;
2055}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002056
Christoph Hellwige3094442006-02-16 13:25:36 +01002057static int
2058mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2059{
2060 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2061 int i, error;
2062 struct mptsas_portinfo *p;
2063 struct mptsas_enclosure enclosure_info;
2064 u64 enclosure_handle;
2065
2066 mutex_lock(&ioc->sas_topology_mutex);
2067 list_for_each_entry(p, &ioc->sas_topology, list) {
2068 for (i = 0; i < p->num_phys; i++) {
2069 if (p->phy_info[i].attached.sas_address ==
2070 rphy->identify.sas_address) {
2071 enclosure_handle = p->phy_info[i].
2072 attached.handle_enclosure;
2073 goto found_info;
2074 }
2075 }
2076 }
2077 mutex_unlock(&ioc->sas_topology_mutex);
2078 return -ENXIO;
2079
2080 found_info:
2081 mutex_unlock(&ioc->sas_topology_mutex);
2082 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002083 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002084 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2085 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2086 if (!error)
2087 *identifier = enclosure_info.enclosure_logical_id;
2088 return error;
2089}
2090
2091static int
2092mptsas_get_bay_identifier(struct sas_rphy *rphy)
2093{
2094 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2095 struct mptsas_portinfo *p;
2096 int i, rc;
2097
2098 mutex_lock(&ioc->sas_topology_mutex);
2099 list_for_each_entry(p, &ioc->sas_topology, list) {
2100 for (i = 0; i < p->num_phys; i++) {
2101 if (p->phy_info[i].attached.sas_address ==
2102 rphy->identify.sas_address) {
2103 rc = p->phy_info[i].attached.slot;
2104 goto out;
2105 }
2106 }
2107 }
2108 rc = -ENXIO;
2109 out:
2110 mutex_unlock(&ioc->sas_topology_mutex);
2111 return rc;
2112}
2113
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002114static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2115 struct request *req)
2116{
2117 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2118 MPT_FRAME_HDR *mf;
2119 SmpPassthroughRequest_t *smpreq;
2120 struct request *rsp = req->next_rq;
2121 int ret;
2122 int flagsLength;
2123 unsigned long timeleft;
2124 char *psge;
2125 dma_addr_t dma_addr_in = 0;
2126 dma_addr_t dma_addr_out = 0;
2127 u64 sas_address = 0;
2128
2129 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002130 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002131 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002132 return -EINVAL;
2133 }
2134
2135 /* do we need to support multiple segments? */
2136 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002137 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002138 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2139 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002140 return -EINVAL;
2141 }
2142
2143 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2144 if (ret)
2145 goto out;
2146
2147 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2148 if (!mf) {
2149 ret = -ENOMEM;
2150 goto out_unlock;
2151 }
2152
2153 smpreq = (SmpPassthroughRequest_t *)mf;
2154 memset(smpreq, 0, sizeof(*smpreq));
2155
Tejun Heob0790412009-05-07 22:24:42 +09002156 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002157 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2158
2159 if (rphy)
2160 sas_address = rphy->identify.sas_address;
2161 else {
2162 struct mptsas_portinfo *port_info;
2163
2164 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302165 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002166 if (port_info && port_info->phy_info)
2167 sas_address =
2168 port_info->phy_info[0].phy->identify.sas_address;
2169 mutex_unlock(&ioc->sas_topology_mutex);
2170 }
2171
2172 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2173
2174 psge = (char *)
2175 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2176
2177 /* request */
2178 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2179 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302180 MPI_SGE_FLAGS_DIRECTION)
2181 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002182 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002183
2184 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002185 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002186 if (!dma_addr_out)
2187 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302188 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302189 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002190
2191 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302192 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2193 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2194 MPI_SGE_FLAGS_IOC_TO_HOST |
2195 MPI_SGE_FLAGS_END_OF_BUFFER;
2196
2197 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002198 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002199 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002200 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002201 if (!dma_addr_in)
2202 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302203 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002204
Kashyap, Desai2f187862009-05-29 16:52:37 +05302205 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002206 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2207
2208 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2209 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002210 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002211 /* On timeout reset the board */
2212 mpt_HardResetHandler(ioc, CAN_SLEEP);
2213 ret = -ETIMEDOUT;
2214 goto unmap;
2215 }
2216 mf = NULL;
2217
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302218 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002219 SmpPassthroughReply_t *smprep;
2220
2221 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2222 memcpy(req->sense, smprep, sizeof(*smprep));
2223 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002224 req->resid_len = 0;
2225 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002226 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302227 printk(MYIOC_s_ERR_FMT
2228 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002229 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002230 ret = -ENXIO;
2231 }
2232unmap:
2233 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002234 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002235 PCI_DMA_BIDIRECTIONAL);
2236 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002237 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002238 PCI_DMA_BIDIRECTIONAL);
2239put_mf:
2240 if (mf)
2241 mpt_free_msg_frame(ioc, mf);
2242out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302243 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002244 mutex_unlock(&ioc->sas_mgmt.mutex);
2245out:
2246 return ret;
2247}
2248
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002249static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002250 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002251 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2252 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002253 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002254 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002255};
2256
2257static struct scsi_transport_template *mptsas_transport_template;
2258
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002259static int
2260mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2261{
2262 ConfigExtendedPageHeader_t hdr;
2263 CONFIGPARMS cfg;
2264 SasIOUnitPage0_t *buffer;
2265 dma_addr_t dma_handle;
2266 int error, i;
2267
2268 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2269 hdr.ExtPageLength = 0;
2270 hdr.PageNumber = 0;
2271 hdr.Reserved1 = 0;
2272 hdr.Reserved2 = 0;
2273 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2274 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2275
2276 cfg.cfghdr.ehdr = &hdr;
2277 cfg.physAddr = -1;
2278 cfg.pageAddr = 0;
2279 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2280 cfg.dir = 0; /* read */
2281 cfg.timeout = 10;
2282
2283 error = mpt_config(ioc, &cfg);
2284 if (error)
2285 goto out;
2286 if (!hdr.ExtPageLength) {
2287 error = -ENXIO;
2288 goto out;
2289 }
2290
2291 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2292 &dma_handle);
2293 if (!buffer) {
2294 error = -ENOMEM;
2295 goto out;
2296 }
2297
2298 cfg.physAddr = dma_handle;
2299 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2300
2301 error = mpt_config(ioc, &cfg);
2302 if (error)
2303 goto out_free_consistent;
2304
2305 port_info->num_phys = buffer->NumPhys;
2306 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302307 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002308 if (!port_info->phy_info) {
2309 error = -ENOMEM;
2310 goto out_free_consistent;
2311 }
2312
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302313 ioc->nvdata_version_persistent =
2314 le16_to_cpu(buffer->NvdataVersionPersistent);
2315 ioc->nvdata_version_default =
2316 le16_to_cpu(buffer->NvdataVersionDefault);
2317
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002318 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302319 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002320 port_info->phy_info[i].phy_id = i;
2321 port_info->phy_info[i].port_id =
2322 buffer->PhyData[i].Port;
2323 port_info->phy_info[i].negotiated_link_rate =
2324 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002325 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002326 port_info->phy_info[i].handle =
2327 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002328 }
2329
2330 out_free_consistent:
2331 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2332 buffer, dma_handle);
2333 out:
2334 return error;
2335}
2336
2337static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302338mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2339{
2340 ConfigExtendedPageHeader_t hdr;
2341 CONFIGPARMS cfg;
2342 SasIOUnitPage1_t *buffer;
2343 dma_addr_t dma_handle;
2344 int error;
2345 u16 device_missing_delay;
2346
2347 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2348 memset(&cfg, 0, sizeof(CONFIGPARMS));
2349
2350 cfg.cfghdr.ehdr = &hdr;
2351 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2352 cfg.timeout = 10;
2353 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2354 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2355 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2356 cfg.cfghdr.ehdr->PageNumber = 1;
2357
2358 error = mpt_config(ioc, &cfg);
2359 if (error)
2360 goto out;
2361 if (!hdr.ExtPageLength) {
2362 error = -ENXIO;
2363 goto out;
2364 }
2365
2366 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2367 &dma_handle);
2368 if (!buffer) {
2369 error = -ENOMEM;
2370 goto out;
2371 }
2372
2373 cfg.physAddr = dma_handle;
2374 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2375
2376 error = mpt_config(ioc, &cfg);
2377 if (error)
2378 goto out_free_consistent;
2379
2380 ioc->io_missing_delay =
2381 le16_to_cpu(buffer->IODeviceMissingDelay);
2382 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2383 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2384 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2385 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2386
2387 out_free_consistent:
2388 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2389 buffer, dma_handle);
2390 out:
2391 return error;
2392}
2393
2394static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002395mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2396 u32 form, u32 form_specific)
2397{
2398 ConfigExtendedPageHeader_t hdr;
2399 CONFIGPARMS cfg;
2400 SasPhyPage0_t *buffer;
2401 dma_addr_t dma_handle;
2402 int error;
2403
2404 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2405 hdr.ExtPageLength = 0;
2406 hdr.PageNumber = 0;
2407 hdr.Reserved1 = 0;
2408 hdr.Reserved2 = 0;
2409 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2410 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2411
2412 cfg.cfghdr.ehdr = &hdr;
2413 cfg.dir = 0; /* read */
2414 cfg.timeout = 10;
2415
2416 /* Get Phy Pg 0 for each Phy. */
2417 cfg.physAddr = -1;
2418 cfg.pageAddr = form + form_specific;
2419 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2420
2421 error = mpt_config(ioc, &cfg);
2422 if (error)
2423 goto out;
2424
2425 if (!hdr.ExtPageLength) {
2426 error = -ENXIO;
2427 goto out;
2428 }
2429
2430 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2431 &dma_handle);
2432 if (!buffer) {
2433 error = -ENOMEM;
2434 goto out;
2435 }
2436
2437 cfg.physAddr = dma_handle;
2438 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2439
2440 error = mpt_config(ioc, &cfg);
2441 if (error)
2442 goto out_free_consistent;
2443
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302444 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002445
2446 phy_info->hw_link_rate = buffer->HwLinkRate;
2447 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2448 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2449 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2450
2451 out_free_consistent:
2452 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2453 buffer, dma_handle);
2454 out:
2455 return error;
2456}
2457
2458static int
2459mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2460 u32 form, u32 form_specific)
2461{
2462 ConfigExtendedPageHeader_t hdr;
2463 CONFIGPARMS cfg;
2464 SasDevicePage0_t *buffer;
2465 dma_addr_t dma_handle;
2466 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002467 int error=0;
2468
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002469 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2470 hdr.ExtPageLength = 0;
2471 hdr.PageNumber = 0;
2472 hdr.Reserved1 = 0;
2473 hdr.Reserved2 = 0;
2474 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2475 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2476
2477 cfg.cfghdr.ehdr = &hdr;
2478 cfg.pageAddr = form + form_specific;
2479 cfg.physAddr = -1;
2480 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2481 cfg.dir = 0; /* read */
2482 cfg.timeout = 10;
2483
Moore, Ericdb9c9172006-03-14 09:14:18 -07002484 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002485 error = mpt_config(ioc, &cfg);
2486 if (error)
2487 goto out;
2488 if (!hdr.ExtPageLength) {
2489 error = -ENXIO;
2490 goto out;
2491 }
2492
2493 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2494 &dma_handle);
2495 if (!buffer) {
2496 error = -ENOMEM;
2497 goto out;
2498 }
2499
2500 cfg.physAddr = dma_handle;
2501 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2502
2503 error = mpt_config(ioc, &cfg);
2504 if (error)
2505 goto out_free_consistent;
2506
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302507 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002508
Kashyap, Desai2f187862009-05-29 16:52:37 +05302509 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002510 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002511 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002512 device_info->handle_enclosure =
2513 le16_to_cpu(buffer->EnclosureHandle);
2514 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002515 device_info->phy_id = buffer->PhyNum;
2516 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002517 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002518 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002519 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002520 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2521 device_info->sas_address = le64_to_cpu(sas_address);
2522 device_info->device_info =
2523 le32_to_cpu(buffer->DeviceInfo);
2524
2525 out_free_consistent:
2526 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2527 buffer, dma_handle);
2528 out:
2529 return error;
2530}
2531
2532static int
2533mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2534 u32 form, u32 form_specific)
2535{
2536 ConfigExtendedPageHeader_t hdr;
2537 CONFIGPARMS cfg;
2538 SasExpanderPage0_t *buffer;
2539 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002540 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302541 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002542
Kashyap, Desai2f187862009-05-29 16:52:37 +05302543 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002544 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2545 hdr.ExtPageLength = 0;
2546 hdr.PageNumber = 0;
2547 hdr.Reserved1 = 0;
2548 hdr.Reserved2 = 0;
2549 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2550 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2551
2552 cfg.cfghdr.ehdr = &hdr;
2553 cfg.physAddr = -1;
2554 cfg.pageAddr = form + form_specific;
2555 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2556 cfg.dir = 0; /* read */
2557 cfg.timeout = 10;
2558
Moore, Ericdb9c9172006-03-14 09:14:18 -07002559 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002560 error = mpt_config(ioc, &cfg);
2561 if (error)
2562 goto out;
2563
2564 if (!hdr.ExtPageLength) {
2565 error = -ENXIO;
2566 goto out;
2567 }
2568
2569 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2570 &dma_handle);
2571 if (!buffer) {
2572 error = -ENOMEM;
2573 goto out;
2574 }
2575
2576 cfg.physAddr = dma_handle;
2577 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2578
2579 error = mpt_config(ioc, &cfg);
2580 if (error)
2581 goto out_free_consistent;
2582
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002583 if (!buffer->NumPhys) {
2584 error = -ENODEV;
2585 goto out_free_consistent;
2586 }
2587
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002588 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302589 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002590 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302591 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002592 if (!port_info->phy_info) {
2593 error = -ENOMEM;
2594 goto out_free_consistent;
2595 }
2596
Kashyap, Desai2f187862009-05-29 16:52:37 +05302597 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002598 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002599 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002600 port_info->phy_info[i].handle =
2601 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302602 port_info->phy_info[i].identify.sas_address =
2603 le64_to_cpu(sas_address);
2604 port_info->phy_info[i].identify.handle_parent =
2605 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002606 }
Eric Moore547f9a22006-06-27 14:42:12 -06002607
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002608 out_free_consistent:
2609 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2610 buffer, dma_handle);
2611 out:
2612 return error;
2613}
2614
2615static int
2616mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2617 u32 form, u32 form_specific)
2618{
2619 ConfigExtendedPageHeader_t hdr;
2620 CONFIGPARMS cfg;
2621 SasExpanderPage1_t *buffer;
2622 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002623 int error=0;
2624
Kashyap, Desai2f187862009-05-29 16:52:37 +05302625 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002626 hdr.ExtPageLength = 0;
2627 hdr.PageNumber = 1;
2628 hdr.Reserved1 = 0;
2629 hdr.Reserved2 = 0;
2630 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2631 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2632
2633 cfg.cfghdr.ehdr = &hdr;
2634 cfg.physAddr = -1;
2635 cfg.pageAddr = form + form_specific;
2636 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2637 cfg.dir = 0; /* read */
2638 cfg.timeout = 10;
2639
2640 error = mpt_config(ioc, &cfg);
2641 if (error)
2642 goto out;
2643
2644 if (!hdr.ExtPageLength) {
2645 error = -ENXIO;
2646 goto out;
2647 }
2648
2649 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2650 &dma_handle);
2651 if (!buffer) {
2652 error = -ENOMEM;
2653 goto out;
2654 }
2655
2656 cfg.physAddr = dma_handle;
2657 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2658
2659 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302660
2661 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2662 error = -ENODEV;
2663 goto out;
2664 }
2665
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002666 if (error)
2667 goto out_free_consistent;
2668
2669
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302670 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002671
2672 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002673 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002674 phy_info->port_id = buffer->PhysicalPort;
2675 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2676 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2677 phy_info->hw_link_rate = buffer->HwLinkRate;
2678 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2679 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2680
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002681 out_free_consistent:
2682 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2683 buffer, dma_handle);
2684 out:
2685 return error;
2686}
2687
2688static void
2689mptsas_parse_device_info(struct sas_identify *identify,
2690 struct mptsas_devinfo *device_info)
2691{
2692 u16 protocols;
2693
2694 identify->sas_address = device_info->sas_address;
2695 identify->phy_identifier = device_info->phy_id;
2696
2697 /*
2698 * Fill in Phy Initiator Port Protocol.
2699 * Bits 6:3, more than one bit can be set, fall through cases.
2700 */
2701 protocols = device_info->device_info & 0x78;
2702 identify->initiator_port_protocols = 0;
2703 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2704 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2705 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2706 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2707 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2708 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2709 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2710 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2711
2712 /*
2713 * Fill in Phy Target Port Protocol.
2714 * Bits 10:7, more than one bit can be set, fall through cases.
2715 */
2716 protocols = device_info->device_info & 0x780;
2717 identify->target_port_protocols = 0;
2718 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2719 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2720 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2721 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2722 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2723 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2724 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2725 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2726
2727 /*
2728 * Fill in Attached device type.
2729 */
2730 switch (device_info->device_info &
2731 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2732 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2733 identify->device_type = SAS_PHY_UNUSED;
2734 break;
2735 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2736 identify->device_type = SAS_END_DEVICE;
2737 break;
2738 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2739 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2740 break;
2741 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2742 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2743 break;
2744 }
2745}
2746
2747static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002748 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002749{
Moore, Erice6b2d762006-03-14 09:14:24 -07002750 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002751 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002752 struct sas_port *port;
2753 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002754
Eric Moore547f9a22006-06-27 14:42:12 -06002755 if (!dev) {
2756 error = -ENODEV;
2757 goto out;
2758 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002759
2760 if (!phy_info->phy) {
2761 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002762 if (!phy) {
2763 error = -ENOMEM;
2764 goto out;
2765 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002766 } else
2767 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002768
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002769 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002770
2771 /*
2772 * Set Negotiated link rate.
2773 */
2774 switch (phy_info->negotiated_link_rate) {
2775 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002776 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002777 break;
2778 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002779 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002780 break;
2781 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002782 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002783 break;
2784 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002785 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002786 break;
2787 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2788 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2789 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002790 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002791 break;
2792 }
2793
2794 /*
2795 * Set Max hardware link rate.
2796 */
2797 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2798 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002799 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002800 break;
2801 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002802 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002803 break;
2804 default:
2805 break;
2806 }
2807
2808 /*
2809 * Set Max programmed link rate.
2810 */
2811 switch (phy_info->programmed_link_rate &
2812 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2813 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002814 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002815 break;
2816 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002817 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002818 break;
2819 default:
2820 break;
2821 }
2822
2823 /*
2824 * Set Min hardware link rate.
2825 */
2826 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2827 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002828 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002829 break;
2830 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002831 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002832 break;
2833 default:
2834 break;
2835 }
2836
2837 /*
2838 * Set Min programmed link rate.
2839 */
2840 switch (phy_info->programmed_link_rate &
2841 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2842 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002843 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002844 break;
2845 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002846 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002847 break;
2848 default:
2849 break;
2850 }
2851
Moore, Erice6b2d762006-03-14 09:14:24 -07002852 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002853
Moore, Erice6b2d762006-03-14 09:14:24 -07002854 error = sas_phy_add(phy);
2855 if (error) {
2856 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002857 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002858 }
2859 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002860 }
2861
Eric Moore547f9a22006-06-27 14:42:12 -06002862 if (!phy_info->attached.handle ||
2863 !phy_info->port_details)
2864 goto out;
2865
2866 port = mptsas_get_port(phy_info);
2867 ioc = phy_to_ioc(phy_info->phy);
2868
2869 if (phy_info->sas_port_add_phy) {
2870
2871 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002872 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002873 if (!port) {
2874 error = -ENOMEM;
2875 goto out;
2876 }
2877 error = sas_port_add(port);
2878 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302879 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002880 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002881 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002882 goto out;
2883 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302884 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302885 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
2886 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
2887 ioc->name, port->port_identifier,
2888 (unsigned long long)phy_info->
2889 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06002890 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302891 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2892 "sas_port_add_phy: phy_id=%d\n",
2893 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002894 sas_port_add_phy(port, phy_info->phy);
2895 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302896 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
2897 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
2898 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06002899 }
Eric Moore547f9a22006-06-27 14:42:12 -06002900 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002901
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002902 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002903 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002904 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002905
James Bottomley2686de22006-06-30 12:54:02 -05002906 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002907 /*
2908 * Let the hotplug_work thread handle processing
2909 * the adding/removing of devices that occur
2910 * after start of day.
2911 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302912 if (mptsas_is_end_device(&phy_info->attached) &&
2913 phy_info->attached.handle_parent) {
2914 goto out;
2915 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002916
James Bottomleyf013db32006-03-18 14:54:36 -06002917 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002918 if (scsi_is_host_device(parent)) {
2919 struct mptsas_portinfo *port_info;
2920 int i;
2921
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302922 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002923
2924 for (i = 0; i < port_info->num_phys; i++)
2925 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002926 identify.sas_address) {
2927 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002928 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002929 }
James Bottomley2686de22006-06-30 12:54:02 -05002930
2931 } else if (scsi_is_sas_rphy(parent)) {
2932 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2933 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002934 parent_rphy->identify.sas_address) {
2935 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002936 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002937 }
James Bottomley2686de22006-06-30 12:54:02 -05002938 }
2939
James Bottomleyf013db32006-03-18 14:54:36 -06002940 switch (identify.device_type) {
2941 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002942 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002943 break;
2944 case SAS_EDGE_EXPANDER_DEVICE:
2945 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002946 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002947 break;
2948 default:
2949 rphy = NULL;
2950 break;
2951 }
Eric Moore547f9a22006-06-27 14:42:12 -06002952 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302953 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002954 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002955 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002956 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002957 }
2958
Eric Moore547f9a22006-06-27 14:42:12 -06002959 rphy->identify = identify;
2960 error = sas_rphy_add(rphy);
2961 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302962 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002963 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002964 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002965 sas_rphy_free(rphy);
2966 goto out;
2967 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302968 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002969 }
2970
Eric Moore547f9a22006-06-27 14:42:12 -06002971 out:
2972 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002973}
2974
2975static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002976mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002977{
Moore, Erice6b2d762006-03-14 09:14:24 -07002978 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002979 int error = -ENOMEM, i;
2980
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302981 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002982 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002983 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002984
Moore, Erice6b2d762006-03-14 09:14:24 -07002985 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002986 if (error)
2987 goto out_free_port_info;
2988
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302989 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002990 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302991 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002992 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302993 ioc->hba_port_info = port_info = hba;
2994 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002995 list_add_tail(&port_info->list, &ioc->sas_topology);
2996 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002997 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002998 port_info->phy_info[i].negotiated_link_rate =
2999 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003000 port_info->phy_info[i].handle =
3001 hba->phy_info[i].handle;
3002 port_info->phy_info[i].port_id =
3003 hba->phy_info[i].port_id;
3004 }
Eric Moore547f9a22006-06-27 14:42:12 -06003005 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003006 kfree(hba);
3007 hba = NULL;
3008 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003009 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303010#if defined(CPQ_CIM)
3011 ioc->num_ports = port_info->num_phys;
3012#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003013 for (i = 0; i < port_info->num_phys; i++) {
3014 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3015 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3016 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303017 port_info->phy_info[i].identify.handle =
3018 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003019 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003020 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3021 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303022 port_info->phy_info[i].identify.handle);
3023 if (!ioc->hba_port_sas_addr)
3024 ioc->hba_port_sas_addr =
3025 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003026 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003027 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003028 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003029 mptsas_sas_device_pg0(ioc,
3030 &port_info->phy_info[i].attached,
3031 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3032 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3033 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003034 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003035
Eric Moore547f9a22006-06-27 14:42:12 -06003036 mptsas_setup_wide_ports(ioc, port_info);
3037
3038 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003039 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003040 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003041
3042 return 0;
3043
3044 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003045 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003046 out:
3047 return error;
3048}
3049
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303050static void
3051mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003052{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303053 struct mptsas_portinfo *parent;
3054 struct device *parent_dev;
3055 struct sas_rphy *rphy;
3056 int i;
3057 u64 sas_address; /* expander sas address */
3058 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003059
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303060 handle = port_info->phy_info[0].handle;
3061 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003062 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003063 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303064 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3065 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003066
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303067 mptsas_sas_device_pg0(ioc,
3068 &port_info->phy_info[i].identify,
3069 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3070 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3071 port_info->phy_info[i].identify.handle);
3072 port_info->phy_info[i].identify.phy_id =
3073 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003074
3075 if (port_info->phy_info[i].attached.handle) {
3076 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303077 &port_info->phy_info[i].attached,
3078 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3079 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3080 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003081 port_info->phy_info[i].attached.phy_id =
3082 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003083 }
Eric Moore547f9a22006-06-27 14:42:12 -06003084 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003085
Moore, Erice6b2d762006-03-14 09:14:24 -07003086 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303087 parent = mptsas_find_portinfo_by_handle(ioc,
3088 port_info->phy_info[0].identify.handle_parent);
3089 if (!parent) {
3090 mutex_unlock(&ioc->sas_topology_mutex);
3091 return;
3092 }
3093 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3094 i++) {
3095 if (parent->phy_info[i].attached.sas_address == sas_address) {
3096 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3097 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003098 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003099 }
3100 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303101
3102 mptsas_setup_wide_ports(ioc, port_info);
3103 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3104 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3105 ioc->sas_index, 0);
3106}
3107
3108static void
3109mptsas_expander_event_add(MPT_ADAPTER *ioc,
3110 MpiEventDataSasExpanderStatusChange_t *expander_data)
3111{
3112 struct mptsas_portinfo *port_info;
3113 int i;
3114 __le64 sas_address;
3115
3116 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3117 if (!port_info)
3118 BUG();
3119 port_info->num_phys = (expander_data->NumPhys) ?
3120 expander_data->NumPhys : 1;
3121 port_info->phy_info = kcalloc(port_info->num_phys,
3122 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3123 if (!port_info->phy_info)
3124 BUG();
3125 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3126 for (i = 0; i < port_info->num_phys; i++) {
3127 port_info->phy_info[i].portinfo = port_info;
3128 port_info->phy_info[i].handle =
3129 le16_to_cpu(expander_data->DevHandle);
3130 port_info->phy_info[i].identify.sas_address =
3131 le64_to_cpu(sas_address);
3132 port_info->phy_info[i].identify.handle_parent =
3133 le16_to_cpu(expander_data->ParentDevHandle);
3134 }
3135
3136 mutex_lock(&ioc->sas_topology_mutex);
3137 list_add_tail(&port_info->list, &ioc->sas_topology);
3138 mutex_unlock(&ioc->sas_topology_mutex);
3139
3140 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3141 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3142 (unsigned long long)sas_address);
3143
3144 mptsas_expander_refresh(ioc, port_info);
3145}
3146
3147/**
3148 * mptsas_delete_expander_siblings - remove siblings attached to expander
3149 * @ioc: Pointer to MPT_ADAPTER structure
3150 * @parent: the parent port_info object
3151 * @expander: the expander port_info object
3152 **/
3153static void
3154mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3155 *parent, struct mptsas_portinfo *expander)
3156{
3157 struct mptsas_phyinfo *phy_info;
3158 struct mptsas_portinfo *port_info;
3159 struct sas_rphy *rphy;
3160 int i;
3161
3162 phy_info = expander->phy_info;
3163 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3164 rphy = mptsas_get_rphy(phy_info);
3165 if (!rphy)
3166 continue;
3167 if (rphy->identify.device_type == SAS_END_DEVICE)
3168 mptsas_del_end_device(ioc, phy_info);
3169 }
3170
3171 phy_info = expander->phy_info;
3172 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3173 rphy = mptsas_get_rphy(phy_info);
3174 if (!rphy)
3175 continue;
3176 if (rphy->identify.device_type ==
3177 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3178 rphy->identify.device_type ==
3179 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3180 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3181 rphy->identify.sas_address);
3182 if (!port_info)
3183 continue;
3184 if (port_info == parent) /* backlink rphy */
3185 continue;
3186 /*
3187 Delete this expander even if the expdevpage is exists
3188 because the parent expander is already deleted
3189 */
3190 mptsas_expander_delete(ioc, port_info, 1);
3191 }
3192 }
3193}
3194
3195
3196/**
3197 * mptsas_expander_delete - remove this expander
3198 * @ioc: Pointer to MPT_ADAPTER structure
3199 * @port_info: expander port_info struct
3200 * @force: Flag to forcefully delete the expander
3201 *
3202 **/
3203
3204static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3205 struct mptsas_portinfo *port_info, u8 force)
3206{
3207
3208 struct mptsas_portinfo *parent;
3209 int i;
3210 u64 expander_sas_address;
3211 struct mptsas_phyinfo *phy_info;
3212 struct mptsas_portinfo buffer;
3213 struct mptsas_portinfo_details *port_details;
3214 struct sas_port *port;
3215
3216 if (!port_info)
3217 return;
3218
3219 /* see if expander is still there before deleting */
3220 mptsas_sas_expander_pg0(ioc, &buffer,
3221 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3222 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3223 port_info->phy_info[0].identify.handle);
3224
3225 if (buffer.num_phys) {
3226 kfree(buffer.phy_info);
3227 if (!force)
3228 return;
3229 }
3230
3231
3232 /*
3233 * Obtain the port_info instance to the parent port
3234 */
3235 port_details = NULL;
3236 expander_sas_address =
3237 port_info->phy_info[0].identify.sas_address;
3238 parent = mptsas_find_portinfo_by_handle(ioc,
3239 port_info->phy_info[0].identify.handle_parent);
3240 mptsas_delete_expander_siblings(ioc, parent, port_info);
3241 if (!parent)
3242 goto out;
3243
3244 /*
3245 * Delete rphys in the parent that point
3246 * to this expander.
3247 */
3248 phy_info = parent->phy_info;
3249 port = NULL;
3250 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3251 if (!phy_info->phy)
3252 continue;
3253 if (phy_info->attached.sas_address !=
3254 expander_sas_address)
3255 continue;
3256 if (!port) {
3257 port = mptsas_get_port(phy_info);
3258 port_details = phy_info->port_details;
3259 }
3260 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3261 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3262 phy_info->phy_id, phy_info->phy);
3263 sas_port_delete_phy(port, phy_info->phy);
3264 }
3265 if (port) {
3266 dev_printk(KERN_DEBUG, &port->dev,
3267 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3268 ioc->name, port->port_identifier,
3269 (unsigned long long)expander_sas_address);
3270 sas_port_delete(port);
3271 mptsas_port_delete(ioc, port_details);
3272 }
3273 out:
3274
3275 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3276 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3277 (unsigned long long)expander_sas_address);
3278
3279 /*
3280 * free link
3281 */
3282 list_del(&port_info->list);
3283 kfree(port_info->phy_info);
3284 kfree(port_info);
3285}
3286
3287
3288/**
3289 * mptsas_send_expander_event - expanders events
3290 * @ioc: Pointer to MPT_ADAPTER structure
3291 * @expander_data: event data
3292 *
3293 *
3294 * This function handles adding, removing, and refreshing
3295 * device handles within the expander objects.
3296 */
3297static void
3298mptsas_send_expander_event(struct fw_event_work *fw_event)
3299{
3300 MPT_ADAPTER *ioc;
3301 MpiEventDataSasExpanderStatusChange_t *expander_data;
3302 struct mptsas_portinfo *port_info;
3303 __le64 sas_address;
3304 int i;
3305
3306 ioc = fw_event->ioc;
3307 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3308 fw_event->event_data;
3309 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3310 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3311
3312 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3313 if (port_info) {
3314 for (i = 0; i < port_info->num_phys; i++) {
3315 port_info->phy_info[i].portinfo = port_info;
3316 port_info->phy_info[i].handle =
3317 le16_to_cpu(expander_data->DevHandle);
3318 port_info->phy_info[i].identify.sas_address =
3319 le64_to_cpu(sas_address);
3320 port_info->phy_info[i].identify.handle_parent =
3321 le16_to_cpu(expander_data->ParentDevHandle);
3322 }
3323 mptsas_expander_refresh(ioc, port_info);
3324 } else if (!port_info && expander_data->NumPhys)
3325 mptsas_expander_event_add(ioc, expander_data);
3326 } else if (expander_data->ReasonCode ==
3327 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3328 mptsas_expander_delete(ioc, port_info, 0);
3329
3330 mptsas_free_fw_event(ioc, fw_event);
3331}
3332
3333
3334/**
3335 * mptsas_expander_add -
3336 * @ioc: Pointer to MPT_ADAPTER structure
3337 * @handle:
3338 *
3339 */
3340struct mptsas_portinfo *
3341mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3342{
3343 struct mptsas_portinfo buffer, *port_info;
3344 int i;
3345
3346 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3347 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3348 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3349 return NULL;
3350
3351 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3352 if (!port_info) {
3353 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3354 "%s: exit at line=%d\n", ioc->name,
3355 __func__, __LINE__));
3356 return NULL;
3357 }
3358 port_info->num_phys = buffer.num_phys;
3359 port_info->phy_info = buffer.phy_info;
3360 for (i = 0; i < port_info->num_phys; i++)
3361 port_info->phy_info[i].portinfo = port_info;
3362 mutex_lock(&ioc->sas_topology_mutex);
3363 list_add_tail(&port_info->list, &ioc->sas_topology);
3364 mutex_unlock(&ioc->sas_topology_mutex);
3365 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3366 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3367 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3368 mptsas_expander_refresh(ioc, port_info);
3369 return port_info;
3370}
3371
3372static void
3373mptsas_send_link_status_event(struct fw_event_work *fw_event)
3374{
3375 MPT_ADAPTER *ioc;
3376 MpiEventDataSasPhyLinkStatus_t *link_data;
3377 struct mptsas_portinfo *port_info;
3378 struct mptsas_phyinfo *phy_info = NULL;
3379 __le64 sas_address;
3380 u8 phy_num;
3381 u8 link_rate;
3382
3383 ioc = fw_event->ioc;
3384 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3385
3386 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3387 sas_address = le64_to_cpu(sas_address);
3388 link_rate = link_data->LinkRates >> 4;
3389 phy_num = link_data->PhyNum;
3390
3391 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3392 if (port_info) {
3393 phy_info = &port_info->phy_info[phy_num];
3394 if (phy_info)
3395 phy_info->negotiated_link_rate = link_rate;
3396 }
3397
3398 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3399 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3400
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303401 if (!port_info) {
3402 if (ioc->old_sas_discovery_protocal) {
3403 port_info = mptsas_expander_add(ioc,
3404 le16_to_cpu(link_data->DevHandle));
3405 if (port_info)
3406 goto out;
3407 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303408 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303409 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303410
3411 if (port_info == ioc->hba_port_info)
3412 mptsas_probe_hba_phys(ioc);
3413 else
3414 mptsas_expander_refresh(ioc, port_info);
3415 } else if (phy_info && phy_info->phy) {
3416 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3417 phy_info->phy->negotiated_linkrate =
3418 SAS_PHY_DISABLED;
3419 else if (link_rate ==
3420 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3421 phy_info->phy->negotiated_linkrate =
3422 SAS_LINK_RATE_FAILED;
3423 else
3424 phy_info->phy->negotiated_linkrate =
3425 SAS_LINK_RATE_UNKNOWN;
3426 }
3427 out:
3428 mptsas_free_fw_event(ioc, fw_event);
3429}
3430
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303431static void
3432mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3433{
3434 struct mptsas_portinfo buffer, *port_info;
3435 struct mptsas_device_info *sas_info;
3436 struct mptsas_devinfo sas_device;
3437 u32 handle;
3438 VirtTarget *vtarget = NULL;
3439 struct mptsas_phyinfo *phy_info;
3440 u8 found_expander;
3441 int retval, retry_count;
3442 unsigned long flags;
3443
3444 mpt_findImVolumes(ioc);
3445
3446 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3447 if (ioc->ioc_reset_in_progress) {
3448 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3449 "%s: exiting due to a parallel reset \n", ioc->name,
3450 __func__));
3451 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3452 return;
3453 }
3454 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3455
3456 /* devices, logical volumes */
3457 mutex_lock(&ioc->sas_device_info_mutex);
3458 redo_device_scan:
3459 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303460 if (sas_info->is_cached)
3461 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303462 if (!sas_info->is_logical_volume) {
3463 sas_device.handle = 0;
3464 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303465retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303466 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303467 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3468 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3469 (sas_info->fw.channel << 8) +
3470 sas_info->fw.id);
3471
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303472 if (sas_device.handle)
3473 continue;
3474 if (retval == -EBUSY) {
3475 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3476 if (ioc->ioc_reset_in_progress) {
3477 dfailprintk(ioc,
3478 printk(MYIOC_s_DEBUG_FMT
3479 "%s: exiting due to reset\n",
3480 ioc->name, __func__));
3481 spin_unlock_irqrestore
3482 (&ioc->taskmgmt_lock, flags);
3483 mutex_unlock(&ioc->
3484 sas_device_info_mutex);
3485 return;
3486 }
3487 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3488 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303489 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303490
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303491 if (retval && (retval != -ENODEV)) {
3492 if (retry_count < 10) {
3493 retry_count++;
3494 goto retry_page;
3495 } else {
3496 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3497 "%s: Config page retry exceeded retry "
3498 "count deleting device 0x%llx\n",
3499 ioc->name, __func__,
3500 sas_info->sas_address));
3501 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303502 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303503
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303504 /* delete device */
3505 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303506 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303507
3508 if (vtarget)
3509 vtarget->deleted = 1;
3510
3511 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3512 sas_info->sas_address);
3513
3514 if (phy_info) {
3515 mptsas_del_end_device(ioc, phy_info);
3516 goto redo_device_scan;
3517 }
3518 } else
3519 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303520 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003521 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303522
3523 /* expanders */
3524 mutex_lock(&ioc->sas_topology_mutex);
3525 redo_expander_scan:
3526 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3527
3528 if (port_info->phy_info &&
3529 (!(port_info->phy_info[0].identify.device_info &
3530 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3531 continue;
3532 found_expander = 0;
3533 handle = 0xFFFF;
3534 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3535 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3536 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3537 !found_expander) {
3538
3539 handle = buffer.phy_info[0].handle;
3540 if (buffer.phy_info[0].identify.sas_address ==
3541 port_info->phy_info[0].identify.sas_address) {
3542 found_expander = 1;
3543 }
3544 kfree(buffer.phy_info);
3545 }
3546
3547 if (!found_expander) {
3548 mptsas_expander_delete(ioc, port_info, 0);
3549 goto redo_expander_scan;
3550 }
3551 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003552 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303553}
3554
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303555/**
3556 * mptsas_probe_expanders - adding expanders
3557 * @ioc: Pointer to MPT_ADAPTER structure
3558 *
3559 **/
3560static void
3561mptsas_probe_expanders(MPT_ADAPTER *ioc)
3562{
3563 struct mptsas_portinfo buffer, *port_info;
3564 u32 handle;
3565 int i;
3566
3567 handle = 0xFFFF;
3568 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3569 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3570 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3571
3572 handle = buffer.phy_info[0].handle;
3573 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3574 buffer.phy_info[0].identify.sas_address);
3575
3576 if (port_info) {
3577 /* refreshing handles */
3578 for (i = 0; i < buffer.num_phys; i++) {
3579 port_info->phy_info[i].handle = handle;
3580 port_info->phy_info[i].identify.handle_parent =
3581 buffer.phy_info[0].identify.handle_parent;
3582 }
3583 mptsas_expander_refresh(ioc, port_info);
3584 kfree(buffer.phy_info);
3585 continue;
3586 }
3587
3588 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3589 if (!port_info) {
3590 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3591 "%s: exit at line=%d\n", ioc->name,
3592 __func__, __LINE__));
3593 return;
3594 }
3595 port_info->num_phys = buffer.num_phys;
3596 port_info->phy_info = buffer.phy_info;
3597 for (i = 0; i < port_info->num_phys; i++)
3598 port_info->phy_info[i].portinfo = port_info;
3599 mutex_lock(&ioc->sas_topology_mutex);
3600 list_add_tail(&port_info->list, &ioc->sas_topology);
3601 mutex_unlock(&ioc->sas_topology_mutex);
3602 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3603 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3604 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3605 mptsas_expander_refresh(ioc, port_info);
3606 }
3607}
3608
3609static void
3610mptsas_probe_devices(MPT_ADAPTER *ioc)
3611{
3612 u16 handle;
3613 struct mptsas_devinfo sas_device;
3614 struct mptsas_phyinfo *phy_info;
3615
3616 handle = 0xFFFF;
3617 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3618 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3619
3620 handle = sas_device.handle;
3621
3622 if ((sas_device.device_info &
3623 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3624 MPI_SAS_DEVICE_INFO_STP_TARGET |
3625 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3626 continue;
3627
3628 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3629 if (!phy_info)
3630 continue;
3631
3632 if (mptsas_get_rphy(phy_info))
3633 continue;
3634
3635 mptsas_add_end_device(ioc, phy_info);
3636 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003637}
3638
Kashyap, Desai2f187862009-05-29 16:52:37 +05303639/**
3640 * mptsas_scan_sas_topology -
3641 * @ioc: Pointer to MPT_ADAPTER structure
3642 * @sas_address:
3643 *
3644 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003645static void
3646mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3647{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303648 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003649 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003650
Moore, Erice6b2d762006-03-14 09:14:24 -07003651 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303652 mptsas_probe_expanders(ioc);
3653 mptsas_probe_devices(ioc);
3654
Moore, Ericf44e5462006-03-14 09:14:21 -07003655 /*
3656 Reporting RAID volumes.
3657 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303658 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3659 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3660 return;
Eric Moore793955f2007-01-29 09:42:20 -07003661 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303662 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3663 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3664 if (sdev) {
3665 scsi_device_put(sdev);
3666 continue;
3667 }
3668 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3669 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3670 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003671 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003672 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3673 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003674}
3675
Kashyap, Desai57e98512009-05-29 16:55:09 +05303676
3677static void
3678mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3679{
3680 MPT_ADAPTER *ioc;
3681 EventDataQueueFull_t *qfull_data;
3682 struct mptsas_device_info *sas_info;
3683 struct scsi_device *sdev;
3684 int depth;
3685 int id = -1;
3686 int channel = -1;
3687 int fw_id, fw_channel;
3688 u16 current_depth;
3689
3690
3691 ioc = fw_event->ioc;
3692 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3693 fw_id = qfull_data->TargetID;
3694 fw_channel = qfull_data->Bus;
3695 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3696
3697 /* if hidden raid component, look for the volume id */
3698 mutex_lock(&ioc->sas_device_info_mutex);
3699 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3700 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3701 list) {
3702 if (sas_info->is_cached ||
3703 sas_info->is_logical_volume)
3704 continue;
3705 if (sas_info->is_hidden_raid_component &&
3706 (sas_info->fw.channel == fw_channel &&
3707 sas_info->fw.id == fw_id)) {
3708 id = sas_info->volume_id;
3709 channel = MPTSAS_RAID_CHANNEL;
3710 goto out;
3711 }
3712 }
3713 } else {
3714 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3715 list) {
3716 if (sas_info->is_cached ||
3717 sas_info->is_hidden_raid_component ||
3718 sas_info->is_logical_volume)
3719 continue;
3720 if (sas_info->fw.channel == fw_channel &&
3721 sas_info->fw.id == fw_id) {
3722 id = sas_info->os.id;
3723 channel = sas_info->os.channel;
3724 goto out;
3725 }
3726 }
3727
3728 }
3729
3730 out:
3731 mutex_unlock(&ioc->sas_device_info_mutex);
3732
3733 if (id != -1) {
3734 shost_for_each_device(sdev, ioc->sh) {
3735 if (sdev->id == id && sdev->channel == channel) {
3736 if (current_depth > sdev->queue_depth) {
3737 sdev_printk(KERN_INFO, sdev,
3738 "strange observation, the queue "
3739 "depth is (%d) meanwhile fw queue "
3740 "depth (%d)\n", sdev->queue_depth,
3741 current_depth);
3742 continue;
3743 }
3744 depth = scsi_track_queue_full(sdev,
3745 current_depth - 1);
3746 if (depth > 0)
3747 sdev_printk(KERN_INFO, sdev,
3748 "Queue depth reduced to (%d)\n",
3749 depth);
3750 else if (depth < 0)
3751 sdev_printk(KERN_INFO, sdev,
3752 "Tagged Command Queueing is being "
3753 "disabled\n");
3754 else if (depth == 0)
3755 sdev_printk(KERN_INFO, sdev,
3756 "Queue depth not changed yet\n");
3757 }
3758 }
3759 }
3760
3761 mptsas_free_fw_event(ioc, fw_event);
3762}
3763
3764
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003765static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003766mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003767{
3768 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003769 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003770 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003771
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003772 mutex_lock(&ioc->sas_topology_mutex);
3773 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3774 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003775 if (!mptsas_is_end_device(
3776 &port_info->phy_info[i].attached))
3777 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003778 if (port_info->phy_info[i].attached.sas_address
3779 != sas_address)
3780 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003781 phy_info = &port_info->phy_info[i];
3782 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003783 }
3784 }
3785 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003786 return phy_info;
3787}
3788
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303789/**
3790 * mptsas_find_phyinfo_by_phys_disk_num -
3791 * @ioc: Pointer to MPT_ADAPTER structure
3792 * @phys_disk_num:
3793 * @channel:
3794 * @id:
3795 *
3796 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003797static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303798mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3799 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003800{
Eric Mooreb506ade2007-01-29 09:45:37 -07003801 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303802 struct mptsas_portinfo *port_info;
3803 RaidPhysDiskPage1_t *phys_disk = NULL;
3804 int num_paths;
3805 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003806 int i;
3807
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303808 phy_info = NULL;
3809 if (!ioc->raid_data.pIocPg3)
3810 return NULL;
3811 /* dual port support */
3812 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
3813 if (!num_paths)
3814 goto out;
3815 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
3816 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
3817 if (!phys_disk)
3818 goto out;
3819 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
3820 for (i = 0; i < num_paths; i++) {
3821 if ((phys_disk->Path[i].Flags & 1) != 0)
3822 /* entry no longer valid */
3823 continue;
3824 if ((id == phys_disk->Path[i].PhysDiskID) &&
3825 (channel == phys_disk->Path[i].PhysDiskBus)) {
3826 memcpy(&sas_address, &phys_disk->Path[i].WWID,
3827 sizeof(u64));
3828 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3829 sas_address);
3830 goto out;
3831 }
3832 }
3833
3834 out:
3835 kfree(phys_disk);
3836 if (phy_info)
3837 return phy_info;
3838
3839 /*
3840 * Extra code to handle RAID0 case, where the sas_address is not updated
3841 * in phys_disk_page_1 when hotswapped
3842 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003843 mutex_lock(&ioc->sas_topology_mutex);
3844 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303845 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07003846 if (!mptsas_is_end_device(
3847 &port_info->phy_info[i].attached))
3848 continue;
3849 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3850 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303851 if ((port_info->phy_info[i].attached.phys_disk_num ==
3852 phys_disk_num) &&
3853 (port_info->phy_info[i].attached.id == id) &&
3854 (port_info->phy_info[i].attached.channel ==
3855 channel))
3856 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06003857 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003858 }
3859 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003860 return phy_info;
3861}
3862
3863static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003864mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3865{
Eric Mooref99be432007-01-04 20:46:54 -07003866 int rc;
3867
Moore, Ericf44e5462006-03-14 09:14:21 -07003868 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003869 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003870}
3871
3872static void
3873mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3874{
3875 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3876 mptsas_reprobe_lun);
3877}
3878
Eric Mooreb506ade2007-01-29 09:45:37 -07003879static void
3880mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3881{
3882 CONFIGPARMS cfg;
3883 ConfigPageHeader_t hdr;
3884 dma_addr_t dma_handle;
3885 pRaidVolumePage0_t buffer = NULL;
3886 RaidPhysDiskPage0_t phys_disk;
3887 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303888 struct mptsas_phyinfo *phy_info;
3889 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003890
3891 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3892 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3893 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3894 cfg.pageAddr = (channel << 8) + id;
3895 cfg.cfghdr.hdr = &hdr;
3896 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3897
3898 if (mpt_config(ioc, &cfg) != 0)
3899 goto out;
3900
3901 if (!hdr.PageLength)
3902 goto out;
3903
3904 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3905 &dma_handle);
3906
3907 if (!buffer)
3908 goto out;
3909
3910 cfg.physAddr = dma_handle;
3911 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3912
3913 if (mpt_config(ioc, &cfg) != 0)
3914 goto out;
3915
3916 if (!(buffer->VolumeStatus.Flags &
3917 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3918 goto out;
3919
3920 if (!buffer->NumPhysDisks)
3921 goto out;
3922
3923 for (i = 0; i < buffer->NumPhysDisks; i++) {
3924
3925 if (mpt_raid_phys_disk_pg0(ioc,
3926 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3927 continue;
3928
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303929 if (mptsas_sas_device_pg0(ioc, &sas_device,
3930 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3931 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3932 (phys_disk.PhysDiskBus << 8) +
3933 phys_disk.PhysDiskID))
3934 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003935
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303936 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3937 sas_device.sas_address);
3938 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003939 }
3940
3941 out:
3942 if (buffer)
3943 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3944 dma_handle);
3945}
Moore, Erice6b2d762006-03-14 09:14:24 -07003946/*
3947 * Work queue thread to handle SAS hotplug events
3948 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003949static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303950mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3951 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003952{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003953 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003954 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003955 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003956 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303957 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003958
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303959 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003960
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303961 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003962
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303963 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003964 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003965
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303966 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3967 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3968 hot_plug_info->id) {
3969 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3970 "to add hidden disk - target_id matchs "
3971 "volume_id\n", ioc->name);
3972 mptsas_free_fw_event(ioc, fw_event);
3973 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003974 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003975 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303976 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003977
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003978 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303979 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3980 mptsas_sas_device_pg0(ioc, &sas_device,
3981 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3982 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3983 (hot_plug_info->channel << 8) +
3984 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003985
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303986 if (!sas_device.handle)
3987 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003988
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303989 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3990 if (!phy_info)
3991 break;
3992
3993 if (mptsas_get_rphy(phy_info))
3994 break;
3995
3996 mptsas_add_end_device(ioc, phy_info);
3997 break;
3998
3999 case MPTSAS_DEL_DEVICE:
4000 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4001 hot_plug_info->sas_address);
4002 mptsas_del_end_device(ioc, phy_info);
4003 break;
4004
4005 case MPTSAS_DEL_PHYSDISK:
4006
4007 mpt_findImVolumes(ioc);
4008
4009 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304010 ioc, hot_plug_info->phys_disk_num,
4011 hot_plug_info->channel,
4012 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304013 mptsas_del_end_device(ioc, phy_info);
4014 break;
4015
4016 case MPTSAS_ADD_PHYSDISK_REPROBE:
4017
Christoph Hellwige3094442006-02-16 13:25:36 +01004018 if (mptsas_sas_device_pg0(ioc, &sas_device,
4019 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004020 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304021 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4022 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4023 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4024 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004025 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004026 }
4027
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304028 phy_info = mptsas_find_phyinfo_by_sas_address(
4029 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004030
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304031 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304032 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304033 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4034 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004035 break;
4036 }
4037
4038 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304039 if (!starget) {
4040 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4041 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4042 __func__, hot_plug_info->id, __LINE__));
4043 break;
4044 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004045
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304046 vtarget = starget->hostdata;
4047 if (!vtarget) {
4048 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4049 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4050 __func__, hot_plug_info->id, __LINE__));
4051 break;
4052 }
Eric Moore547f9a22006-06-27 14:42:12 -06004053
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304054 mpt_findImVolumes(ioc);
4055
4056 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4057 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4058 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4059 hot_plug_info->phys_disk_num, (unsigned long long)
4060 sas_device.sas_address);
4061
4062 vtarget->id = hot_plug_info->phys_disk_num;
4063 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4064 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4065 mptsas_reprobe_target(starget, 1);
4066 break;
4067
4068 case MPTSAS_DEL_PHYSDISK_REPROBE:
4069
4070 if (mptsas_sas_device_pg0(ioc, &sas_device,
4071 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4072 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4073 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304074 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304075 "%s: fw_id=%d exit at line=%d\n",
4076 ioc->name, __func__,
4077 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004078 break;
4079 }
4080
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304081 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4082 sas_device.sas_address);
4083 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304084 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304085 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4086 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004087 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004088 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004089
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304090 starget = mptsas_get_starget(phy_info);
4091 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304092 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304093 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4094 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004095 break;
4096 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004097
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304098 vtarget = starget->hostdata;
4099 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304100 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304101 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4102 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004103 break;
4104 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304105
4106 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4107 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4108 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4109 __func__, hot_plug_info->id, __LINE__));
4110 break;
4111 }
4112
4113 mpt_findImVolumes(ioc);
4114
4115 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4116 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4117 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4118 hot_plug_info->phys_disk_num, (unsigned long long)
4119 sas_device.sas_address);
4120
4121 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4122 vtarget->id = hot_plug_info->id;
4123 phy_info->attached.phys_disk_num = ~0;
4124 mptsas_reprobe_target(starget, 0);
4125 mptsas_add_device_component_by_fw(ioc,
4126 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004127 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304128
Moore, Ericc73787ee2006-01-26 16:20:06 -07004129 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304130
Moore, Ericc73787ee2006-01-26 16:20:06 -07004131 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304132 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4133 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4134 hot_plug_info->id);
4135 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4136 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004137 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304138
Moore, Ericc73787ee2006-01-26 16:20:06 -07004139 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304140
Moore, Ericc73787ee2006-01-26 16:20:06 -07004141 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304142 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4143 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4144 hot_plug_info->id);
4145 scsi_remove_device(hot_plug_info->sdev);
4146 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004147 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304148
Eric Mooreb506ade2007-01-29 09:45:37 -07004149 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304150
4151 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004152 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304153 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004154 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304155
Moore, Ericbd23e942006-04-17 12:43:04 -06004156 default:
4157 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004158 }
4159
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304160 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004161}
4162
4163static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304164mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004165{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304166 MPT_ADAPTER *ioc;
4167 struct mptsas_hotplug_event hot_plug_info;
4168 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4169 u32 device_info;
4170 u64 sas_address;
4171
4172 ioc = fw_event->ioc;
4173 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4174 fw_event->event_data;
4175 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004176
4177 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304178 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4179 MPI_SAS_DEVICE_INFO_STP_TARGET |
4180 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4181 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004182 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304183 }
4184
4185 if (sas_event_data->ReasonCode ==
4186 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4187 mptbase_sas_persist_operation(ioc,
4188 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4189 mptsas_free_fw_event(ioc, fw_event);
4190 return;
4191 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004192
Moore, Eric4b766472006-03-14 09:14:12 -07004193 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004194 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004195 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304196 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4197 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4198 hot_plug_info.channel = sas_event_data->Bus;
4199 hot_plug_info.id = sas_event_data->TargetID;
4200 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004201 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304202 sizeof(u64));
4203 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4204 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004205 if (sas_event_data->ReasonCode &
4206 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304207 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004208 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304209 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4210 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004211 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304212
Moore, Eric4b766472006-03-14 09:14:12 -07004213 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304214 mptbase_sas_persist_operation(ioc,
4215 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4216 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004217 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304218
Moore, Eric4b766472006-03-14 09:14:12 -07004219 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304220 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004221 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304222 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004223 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304224 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004225 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004226 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004227}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304228
Moore, Ericc73787ee2006-01-26 16:20:06 -07004229static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304230mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004231{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304232 MPT_ADAPTER *ioc;
4233 EVENT_DATA_RAID *raid_event_data;
4234 struct mptsas_hotplug_event hot_plug_info;
4235 int status;
4236 int state;
4237 struct scsi_device *sdev = NULL;
4238 VirtDevice *vdevice = NULL;
4239 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004240
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304241 ioc = fw_event->ioc;
4242 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4243 status = le32_to_cpu(raid_event_data->SettingsStatus);
4244 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004245
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304246 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4247 hot_plug_info.id = raid_event_data->VolumeID;
4248 hot_plug_info.channel = raid_event_data->VolumeBus;
4249 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4250
4251 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4252 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4253 raid_event_data->ReasonCode ==
4254 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4255 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4256 hot_plug_info.id, 0);
4257 hot_plug_info.sdev = sdev;
4258 if (sdev)
4259 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004260 }
4261
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304262 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4263 "ReasonCode=%02x\n", ioc->name, __func__,
4264 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004265
4266 switch (raid_event_data->ReasonCode) {
4267 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304268 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004269 break;
4270 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304271 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004272 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004273 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4274 switch (state) {
4275 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004276 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304277 mpt_raid_phys_disk_pg0(ioc,
4278 raid_event_data->PhysDiskNum, &phys_disk);
4279 hot_plug_info.id = phys_disk.PhysDiskID;
4280 hot_plug_info.channel = phys_disk.PhysDiskBus;
4281 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004282 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304283 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004284 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004285 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4286 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4287 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304288 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004289 break;
4290 default:
4291 break;
4292 }
4293 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004294 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304295 if (!sdev)
4296 break;
4297 vdevice->vtarget->deleted = 1; /* block IO */
4298 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004299 break;
4300 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304301 if (sdev) {
4302 scsi_device_put(sdev);
4303 break;
4304 }
4305 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004306 break;
4307 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304308 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4309 if (!sdev)
4310 break;
4311 vdevice->vtarget->deleted = 1; /* block IO */
4312 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4313 break;
4314 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004315 switch (state) {
4316 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4317 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304318 if (!sdev)
4319 break;
4320 vdevice->vtarget->deleted = 1; /* block IO */
4321 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004322 break;
4323 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4324 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304325 if (sdev) {
4326 scsi_device_put(sdev);
4327 break;
4328 }
4329 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004330 break;
4331 default:
4332 break;
4333 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004334 break;
4335 default:
4336 break;
4337 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304338
4339 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4340 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4341 else
4342 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004343}
4344
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304345/**
4346 * mptsas_issue_tm - send mptsas internal tm request
4347 * @ioc: Pointer to MPT_ADAPTER structure
4348 * @type: Task Management type
4349 * @channel: channel number for task management
4350 * @id: Logical Target ID for reset (if appropriate)
4351 * @lun: Logical unit for reset (if appropriate)
4352 * @task_context: Context for the task to be aborted
4353 * @timeout: timeout for task management control
4354 *
4355 * return 0 on success and -1 on failure:
4356 *
4357 */
4358static int
4359mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4360 int task_context, ulong timeout, u8 *issue_reset)
4361{
4362 MPT_FRAME_HDR *mf;
4363 SCSITaskMgmt_t *pScsiTm;
4364 int retval;
4365 unsigned long timeleft;
4366
4367 *issue_reset = 0;
4368 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4369 if (mf == NULL) {
4370 retval = -1; /* return failure */
4371 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4372 "msg frames!!\n", ioc->name));
4373 goto out;
4374 }
4375
4376 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4377 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4378 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4379 type, timeout, channel, id, (unsigned long long)lun,
4380 task_context));
4381
4382 pScsiTm = (SCSITaskMgmt_t *) mf;
4383 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4384 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4385 pScsiTm->TaskType = type;
4386 pScsiTm->MsgFlags = 0;
4387 pScsiTm->TargetID = id;
4388 pScsiTm->Bus = channel;
4389 pScsiTm->ChainOffset = 0;
4390 pScsiTm->Reserved = 0;
4391 pScsiTm->Reserved1 = 0;
4392 pScsiTm->TaskMsgContext = task_context;
4393 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4394
4395 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4396 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4397 retval = 0;
4398 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4399
4400 /* Now wait for the command to complete */
4401 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4402 timeout*HZ);
4403 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4404 retval = -1; /* return failure */
4405 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4406 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4407 mpt_free_msg_frame(ioc, mf);
4408 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4409 goto out;
4410 *issue_reset = 1;
4411 goto out;
4412 }
4413
4414 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4415 retval = -1; /* return failure */
4416 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4417 "TaskMgmt request: failed with no reply\n", ioc->name));
4418 goto out;
4419 }
4420
4421 out:
4422 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4423 return retval;
4424}
4425
4426/**
4427 * mptsas_broadcast_primative_work - Handle broadcast primitives
4428 * @work: work queue payload containing info describing the event
4429 *
4430 * this will be handled in workqueue context.
4431 */
4432static void
4433mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4434{
4435 MPT_ADAPTER *ioc = fw_event->ioc;
4436 MPT_FRAME_HDR *mf;
4437 VirtDevice *vdevice;
4438 int ii;
4439 struct scsi_cmnd *sc;
4440 SCSITaskMgmtReply_t *pScsiTmReply;
4441 u8 issue_reset;
4442 int task_context;
4443 u8 channel, id;
4444 int lun;
4445 u32 termination_count;
4446 u32 query_count;
4447
4448 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4449 "%s - enter\n", ioc->name, __func__));
4450
4451 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4452 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4453 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4454 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4455 return;
4456 }
4457
4458 issue_reset = 0;
4459 termination_count = 0;
4460 query_count = 0;
4461 mpt_findImVolumes(ioc);
4462 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4463
4464 for (ii = 0; ii < ioc->req_depth; ii++) {
4465 if (ioc->fw_events_off)
4466 goto out;
4467 sc = mptscsih_get_scsi_lookup(ioc, ii);
4468 if (!sc)
4469 continue;
4470 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4471 if (!mf)
4472 continue;
4473 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4474 vdevice = sc->device->hostdata;
4475 if (!vdevice || !vdevice->vtarget)
4476 continue;
4477 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4478 continue; /* skip hidden raid components */
4479 if (vdevice->vtarget->raidVolume)
4480 continue; /* skip hidden raid components */
4481 channel = vdevice->vtarget->channel;
4482 id = vdevice->vtarget->id;
4483 lun = vdevice->lun;
4484 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4485 channel, id, (u64)lun, task_context, 30, &issue_reset))
4486 goto out;
4487 query_count++;
4488 termination_count +=
4489 le32_to_cpu(pScsiTmReply->TerminationCount);
4490 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4491 (pScsiTmReply->ResponseCode ==
4492 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4493 pScsiTmReply->ResponseCode ==
4494 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4495 continue;
4496 if (mptsas_issue_tm(ioc,
4497 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4498 channel, id, (u64)lun, 0, 30, &issue_reset))
4499 goto out;
4500 termination_count +=
4501 le32_to_cpu(pScsiTmReply->TerminationCount);
4502 }
4503
4504 out:
4505 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4506 "%s - exit, query_count = %d termination_count = %d\n",
4507 ioc->name, __func__, query_count, termination_count));
4508
4509 ioc->broadcast_aen_busy = 0;
4510 mpt_clear_taskmgmt_in_progress_flag(ioc);
4511 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4512
4513 if (issue_reset) {
4514 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4515 ioc->name, __func__);
4516 mpt_HardResetHandler(ioc, CAN_SLEEP);
4517 }
4518 mptsas_free_fw_event(ioc, fw_event);
4519}
4520
Eric Mooreb506ade2007-01-29 09:45:37 -07004521/*
4522 * mptsas_send_ir2_event - handle exposing hidden disk when
4523 * an inactive raid volume is added
4524 *
4525 * @ioc: Pointer to MPT_ADAPTER structure
4526 * @ir2_data
4527 *
4528 */
4529static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304530mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004531{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304532 MPT_ADAPTER *ioc;
4533 struct mptsas_hotplug_event hot_plug_info;
4534 MPI_EVENT_DATA_IR2 *ir2_data;
4535 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304536 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004537
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304538 ioc = fw_event->ioc;
4539 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4540 reasonCode = ir2_data->ReasonCode;
4541
4542 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4543 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4544
4545 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4546 hot_plug_info.id = ir2_data->TargetID;
4547 hot_plug_info.channel = ir2_data->Bus;
4548 switch (reasonCode) {
4549 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4550 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4551 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304552 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4553 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4554 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4555 break;
4556 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4557 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4558 mpt_raid_phys_disk_pg0(ioc,
4559 ir2_data->PhysDiskNum, &phys_disk);
4560 hot_plug_info.id = phys_disk.PhysDiskID;
4561 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4562 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304563 default:
4564 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004565 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304566 }
4567 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4568}
Moore, Erice6b2d762006-03-14 09:14:24 -07004569
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004570static int
4571mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4572{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304573 u32 event = le32_to_cpu(reply->Event);
4574 int sz, event_data_sz;
4575 struct fw_event_work *fw_event;
4576 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004577
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304578 /* events turned off due to host reset or driver unloading */
4579 if (ioc->fw_events_off)
4580 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004581
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304582 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004583 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304584 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4585 {
4586 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4587 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4588 if (broadcast_event_data->Primitive !=
4589 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4590 return 0;
4591 if (ioc->broadcast_aen_busy)
4592 return 0;
4593 ioc->broadcast_aen_busy = 1;
4594 break;
4595 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004596 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304597 {
4598 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4599 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4600
4601 if (sas_event_data->ReasonCode ==
4602 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4603 mptsas_target_reset_queue(ioc, sas_event_data);
4604 return 0;
4605 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004606 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304607 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304608 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4609 {
4610 MpiEventDataSasExpanderStatusChange_t *expander_data =
4611 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4612
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304613 if (ioc->old_sas_discovery_protocal)
4614 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304615
4616 if (expander_data->ReasonCode ==
4617 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4618 ioc->device_missing_delay)
4619 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004620 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304621 }
4622 case MPI_EVENT_SAS_DISCOVERY:
4623 {
4624 u32 discovery_status;
4625 EventDataSasDiscovery_t *discovery_data =
4626 (EventDataSasDiscovery_t *)reply->Data;
4627
4628 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4629 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304630 if (ioc->old_sas_discovery_protocal && !discovery_status)
4631 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304632 return 0;
4633 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304634 case MPI_EVENT_INTEGRATED_RAID:
4635 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004636 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304637 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4638 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004639 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004640 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304641 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004642 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004643
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304644 event_data_sz = ((reply->MsgLength * 4) -
4645 offsetof(EventNotificationReply_t, Data));
4646 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4647 fw_event = kzalloc(sz, GFP_ATOMIC);
4648 if (!fw_event) {
4649 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4650 __func__, __LINE__);
4651 return 0;
4652 }
4653 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4654 fw_event->event = event;
4655 fw_event->ioc = ioc;
4656 mptsas_add_fw_event(ioc, fw_event, delay);
4657 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004658}
4659
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304660/* Delete a volume when no longer listed in ioc pg2
4661 */
4662static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4663{
4664 struct scsi_device *sdev;
4665 int i;
4666
4667 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4668 if (!sdev)
4669 return;
4670 if (!ioc->raid_data.pIocPg2)
4671 goto out;
4672 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4673 goto out;
4674 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4675 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4676 goto release_sdev;
4677 out:
4678 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4679 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4680 scsi_remove_device(sdev);
4681 release_sdev:
4682 scsi_device_put(sdev);
4683}
4684
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004685static int
4686mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4687{
4688 struct Scsi_Host *sh;
4689 MPT_SCSI_HOST *hd;
4690 MPT_ADAPTER *ioc;
4691 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004692 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004693 int numSGE = 0;
4694 int scale;
4695 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004696 int error=0;
4697 int r;
4698
4699 r = mpt_attach(pdev,id);
4700 if (r)
4701 return r;
4702
4703 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304704 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004705 ioc->DoneCtx = mptsasDoneCtx;
4706 ioc->TaskCtx = mptsasTaskCtx;
4707 ioc->InternalCtx = mptsasInternalCtx;
4708
4709 /* Added sanity check on readiness of the MPT adapter.
4710 */
4711 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4712 printk(MYIOC_s_WARN_FMT
4713 "Skipping because it's not operational!\n",
4714 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004715 error = -ENODEV;
4716 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004717 }
4718
4719 if (!ioc->active) {
4720 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4721 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004722 error = -ENODEV;
4723 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004724 }
4725
4726 /* Sanity check - ensure at least 1 port is INITIATOR capable
4727 */
4728 ioc_cap = 0;
4729 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4730 if (ioc->pfacts[ii].ProtocolFlags &
4731 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4732 ioc_cap++;
4733 }
4734
4735 if (!ioc_cap) {
4736 printk(MYIOC_s_WARN_FMT
4737 "Skipping ioc=%p because SCSI Initiator mode "
4738 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004739 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004740 }
4741
4742 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4743 if (!sh) {
4744 printk(MYIOC_s_WARN_FMT
4745 "Unable to register controller with SCSI subsystem\n",
4746 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004747 error = -1;
4748 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004749 }
4750
4751 spin_lock_irqsave(&ioc->FreeQlock, flags);
4752
4753 /* Attach the SCSI Host to the IOC structure
4754 */
4755 ioc->sh = sh;
4756
4757 sh->io_port = 0;
4758 sh->n_io_port = 0;
4759 sh->irq = 0;
4760
4761 /* set 16 byte cdb's */
4762 sh->max_cmd_len = 16;
4763
Eric Moore793955f2007-01-29 09:42:20 -07004764 sh->max_id = ioc->pfacts[0].PortSCSIID;
4765 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004766
4767 sh->transportt = mptsas_transport_template;
4768
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004769 /* Required entry.
4770 */
4771 sh->unique_id = ioc->id;
4772
4773 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004774 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004775 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004776 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004777 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004778
4779 /* Verify that we won't exceed the maximum
4780 * number of chain buffers
4781 * We can optimize: ZZ = req_sz/sizeof(SGE)
4782 * For 32bit SGE's:
4783 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4784 * + (req_sz - 64)/sizeof(SGE)
4785 * A slightly different algorithm is required for
4786 * 64bit SGEs.
4787 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304788 scale = ioc->req_sz/ioc->SGE_size;
4789 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004790 numSGE = (scale - 1) *
4791 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304792 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004793 } else {
4794 numSGE = 1 + (scale - 1) *
4795 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304796 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004797 }
4798
4799 if (numSGE < sh->sg_tablesize) {
4800 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304801 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004802 "Resetting sg_tablesize to %d from %d\n",
4803 ioc->name, numSGE, sh->sg_tablesize));
4804 sh->sg_tablesize = numSGE;
4805 }
4806
Eric Mooree7eae9f2007-09-29 10:15:59 -06004807 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004808 hd->ioc = ioc;
4809
4810 /* SCSI needs scsi_cmnd lookup table!
4811 * (with size equal to req_depth*PtrSz!)
4812 */
Eric Mooree8206382007-09-29 10:16:53 -06004813 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4814 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004815 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004816 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004817 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004818 }
Eric Mooree8206382007-09-29 10:16:53 -06004819 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004820
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304821 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004822 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004823
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004824 /* Clear the TM flags
4825 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004826 hd->abortSCpnt = NULL;
4827
4828 /* Clear the pointer used to store
4829 * single-threaded commands, i.e., those
4830 * issued during a bus scan, dv and
4831 * configuration pages.
4832 */
4833 hd->cmdPtr = NULL;
4834
4835 /* Initialize this SCSI Hosts' timers
4836 * To use, set the timer expires field
4837 * and add_timer
4838 */
4839 init_timer(&hd->timer);
4840 hd->timer.data = (unsigned long) hd;
4841 hd->timer.function = mptscsih_timer_expired;
4842
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004843 ioc->sas_data.ptClear = mpt_pt_clear;
4844
Eric Mooredf9e0622007-01-29 09:46:21 -07004845 hd->last_queue_full = 0;
4846 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304847 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4848 mutex_init(&ioc->sas_device_info_mutex);
4849
Eric Mooredf9e0622007-01-29 09:46:21 -07004850 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4851
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004852 if (ioc->sas_data.ptClear==1) {
4853 mptbase_sas_persist_operation(
4854 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4855 }
4856
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004857 error = scsi_add_host(sh, &ioc->pcidev->dev);
4858 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004859 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4860 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004861 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004862 }
4863
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304864 /* older firmware doesn't support expander events */
4865 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4866 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004867 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304868 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004869 return 0;
4870
Eric Moore547f9a22006-06-27 14:42:12 -06004871 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004872
4873 mptscsih_remove(pdev);
4874 return error;
4875}
4876
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304877void
4878mptsas_shutdown(struct pci_dev *pdev)
4879{
4880 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4881
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304882 mptsas_fw_event_off(ioc);
4883 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304884}
4885
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004886static void __devexit mptsas_remove(struct pci_dev *pdev)
4887{
4888 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4889 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004890 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004891
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304892 mptsas_shutdown(pdev);
4893
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304894 mptsas_del_device_components(ioc);
4895
Eric Mooreb506ade2007-01-29 09:45:37 -07004896 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004897 sas_remove_host(ioc->sh);
4898
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004899 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004900 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4901 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004902 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304903 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304904
Eric Moore547f9a22006-06-27 14:42:12 -06004905 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004906 kfree(p);
4907 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004908 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304909 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004910 mptscsih_remove(pdev);
4911}
4912
4913static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004914 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004915 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004916 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
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_SAS1064E,
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_SAS1068E,
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_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004923 PCI_ANY_ID, PCI_ANY_ID },
4924 {0} /* Terminating entry */
4925};
4926MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4927
4928
4929static struct pci_driver mptsas_driver = {
4930 .name = "mptsas",
4931 .id_table = mptsas_pci_table,
4932 .probe = mptsas_probe,
4933 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304934 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004935#ifdef CONFIG_PM
4936 .suspend = mptscsih_suspend,
4937 .resume = mptscsih_resume,
4938#endif
4939};
4940
4941static int __init
4942mptsas_init(void)
4943{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304944 int error;
4945
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004946 show_mptmod_ver(my_NAME, my_VERSION);
4947
4948 mptsas_transport_template =
4949 sas_attach_transport(&mptsas_transport_functions);
4950 if (!mptsas_transport_template)
4951 return -ENODEV;
4952
4953 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304954 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004955 mptsasInternalCtx =
4956 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004957 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304958 mptsasDeviceResetCtx =
4959 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004960
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304961 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4962 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004963
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304964 error = pci_register_driver(&mptsas_driver);
4965 if (error)
4966 sas_release_transport(mptsas_transport_template);
4967
4968 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004969}
4970
4971static void __exit
4972mptsas_exit(void)
4973{
4974 pci_unregister_driver(&mptsas_driver);
4975 sas_release_transport(mptsas_transport_template);
4976
4977 mpt_reset_deregister(mptsasDoneCtx);
4978 mpt_event_deregister(mptsasDoneCtx);
4979
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004980 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004981 mpt_deregister(mptsasInternalCtx);
4982 mpt_deregister(mptsasTaskCtx);
4983 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304984 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004985}
4986
4987module_init(mptsas_init);
4988module_exit(mptsas_exit);