blob: 72158237f5e892f6a84f84c62b84bb6a7dd807e2 [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, Desaia7938b02009-05-29 16:53:56 +0530124static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200125
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530126static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
127 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200128{
Eric Moore29dd3602007-09-14 18:46:51 -0600129 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
130 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
131 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
132 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
133 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
134 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
136 ioc->name, phy_data->Port));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
138 ioc->name, phy_data->PortFlags));
139 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
140 ioc->name, phy_data->PhyFlags));
141 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
142 ioc->name, phy_data->NegotiatedLinkRate));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
144 "Controller PHY Device Info=0x%X\n", ioc->name,
145 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
147 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200148}
149
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530150static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200151{
152 __le64 sas_address;
153
154 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
155
Eric Moore29dd3602007-09-14 18:46:51 -0600156 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
157 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
158 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
159 "Attached Device Handle=0x%X\n", ioc->name,
160 le16_to_cpu(pg0->AttachedDevHandle)));
161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
162 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
163 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
164 "Attached PHY Identifier=0x%X\n", ioc->name,
165 pg0->AttachedPhyIdentifier));
166 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
167 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
168 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
169 ioc->name, pg0->ProgrammedLinkRate));
170 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
171 ioc->name, pg0->ChangeCount));
172 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
173 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200174}
175
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530176static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200177{
Eric Moore29dd3602007-09-14 18:46:51 -0600178 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
179 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
180 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
181 ioc->name, pg1->InvalidDwordCount));
182 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
183 "Running Disparity Error Count=0x%x\n", ioc->name,
184 pg1->RunningDisparityErrorCount));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
186 "Loss Dword Synch Count=0x%x\n", ioc->name,
187 pg1->LossDwordSynchCount));
188 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
189 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
190 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200191}
192
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530193static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200194{
195 __le64 sas_address;
196
197 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
198
Eric Moore29dd3602007-09-14 18:46:51 -0600199 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
200 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
201 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
202 ioc->name, le16_to_cpu(pg0->DevHandle)));
203 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
204 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
206 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
208 ioc->name, le16_to_cpu(pg0->Slot)));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
210 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
212 ioc->name, pg0->TargetID));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
214 ioc->name, pg0->Bus));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
216 ioc->name, pg0->PhyNum));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
218 ioc->name, le16_to_cpu(pg0->AccessStatus)));
219 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
220 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
221 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
222 ioc->name, le16_to_cpu(pg0->Flags)));
223 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
224 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200225}
226
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530227static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200228{
Eric Moore29dd3602007-09-14 18:46:51 -0600229 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
230 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
231 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
232 ioc->name, pg1->PhysicalPort));
233 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
234 ioc->name, pg1->PhyIdentifier));
235 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
236 ioc->name, pg1->NegotiatedLinkRate));
237 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
238 ioc->name, pg1->ProgrammedLinkRate));
239 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
240 ioc->name, pg1->HwLinkRate));
241 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
242 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
243 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
244 "Attached Device Handle=0x%X\n\n", ioc->name,
245 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200246}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200247
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530248/* inhibit sas firmware event handling */
249static void
250mptsas_fw_event_off(MPT_ADAPTER *ioc)
251{
252 unsigned long flags;
253
254 spin_lock_irqsave(&ioc->fw_event_lock, flags);
255 ioc->fw_events_off = 1;
256 ioc->sas_discovery_quiesce_io = 0;
257 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
258
259}
260
261/* enable sas firmware event handling */
262static void
263mptsas_fw_event_on(MPT_ADAPTER *ioc)
264{
265 unsigned long flags;
266
267 spin_lock_irqsave(&ioc->fw_event_lock, flags);
268 ioc->fw_events_off = 0;
269 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
270}
271
272/* queue a sas firmware event */
273static void
274mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
275 unsigned long delay)
276{
277 unsigned long flags;
278
279 spin_lock_irqsave(&ioc->fw_event_lock, flags);
280 list_add_tail(&fw_event->list, &ioc->fw_event_list);
281 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
282 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
283 ioc->name, __func__, fw_event));
284 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
285 delay);
286 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
287}
288
289/* free memory assoicated to a sas firmware event */
290static void
291mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
292{
293 unsigned long flags;
294
295 spin_lock_irqsave(&ioc->fw_event_lock, flags);
296 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
297 ioc->name, __func__, fw_event));
298 list_del(&fw_event->list);
299 kfree(fw_event);
300 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
301}
302
303/* walk the firmware event queue, and either stop or wait for
304 * outstanding events to complete */
305static void
306mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
307{
308 struct fw_event_work *fw_event, *next;
309 struct mptsas_target_reset_event *target_reset_list, *n;
310 u8 flush_q;
311 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
312
313 /* flush the target_reset_list */
314 if (!list_empty(&hd->target_reset_list)) {
315 list_for_each_entry_safe(target_reset_list, n,
316 &hd->target_reset_list, list) {
317 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
318 "%s: removing target reset for id=%d\n",
319 ioc->name, __func__,
320 target_reset_list->sas_event_data.TargetID));
321 list_del(&target_reset_list->list);
322 kfree(target_reset_list);
323 }
324 }
325
326 if (list_empty(&ioc->fw_event_list) ||
327 !ioc->fw_event_q || in_interrupt())
328 return;
329
330 flush_q = 0;
331 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
332 if (cancel_delayed_work(&fw_event->work))
333 mptsas_free_fw_event(ioc, fw_event);
334 else
335 flush_q = 1;
336 }
337 if (flush_q)
338 flush_workqueue(ioc->fw_event_q);
339}
340
341
Christoph Hellwige3094442006-02-16 13:25:36 +0100342static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
343{
344 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
345 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
346}
347
348static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
349{
350 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
351 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
352}
353
Moore, Erice6b2d762006-03-14 09:14:24 -0700354/*
355 * mptsas_find_portinfo_by_handle
356 *
357 * This function should be called with the sas_topology_mutex already held
358 */
359static struct mptsas_portinfo *
360mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
361{
362 struct mptsas_portinfo *port_info, *rc=NULL;
363 int i;
364
365 list_for_each_entry(port_info, &ioc->sas_topology, list)
366 for (i = 0; i < port_info->num_phys; i++)
367 if (port_info->phy_info[i].identify.handle == handle) {
368 rc = port_info;
369 goto out;
370 }
371 out:
372 return rc;
373}
374
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530375/**
376 * mptsas_find_portinfo_by_sas_address -
377 * @ioc: Pointer to MPT_ADAPTER structure
378 * @handle:
379 *
380 * This function should be called with the sas_topology_mutex already held
381 *
382 **/
383static struct mptsas_portinfo *
384mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
385{
386 struct mptsas_portinfo *port_info, *rc = NULL;
387 int i;
388
389 if (sas_address >= ioc->hba_port_sas_addr &&
390 sas_address < (ioc->hba_port_sas_addr +
391 ioc->hba_port_num_phy))
392 return ioc->hba_port_info;
393
394 mutex_lock(&ioc->sas_topology_mutex);
395 list_for_each_entry(port_info, &ioc->sas_topology, list)
396 for (i = 0; i < port_info->num_phys; i++)
397 if (port_info->phy_info[i].identify.sas_address ==
398 sas_address) {
399 rc = port_info;
400 goto out;
401 }
402 out:
403 mutex_unlock(&ioc->sas_topology_mutex);
404 return rc;
405}
406
Moore, Ericbd23e942006-04-17 12:43:04 -0600407/*
408 * Returns true if there is a scsi end device
409 */
410static inline int
411mptsas_is_end_device(struct mptsas_devinfo * attached)
412{
Eric Moore547f9a22006-06-27 14:42:12 -0600413 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600414 (attached->device_info &
415 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
416 ((attached->device_info &
417 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
418 (attached->device_info &
419 MPI_SAS_DEVICE_INFO_STP_TARGET) |
420 (attached->device_info &
421 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
422 return 1;
423 else
424 return 0;
425}
426
Eric Moore547f9a22006-06-27 14:42:12 -0600427/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600428static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530429mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600430{
431 struct mptsas_portinfo *port_info;
432 struct mptsas_phyinfo *phy_info;
433 u8 i;
434
435 if (!port_details)
436 return;
437
438 port_info = port_details->port_info;
439 phy_info = port_info->phy_info;
440
Eric Moore29dd3602007-09-14 18:46:51 -0600441 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700442 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700443 port_details->num_phys, (unsigned long long)
444 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600445
446 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
447 if(phy_info->port_details != port_details)
448 continue;
449 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530450 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600451 phy_info->port_details = NULL;
452 }
453 kfree(port_details);
454}
455
456static inline struct sas_rphy *
457mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
458{
459 if (phy_info->port_details)
460 return phy_info->port_details->rphy;
461 else
462 return NULL;
463}
464
465static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530466mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600467{
468 if (phy_info->port_details) {
469 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600470 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
471 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600472 }
473
Eric Moore547f9a22006-06-27 14:42:12 -0600474 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600475 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
476 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600477 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
478 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600479 }
Eric Moore547f9a22006-06-27 14:42:12 -0600480}
481
482static inline struct sas_port *
483mptsas_get_port(struct mptsas_phyinfo *phy_info)
484{
485 if (phy_info->port_details)
486 return phy_info->port_details->port;
487 else
488 return NULL;
489}
490
491static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530492mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600493{
494 if (phy_info->port_details)
495 phy_info->port_details->port = port;
496
Eric Moore547f9a22006-06-27 14:42:12 -0600497 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600498 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
499 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600500 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
501 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600502 }
Eric Moore547f9a22006-06-27 14:42:12 -0600503}
504
505static inline struct scsi_target *
506mptsas_get_starget(struct mptsas_phyinfo *phy_info)
507{
508 if (phy_info->port_details)
509 return phy_info->port_details->starget;
510 else
511 return NULL;
512}
513
514static inline void
515mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
516starget)
517{
518 if (phy_info->port_details)
519 phy_info->port_details->starget = starget;
520}
521
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530522/**
523 * mptsas_add_device_component -
524 * @ioc: Pointer to MPT_ADAPTER structure
525 * @channel: fw mapped id's
526 * @id:
527 * @sas_address:
528 * @device_info:
529 *
530 **/
531static void
532mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
533 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
534{
535 struct mptsas_device_info *sas_info, *next;
536 struct scsi_device *sdev;
537 struct scsi_target *starget;
538 struct sas_rphy *rphy;
539
540 /*
541 * Delete all matching devices out of the list
542 */
543 mutex_lock(&ioc->sas_device_info_mutex);
544 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
545 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530546 if (!sas_info->is_logical_volume &&
547 (sas_info->sas_address == sas_address ||
548 (sas_info->fw.channel == channel &&
549 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530550 list_del(&sas_info->list);
551 kfree(sas_info);
552 }
553 }
554
555 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
556 if (!sas_info)
557 goto out;
558
559 /*
560 * Set Firmware mapping
561 */
562 sas_info->fw.id = id;
563 sas_info->fw.channel = channel;
564
565 sas_info->sas_address = sas_address;
566 sas_info->device_info = device_info;
567 sas_info->slot = slot;
568 sas_info->enclosure_logical_id = enclosure_logical_id;
569 INIT_LIST_HEAD(&sas_info->list);
570 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
571
572 /*
573 * Set OS mapping
574 */
575 shost_for_each_device(sdev, ioc->sh) {
576 starget = scsi_target(sdev);
577 rphy = dev_to_rphy(starget->dev.parent);
578 if (rphy->identify.sas_address == sas_address) {
579 sas_info->os.id = starget->id;
580 sas_info->os.channel = starget->channel;
581 }
582 }
583
584 out:
585 mutex_unlock(&ioc->sas_device_info_mutex);
586 return;
587}
588
589/**
590 * mptsas_add_device_component_by_fw -
591 * @ioc: Pointer to MPT_ADAPTER structure
592 * @channel: fw mapped id's
593 * @id:
594 *
595 **/
596static void
597mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
598{
599 struct mptsas_devinfo sas_device;
600 struct mptsas_enclosure enclosure_info;
601 int rc;
602
603 rc = mptsas_sas_device_pg0(ioc, &sas_device,
604 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
605 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
606 (channel << 8) + id);
607 if (rc)
608 return;
609
610 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
611 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
612 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
613 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
614 sas_device.handle_enclosure);
615
616 mptsas_add_device_component(ioc, sas_device.channel,
617 sas_device.id, sas_device.sas_address, sas_device.device_info,
618 sas_device.slot, enclosure_info.enclosure_logical_id);
619}
620
621/**
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530622 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding
623 * each individual device to list
624 * @ioc: Pointer to MPT_ADAPTER structure
625 * @channel: fw mapped id's
626 * @id:
627 *
628 **/
629static void
630mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
631 struct scsi_target *starget)
632{
633 CONFIGPARMS cfg;
634 ConfigPageHeader_t hdr;
635 dma_addr_t dma_handle;
636 pRaidVolumePage0_t buffer = NULL;
637 int i;
638 RaidPhysDiskPage0_t phys_disk;
639 struct mptsas_device_info *sas_info, *next;
640
641 memset(&cfg, 0 , sizeof(CONFIGPARMS));
642 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
643 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
644 /* assumption that all volumes on channel = 0 */
645 cfg.pageAddr = starget->id;
646 cfg.cfghdr.hdr = &hdr;
647 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
648 cfg.timeout = 10;
649
650 if (mpt_config(ioc, &cfg) != 0)
651 goto out;
652
653 if (!hdr.PageLength)
654 goto out;
655
656 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
657 &dma_handle);
658
659 if (!buffer)
660 goto out;
661
662 cfg.physAddr = dma_handle;
663 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
664
665 if (mpt_config(ioc, &cfg) != 0)
666 goto out;
667
668 if (!buffer->NumPhysDisks)
669 goto out;
670
671 /*
672 * Adding entry for hidden components
673 */
674 for (i = 0; i < buffer->NumPhysDisks; i++) {
675
676 if (mpt_raid_phys_disk_pg0(ioc,
677 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
678 continue;
679
680 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
681 phys_disk.PhysDiskID);
682
683 }
684
685 /*
686 * Delete all matching devices out of the list
687 */
688 mutex_lock(&ioc->sas_device_info_mutex);
689 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
690 list) {
691 if (sas_info->is_logical_volume && sas_info->fw.id ==
692 starget->id) {
693 list_del(&sas_info->list);
694 kfree(sas_info);
695 }
696 }
697
698 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
699 if (sas_info) {
700 sas_info->fw.id = starget->id;
701 sas_info->os.id = starget->id;
702 sas_info->os.channel = starget->channel;
703 sas_info->is_logical_volume = 1;
704 INIT_LIST_HEAD(&sas_info->list);
705 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
706 }
707 mutex_unlock(&ioc->sas_device_info_mutex);
708
709 out:
710 if (buffer)
711 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
712 dma_handle);
713}
714
715/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530716 * mptsas_add_device_component_starget -
717 * @ioc: Pointer to MPT_ADAPTER structure
718 * @starget:
719 *
720 **/
721static void
722mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
723 struct scsi_target *starget)
724{
725 VirtTarget *vtarget;
726 struct sas_rphy *rphy;
727 struct mptsas_phyinfo *phy_info = NULL;
728 struct mptsas_enclosure enclosure_info;
729
730 rphy = dev_to_rphy(starget->dev.parent);
731 vtarget = starget->hostdata;
732 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
733 rphy->identify.sas_address);
734 if (!phy_info)
735 return;
736
737 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
738 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
739 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
740 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
741 phy_info->attached.handle_enclosure);
742
743 mptsas_add_device_component(ioc, phy_info->attached.channel,
744 phy_info->attached.id, phy_info->attached.sas_address,
745 phy_info->attached.device_info,
746 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
747}
748
749/**
750 * mptsas_del_device_components - Cleaning the list
751 * @ioc: Pointer to MPT_ADAPTER structure
752 *
753 **/
754static void
755mptsas_del_device_components(MPT_ADAPTER *ioc)
756{
757 struct mptsas_device_info *sas_info, *next;
758
759 mutex_lock(&ioc->sas_device_info_mutex);
760 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
761 list) {
762 list_del(&sas_info->list);
763 kfree(sas_info);
764 }
765 mutex_unlock(&ioc->sas_device_info_mutex);
766}
767
Eric Moore547f9a22006-06-27 14:42:12 -0600768
769/*
770 * mptsas_setup_wide_ports
771 *
772 * Updates for new and existing narrow/wide port configuration
773 * in the sas_topology
774 */
Eric Moore376ac832006-06-29 17:36:26 -0600775static void
Eric Moore547f9a22006-06-27 14:42:12 -0600776mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
777{
778 struct mptsas_portinfo_details * port_details;
779 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
780 u64 sas_address;
781 int i, j;
782
783 mutex_lock(&ioc->sas_topology_mutex);
784
785 phy_info = port_info->phy_info;
786 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
787 if (phy_info->attached.handle)
788 continue;
789 port_details = phy_info->port_details;
790 if (!port_details)
791 continue;
792 if (port_details->num_phys < 2)
793 continue;
794 /*
795 * Removing a phy from a port, letting the last
796 * phy be removed by firmware events.
797 */
Eric Moore29dd3602007-09-14 18:46:51 -0600798 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
799 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700800 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600801 port_details->num_phys--;
802 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
803 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
804 sas_port_delete_phy(port_details->port, phy_info->phy);
805 phy_info->port_details = NULL;
806 }
807
808 /*
809 * Populate and refresh the tree
810 */
811 phy_info = port_info->phy_info;
812 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
813 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600814 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
815 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600816 if (!sas_address)
817 continue;
818 port_details = phy_info->port_details;
819 /*
820 * Forming a port
821 */
822 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530823 port_details = kzalloc(sizeof(struct
824 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600825 if (!port_details)
826 goto out;
827 port_details->num_phys = 1;
828 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600829 if (phy_info->phy_id < 64 )
830 port_details->phy_bitmask |=
831 (1 << phy_info->phy_id);
832 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600833 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700834 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600835 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600836 phy_info->port_details = port_details;
837 }
838
839 if (i == port_info->num_phys - 1)
840 continue;
841 phy_info_cmp = &port_info->phy_info[i + 1];
842 for (j = i + 1 ; j < port_info->num_phys ; j++,
843 phy_info_cmp++) {
844 if (!phy_info_cmp->attached.sas_address)
845 continue;
846 if (sas_address != phy_info_cmp->attached.sas_address)
847 continue;
848 if (phy_info_cmp->port_details == port_details )
849 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600850 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700851 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600852 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700853 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600854 if (phy_info_cmp->port_details) {
855 port_details->rphy =
856 mptsas_get_rphy(phy_info_cmp);
857 port_details->port =
858 mptsas_get_port(phy_info_cmp);
859 port_details->starget =
860 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600861 port_details->num_phys =
862 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600863 if (!phy_info_cmp->port_details->num_phys)
864 kfree(phy_info_cmp->port_details);
865 } else
866 phy_info_cmp->sas_port_add_phy=1;
867 /*
868 * Adding a phy to a port
869 */
870 phy_info_cmp->port_details = port_details;
871 if (phy_info_cmp->phy_id < 64 )
872 port_details->phy_bitmask |=
873 (1 << phy_info_cmp->phy_id);
874 port_details->num_phys++;
875 }
876 }
877
878 out:
879
Eric Moore547f9a22006-06-27 14:42:12 -0600880 for (i = 0; i < port_info->num_phys; i++) {
881 port_details = port_info->phy_info[i].port_details;
882 if (!port_details)
883 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600884 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700885 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700886 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700887 port_details, i, port_details->num_phys,
888 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600889 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
890 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600891 }
Eric Moore29dd3602007-09-14 18:46:51 -0600892 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600893 mutex_unlock(&ioc->sas_topology_mutex);
894}
895
Eric Mooredf9e0622007-01-29 09:46:21 -0700896/**
897 * csmisas_find_vtarget
898 *
899 * @ioc
900 * @volume_id
901 * @volume_bus
902 *
903 **/
904static VirtTarget *
905mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600906{
Eric Mooredf9e0622007-01-29 09:46:21 -0700907 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600908 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700909 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600910
Eric Mooredf9e0622007-01-29 09:46:21 -0700911 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530912 vdevice = sdev->hostdata;
913 if ((vdevice == NULL) ||
914 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700915 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530916 if ((vdevice->vtarget->tflags &
917 MPT_TARGET_FLAGS_RAID_COMPONENT ||
918 vdevice->vtarget->raidVolume))
919 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600920 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530921 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600922 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600923 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700924 return vtarget;
925}
926
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530927static void
928mptsas_queue_device_delete(MPT_ADAPTER *ioc,
929 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
930{
931 struct fw_event_work *fw_event;
932 int sz;
933
934 sz = offsetof(struct fw_event_work, event_data) +
935 sizeof(MpiEventDataSasDeviceStatusChange_t);
936 fw_event = kzalloc(sz, GFP_ATOMIC);
937 if (!fw_event) {
938 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
939 ioc->name, __func__, __LINE__);
940 return;
941 }
942 memcpy(fw_event->event_data, sas_event_data,
943 sizeof(MpiEventDataSasDeviceStatusChange_t));
944 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
945 fw_event->ioc = ioc;
946 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
947}
948
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530949static void
950mptsas_queue_rescan(MPT_ADAPTER *ioc)
951{
952 struct fw_event_work *fw_event;
953 int sz;
954
955 sz = offsetof(struct fw_event_work, event_data);
956 fw_event = kzalloc(sz, GFP_ATOMIC);
957 if (!fw_event) {
958 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
959 ioc->name, __func__, __LINE__);
960 return;
961 }
962 fw_event->event = -1;
963 fw_event->ioc = ioc;
964 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
965}
966
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530967
Eric Mooredf9e0622007-01-29 09:46:21 -0700968/**
969 * mptsas_target_reset
970 *
971 * Issues TARGET_RESET to end device using handshaking method
972 *
973 * @ioc
974 * @channel
975 * @id
976 *
977 * Returns (1) success
978 * (0) failure
979 *
980 **/
981static int
982mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
983{
984 MPT_FRAME_HDR *mf;
985 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530986 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
987 return 0;
988
Eric Mooredf9e0622007-01-29 09:46:21 -0700989
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530990 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
991 if (mf == NULL) {
992 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530993 "%s, no msg frames @%d!!\n", ioc->name,
994 __func__, __LINE__));
995 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -0700996 }
997
Kashyap, Desaiea2a7882009-05-29 16:46:50 +0530998 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
999 ioc->name, mf));
1000
Eric Mooredf9e0622007-01-29 09:46:21 -07001001 /* Format the Request
1002 */
1003 pScsiTm = (SCSITaskMgmt_t *) mf;
1004 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1005 pScsiTm->TargetID = id;
1006 pScsiTm->Bus = channel;
1007 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1008 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1009 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1010
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301011 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001012
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301013 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1014 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1015 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1016
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301017 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001018
1019 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301020
1021 out_fail:
1022
1023 mpt_clear_taskmgmt_in_progress_flag(ioc);
1024 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001025}
1026
1027/**
1028 * mptsas_target_reset_queue
1029 *
1030 * Receive request for TARGET_RESET after recieving an firmware
1031 * event NOT_RESPONDING_EVENT, then put command in link list
1032 * and queue if task_queue already in use.
1033 *
1034 * @ioc
1035 * @sas_event_data
1036 *
1037 **/
1038static void
1039mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1040 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1041{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001042 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001043 VirtTarget *vtarget = NULL;
1044 struct mptsas_target_reset_event *target_reset_list;
1045 u8 id, channel;
1046
1047 id = sas_event_data->TargetID;
1048 channel = sas_event_data->Bus;
1049
1050 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
1051 return;
1052
1053 vtarget->deleted = 1; /* block IO */
1054
Kashyap, Desai2f187862009-05-29 16:52:37 +05301055 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001056 GFP_ATOMIC);
1057 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301058 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1059 "%s, failed to allocate mem @%d..!!\n",
1060 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001061 return;
1062 }
1063
1064 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1065 sizeof(*sas_event_data));
1066 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1067
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301068 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001069
1070 if (mptsas_target_reset(ioc, channel, id)) {
1071 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001072 }
1073}
1074
1075/**
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301076 * mptsas_taskmgmt_complete - Completion for TARGET_RESET after
1077 * NOT_RESPONDING_EVENT, enable work queue to finish off removing device
1078 * from upper layers. then send next TARGET_RESET in the queue.
1079 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001080 *
1081 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301082static int
1083mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001084{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001085 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001086 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001087 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301088 struct mptsas_target_reset_event *target_reset_list;
1089 SCSITaskMgmtReply_t *pScsiTmReply;
1090
1091 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1092 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1093
1094 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1095 if (pScsiTmReply) {
1096 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1097 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1098 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1099 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1100 "term_cmnds = %d\n", ioc->name,
1101 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1102 pScsiTmReply->TaskType,
1103 le16_to_cpu(pScsiTmReply->IOCStatus),
1104 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1105 pScsiTmReply->ResponseCode,
1106 le32_to_cpu(pScsiTmReply->TerminationCount)));
1107
1108 if (pScsiTmReply->ResponseCode)
1109 mptscsih_taskmgmt_response_code(ioc,
1110 pScsiTmReply->ResponseCode);
1111 }
1112
1113 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1114 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1115 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1116 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1117 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1118 memcpy(ioc->taskmgmt_cmds.reply, mr,
1119 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1120 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1121 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1122 complete(&ioc->taskmgmt_cmds.done);
1123 return 1;
1124 }
1125 return 0;
1126 }
1127
1128 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001129
1130 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301131 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001132
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301133 target_reset_list = list_entry(head->next,
1134 struct mptsas_target_reset_event, list);
1135
1136 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1137 "TaskMgmt: completed (%d seconds)\n",
1138 ioc->name, jiffies_to_msecs(jiffies -
1139 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001140
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301141 id = pScsiTmReply->TargetID;
1142 channel = pScsiTmReply->Bus;
1143 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001144
1145 /*
1146 * retry target reset
1147 */
1148 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301149 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001150 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301151 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001152 }
1153
1154 /*
1155 * enable work queue to remove device from upper layers
1156 */
1157 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301158 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1159 mptsas_queue_device_delete(ioc,
1160 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301161
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301162
Eric Mooredf9e0622007-01-29 09:46:21 -07001163 /*
1164 * issue target reset to next device in the queue
1165 */
1166
1167 head = &hd->target_reset_list;
1168 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301169 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001170
1171 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1172 list);
1173
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301174 id = target_reset_list->sas_event_data.TargetID;
1175 channel = target_reset_list->sas_event_data.Bus;
1176 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001177
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301178 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001179 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001180
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301181 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001182}
1183
1184/**
1185 * mptscsih_ioc_reset
1186 *
1187 * @ioc
1188 * @reset_phase
1189 *
1190 **/
1191static int
1192mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1193{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001194 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001195 int rc;
1196
1197 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301198 if ((ioc->bus_type != SAS) || (!rc))
1199 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001200
Eric Mooree7eae9f2007-09-29 10:15:59 -06001201 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001202 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001203 goto out;
1204
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301205 switch (reset_phase) {
1206 case MPT_IOC_SETUP_RESET:
1207 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1208 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1209 mptsas_fw_event_off(ioc);
1210 break;
1211 case MPT_IOC_PRE_RESET:
1212 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1213 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1214 break;
1215 case MPT_IOC_POST_RESET:
1216 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1217 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1218 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1219 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1220 complete(&ioc->sas_mgmt.done);
1221 }
1222 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301223 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301224 mptsas_fw_event_on(ioc);
1225 break;
1226 default:
1227 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001228 }
1229
1230 out:
1231 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001232}
1233
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301234
1235/**
1236 * enum device_state -
1237 * @DEVICE_RETRY: need to retry the TUR
1238 * @DEVICE_ERROR: TUR return error, don't add device
1239 * @DEVICE_READY: device can be added
1240 *
1241 */
1242enum device_state{
1243 DEVICE_RETRY,
1244 DEVICE_ERROR,
1245 DEVICE_READY,
1246};
1247
Christoph Hellwige3094442006-02-16 13:25:36 +01001248static int
Moore, Eric52435432006-03-14 09:14:15 -07001249mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001250 u32 form, u32 form_specific)
1251{
1252 ConfigExtendedPageHeader_t hdr;
1253 CONFIGPARMS cfg;
1254 SasEnclosurePage0_t *buffer;
1255 dma_addr_t dma_handle;
1256 int error;
1257 __le64 le_identifier;
1258
1259 memset(&hdr, 0, sizeof(hdr));
1260 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1261 hdr.PageNumber = 0;
1262 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1263 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1264
1265 cfg.cfghdr.ehdr = &hdr;
1266 cfg.physAddr = -1;
1267 cfg.pageAddr = form + form_specific;
1268 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1269 cfg.dir = 0; /* read */
1270 cfg.timeout = 10;
1271
1272 error = mpt_config(ioc, &cfg);
1273 if (error)
1274 goto out;
1275 if (!hdr.ExtPageLength) {
1276 error = -ENXIO;
1277 goto out;
1278 }
1279
1280 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1281 &dma_handle);
1282 if (!buffer) {
1283 error = -ENOMEM;
1284 goto out;
1285 }
1286
1287 cfg.physAddr = dma_handle;
1288 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1289
1290 error = mpt_config(ioc, &cfg);
1291 if (error)
1292 goto out_free_consistent;
1293
1294 /* save config data */
1295 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1296 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1297 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1298 enclosure->flags = le16_to_cpu(buffer->Flags);
1299 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1300 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1301 enclosure->start_id = buffer->StartTargetID;
1302 enclosure->start_channel = buffer->StartBus;
1303 enclosure->sep_id = buffer->SEPTargetID;
1304 enclosure->sep_channel = buffer->SEPBus;
1305
1306 out_free_consistent:
1307 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1308 buffer, dma_handle);
1309 out:
1310 return error;
1311}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001312
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301313/**
1314 * mptsas_add_end_device - report a new end device to sas transport layer
1315 * @ioc: Pointer to MPT_ADAPTER structure
1316 * @phy_info: decribes attached device
1317 *
1318 * return (0) success (1) failure
1319 *
1320 **/
1321static int
1322mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1323{
1324 struct sas_rphy *rphy;
1325 struct sas_port *port;
1326 struct sas_identify identify;
1327 char *ds = NULL;
1328 u8 fw_id;
1329
1330 if (!phy_info) {
1331 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1332 "%s: exit at line=%d\n", ioc->name,
1333 __func__, __LINE__));
1334 return 1;
1335 }
1336
1337 fw_id = phy_info->attached.id;
1338
1339 if (mptsas_get_rphy(phy_info)) {
1340 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1341 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1342 __func__, fw_id, __LINE__));
1343 return 2;
1344 }
1345
1346 port = mptsas_get_port(phy_info);
1347 if (!port) {
1348 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1349 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1350 __func__, fw_id, __LINE__));
1351 return 3;
1352 }
1353
1354 if (phy_info->attached.device_info &
1355 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1356 ds = "ssp";
1357 if (phy_info->attached.device_info &
1358 MPI_SAS_DEVICE_INFO_STP_TARGET)
1359 ds = "stp";
1360 if (phy_info->attached.device_info &
1361 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1362 ds = "sata";
1363
1364 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1365 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1366 phy_info->attached.channel, phy_info->attached.id,
1367 phy_info->attached.phy_id, (unsigned long long)
1368 phy_info->attached.sas_address);
1369
1370 mptsas_parse_device_info(&identify, &phy_info->attached);
1371 rphy = sas_end_device_alloc(port);
1372 if (!rphy) {
1373 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1374 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1375 __func__, fw_id, __LINE__));
1376 return 5; /* non-fatal: an rphy can be added later */
1377 }
1378
1379 rphy->identify = identify;
1380 if (sas_rphy_add(rphy)) {
1381 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1382 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1383 __func__, fw_id, __LINE__));
1384 sas_rphy_free(rphy);
1385 return 6;
1386 }
1387 mptsas_set_rphy(ioc, phy_info, rphy);
1388 return 0;
1389}
1390
1391/**
1392 * mptsas_del_end_device - report a deleted end device to sas transport
1393 * layer
1394 * @ioc: Pointer to MPT_ADAPTER structure
1395 * @phy_info: decribes attached device
1396 *
1397 **/
1398static void
1399mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1400{
1401 struct sas_rphy *rphy;
1402 struct sas_port *port;
1403 struct mptsas_portinfo *port_info;
1404 struct mptsas_phyinfo *phy_info_parent;
1405 int i;
1406 char *ds = NULL;
1407 u8 fw_id;
1408 u64 sas_address;
1409
1410 if (!phy_info)
1411 return;
1412
1413 fw_id = phy_info->attached.id;
1414 sas_address = phy_info->attached.sas_address;
1415
1416 if (!phy_info->port_details) {
1417 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1418 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1419 __func__, fw_id, __LINE__));
1420 return;
1421 }
1422 rphy = mptsas_get_rphy(phy_info);
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;
1428 }
1429
1430 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1431 || phy_info->attached.device_info
1432 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1433 || phy_info->attached.device_info
1434 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1435 ds = "initiator";
1436 if (phy_info->attached.device_info &
1437 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1438 ds = "ssp";
1439 if (phy_info->attached.device_info &
1440 MPI_SAS_DEVICE_INFO_STP_TARGET)
1441 ds = "stp";
1442 if (phy_info->attached.device_info &
1443 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1444 ds = "sata";
1445
1446 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1447 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1448 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1449 phy_info->attached.id, phy_info->attached.phy_id,
1450 (unsigned long long) sas_address);
1451
1452 port = mptsas_get_port(phy_info);
1453 if (!port) {
1454 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1455 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1456 __func__, fw_id, __LINE__));
1457 return;
1458 }
1459 port_info = phy_info->portinfo;
1460 phy_info_parent = port_info->phy_info;
1461 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1462 if (!phy_info_parent->phy)
1463 continue;
1464 if (phy_info_parent->attached.sas_address !=
1465 sas_address)
1466 continue;
1467 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1468 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1469 ioc->name, phy_info_parent->phy_id,
1470 phy_info_parent->phy);
1471 sas_port_delete_phy(port, phy_info_parent->phy);
1472 }
1473
1474 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1475 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1476 port->port_identifier, (unsigned long long)sas_address);
1477 sas_port_delete(port);
1478 mptsas_set_port(ioc, phy_info, NULL);
1479 mptsas_port_delete(ioc, phy_info->port_details);
1480}
1481
1482struct mptsas_phyinfo *
1483mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1484 struct mptsas_devinfo *sas_device)
1485{
1486 struct mptsas_phyinfo *phy_info;
1487 struct mptsas_portinfo *port_info;
1488 int i;
1489
1490 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1491 sas_device->sas_address);
1492 if (!phy_info)
1493 goto out;
1494 port_info = phy_info->portinfo;
1495 if (!port_info)
1496 goto out;
1497 mutex_lock(&ioc->sas_topology_mutex);
1498 for (i = 0; i < port_info->num_phys; i++) {
1499 if (port_info->phy_info[i].attached.sas_address !=
1500 sas_device->sas_address)
1501 continue;
1502 port_info->phy_info[i].attached.channel = sas_device->channel;
1503 port_info->phy_info[i].attached.id = sas_device->id;
1504 port_info->phy_info[i].attached.sas_address =
1505 sas_device->sas_address;
1506 port_info->phy_info[i].attached.handle = sas_device->handle;
1507 port_info->phy_info[i].attached.handle_parent =
1508 sas_device->handle_parent;
1509 port_info->phy_info[i].attached.handle_enclosure =
1510 sas_device->handle_enclosure;
1511 }
1512 mutex_unlock(&ioc->sas_topology_mutex);
1513 out:
1514 return phy_info;
1515}
1516
1517/**
1518 * mptsas_firmware_event_work - work thread for processing fw events
1519 * @work: work queue payload containing info describing the event
1520 * Context: user
1521 *
1522 */
1523static void
1524mptsas_firmware_event_work(struct work_struct *work)
1525{
1526 struct fw_event_work *fw_event =
1527 container_of(work, struct fw_event_work, work.work);
1528 MPT_ADAPTER *ioc = fw_event->ioc;
1529
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301530 /* special rescan topology handling */
1531 if (fw_event->event == -1) {
1532 if (ioc->in_rescan) {
1533 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1534 "%s: rescan ignored as it is in progress\n",
1535 ioc->name, __func__));
1536 return;
1537 }
1538 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1539 "reset\n", ioc->name, __func__));
1540 ioc->in_rescan = 1;
1541 mptsas_not_responding_devices(ioc);
1542 mptsas_scan_sas_topology(ioc);
1543 ioc->in_rescan = 0;
1544 mptsas_free_fw_event(ioc, fw_event);
1545 return;
1546 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301547
1548 /* events handling turned off during host reset */
1549 if (ioc->fw_events_off) {
1550 mptsas_free_fw_event(ioc, fw_event);
1551 return;
1552 }
1553
1554 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1555 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1556 (fw_event->event & 0xFF)));
1557
1558 switch (fw_event->event) {
1559 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1560 mptsas_send_sas_event(fw_event);
1561 break;
1562 case MPI_EVENT_INTEGRATED_RAID:
1563 mptsas_send_raid_event(fw_event);
1564 break;
1565 case MPI_EVENT_IR2:
1566 mptsas_send_ir2_event(fw_event);
1567 break;
1568 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1569 mptbase_sas_persist_operation(ioc,
1570 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1571 mptsas_free_fw_event(ioc, fw_event);
1572 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301573 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1574 mptsas_send_expander_event(fw_event);
1575 break;
1576 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1577 mptsas_send_link_status_event(fw_event);
1578 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301579 }
1580}
1581
1582
1583
James Bottomleyf013db32006-03-18 14:54:36 -06001584static int
1585mptsas_slave_configure(struct scsi_device *sdev)
1586{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301587 struct Scsi_Host *host = sdev->host;
1588 MPT_SCSI_HOST *hd = shost_priv(host);
1589 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301590 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001591
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301592 if (vdevice->vtarget->deleted) {
1593 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1594 vdevice->vtarget->deleted = 0;
1595 }
1596
1597 /*
1598 * RAID volumes placed beyond the last expected port.
1599 * Ignore sending sas mode pages in that case..
1600 */
1601 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1602 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001603 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301604 }
James Bottomleyf013db32006-03-18 14:54:36 -06001605
James Bottomleye8bf3942006-07-11 17:49:34 -04001606 sas_read_port_mode_page(sdev);
1607
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301608 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1609
James Bottomleye8bf3942006-07-11 17:49:34 -04001610 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001611 return mptscsih_slave_configure(sdev);
1612}
1613
Eric Moore547f9a22006-06-27 14:42:12 -06001614static int
1615mptsas_target_alloc(struct scsi_target *starget)
1616{
1617 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001618 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001619 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001620 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001621 struct sas_rphy *rphy;
1622 struct mptsas_portinfo *p;
1623 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001624 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001625
1626 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1627 if (!vtarget)
1628 return -ENOMEM;
1629
1630 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001631 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001632 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1633 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001634 channel = 0;
1635
Eric Moore793955f2007-01-29 09:42:20 -07001636 /*
1637 * RAID volumes placed beyond the last expected port.
1638 */
1639 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301640 if (!ioc->raid_data.pIocPg2) {
1641 kfree(vtarget);
1642 return -ENXIO;
1643 }
1644 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1645 if (id == ioc->raid_data.pIocPg2->
1646 RaidVolume[i].VolumeID) {
1647 channel = ioc->raid_data.pIocPg2->
1648 RaidVolume[i].VolumeBus;
1649 }
1650 }
1651 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001652 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001653 }
Eric Moore547f9a22006-06-27 14:42:12 -06001654
1655 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001656 mutex_lock(&ioc->sas_topology_mutex);
1657 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001658 for (i = 0; i < p->num_phys; i++) {
1659 if (p->phy_info[i].attached.sas_address !=
1660 rphy->identify.sas_address)
1661 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001662 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001663 channel = p->phy_info[i].attached.channel;
1664 mptsas_set_starget(&p->phy_info[i], starget);
1665
1666 /*
1667 * Exposing hidden raid components
1668 */
Eric Mooree80b0022007-09-14 18:49:03 -06001669 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1670 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001671 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001672 vtarget->tflags |=
1673 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001674 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001675 }
Eric Mooree80b0022007-09-14 18:49:03 -06001676 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001677 goto out;
1678 }
1679 }
Eric Mooree80b0022007-09-14 18:49:03 -06001680 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001681
1682 kfree(vtarget);
1683 return -ENXIO;
1684
1685 out:
Eric Moore793955f2007-01-29 09:42:20 -07001686 vtarget->id = id;
1687 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001688 starget->hostdata = vtarget;
1689 return 0;
1690}
1691
1692static void
1693mptsas_target_destroy(struct scsi_target *starget)
1694{
1695 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001696 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001697 struct sas_rphy *rphy;
1698 struct mptsas_portinfo *p;
1699 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301700 MPT_ADAPTER *ioc = hd->ioc;
1701 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001702
1703 if (!starget->hostdata)
1704 return;
1705
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301706 vtarget = starget->hostdata;
1707
1708
James Bottomleye8bf3942006-07-11 17:49:34 -04001709 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001710 goto out;
1711
1712 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001713 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;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301718
1719 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1720 "delete device: fw_channel %d, fw_id %d, phy %d, "
1721 "sas_addr 0x%llx\n", ioc->name,
1722 p->phy_info[i].attached.channel,
1723 p->phy_info[i].attached.id,
1724 p->phy_info[i].attached.phy_id, (unsigned long long)
1725 p->phy_info[i].attached.sas_address);
1726
Eric Moore547f9a22006-06-27 14:42:12 -06001727 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001728 }
1729 }
1730
1731 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301732 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001733 kfree(starget->hostdata);
1734 starget->hostdata = NULL;
1735}
1736
1737
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001738static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001739mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001740{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001741 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001742 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001743 struct sas_rphy *rphy;
1744 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001745 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001746 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001747 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001748 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001749
Eric Moorea69de502007-09-14 18:48:19 -06001750 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1751 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001752 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001753 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001754 return -ENOMEM;
1755 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001756 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001757 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001758
James Bottomleye8bf3942006-07-11 17:49:34 -04001759 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001760 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001761
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001762 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001763 mutex_lock(&ioc->sas_topology_mutex);
1764 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001765 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001766 if (p->phy_info[i].attached.sas_address !=
1767 rphy->identify.sas_address)
1768 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001769 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001770 /*
1771 * Exposing hidden raid components
1772 */
Eric Mooree80b0022007-09-14 18:49:03 -06001773 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001774 p->phy_info[i].attached.channel,
1775 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001776 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001777 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001778 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001779 }
1780 }
Eric Mooree80b0022007-09-14 18:49:03 -06001781 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001782
Eric Moorea69de502007-09-14 18:48:19 -06001783 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001784 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001785
1786 out:
Eric Moorea69de502007-09-14 18:48:19 -06001787 vdevice->vtarget->num_luns++;
1788 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001789 return 0;
1790}
1791
Eric Moore547f9a22006-06-27 14:42:12 -06001792static int
1793mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001794{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301795 MPT_SCSI_HOST *hd;
1796 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001797 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001798
Eric Moorea69de502007-09-14 18:48:19 -06001799 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001800 SCpnt->result = DID_NO_CONNECT << 16;
1801 done(SCpnt);
1802 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001803 }
Eric Moore547f9a22006-06-27 14:42:12 -06001804
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301805 hd = shost_priv(SCpnt->device->host);
1806 ioc = hd->ioc;
1807
1808 if (ioc->sas_discovery_quiesce_io)
1809 return SCSI_MLQUEUE_HOST_BUSY;
1810
Eric Moore793955f2007-01-29 09:42:20 -07001811// scsi_print_command(SCpnt);
1812
Eric Moore547f9a22006-06-27 14:42:12 -06001813 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001814}
1815
Eric Moore547f9a22006-06-27 14:42:12 -06001816
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001817static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001818 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001819 .proc_name = "mptsas",
1820 .proc_info = mptscsih_proc_info,
1821 .name = "MPT SPI Host",
1822 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001823 .queuecommand = mptsas_qcmd,
1824 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001825 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001826 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001827 .target_destroy = mptsas_target_destroy,
1828 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001829 .change_queue_depth = mptscsih_change_queue_depth,
1830 .eh_abort_handler = mptscsih_abort,
1831 .eh_device_reset_handler = mptscsih_dev_reset,
1832 .eh_bus_reset_handler = mptscsih_bus_reset,
1833 .eh_host_reset_handler = mptscsih_host_reset,
1834 .bios_param = mptscsih_bios_param,
1835 .can_queue = MPT_FC_CAN_QUEUE,
1836 .this_id = -1,
1837 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1838 .max_sectors = 8192,
1839 .cmd_per_lun = 7,
1840 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301841 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001842};
1843
Christoph Hellwigb5141122005-10-28 22:07:41 +02001844static int mptsas_get_linkerrors(struct sas_phy *phy)
1845{
1846 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1847 ConfigExtendedPageHeader_t hdr;
1848 CONFIGPARMS cfg;
1849 SasPhyPage1_t *buffer;
1850 dma_addr_t dma_handle;
1851 int error;
1852
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001853 /* FIXME: only have link errors on local phys */
1854 if (!scsi_is_sas_phy_local(phy))
1855 return -EINVAL;
1856
Christoph Hellwigb5141122005-10-28 22:07:41 +02001857 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1858 hdr.ExtPageLength = 0;
1859 hdr.PageNumber = 1 /* page number 1*/;
1860 hdr.Reserved1 = 0;
1861 hdr.Reserved2 = 0;
1862 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1863 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1864
1865 cfg.cfghdr.ehdr = &hdr;
1866 cfg.physAddr = -1;
1867 cfg.pageAddr = phy->identify.phy_identifier;
1868 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1869 cfg.dir = 0; /* read */
1870 cfg.timeout = 10;
1871
1872 error = mpt_config(ioc, &cfg);
1873 if (error)
1874 return error;
1875 if (!hdr.ExtPageLength)
1876 return -ENXIO;
1877
1878 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1879 &dma_handle);
1880 if (!buffer)
1881 return -ENOMEM;
1882
1883 cfg.physAddr = dma_handle;
1884 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1885
1886 error = mpt_config(ioc, &cfg);
1887 if (error)
1888 goto out_free_consistent;
1889
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301890 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001891
1892 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1893 phy->running_disparity_error_count =
1894 le32_to_cpu(buffer->RunningDisparityErrorCount);
1895 phy->loss_of_dword_sync_count =
1896 le32_to_cpu(buffer->LossDwordSynchCount);
1897 phy->phy_reset_problem_count =
1898 le32_to_cpu(buffer->PhyResetProblemCount);
1899
1900 out_free_consistent:
1901 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1902 buffer, dma_handle);
1903 return error;
1904}
1905
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001906static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1907 MPT_FRAME_HDR *reply)
1908{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301909 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001910 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301911 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001912 memcpy(ioc->sas_mgmt.reply, reply,
1913 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1914 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301915
1916 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1917 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1918 complete(&ioc->sas_mgmt.done);
1919 return 1;
1920 }
1921 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001922}
1923
1924static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1925{
1926 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1927 SasIoUnitControlRequest_t *req;
1928 SasIoUnitControlReply_t *reply;
1929 MPT_FRAME_HDR *mf;
1930 MPIHeader_t *hdr;
1931 unsigned long timeleft;
1932 int error = -ERESTARTSYS;
1933
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001934 /* FIXME: fusion doesn't allow non-local phy reset */
1935 if (!scsi_is_sas_phy_local(phy))
1936 return -EINVAL;
1937
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001938 /* not implemented for expanders */
1939 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
1940 return -ENXIO;
1941
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001942 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001943 goto out;
1944
1945 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
1946 if (!mf) {
1947 error = -ENOMEM;
1948 goto out_unlock;
1949 }
1950
1951 hdr = (MPIHeader_t *) mf;
1952 req = (SasIoUnitControlRequest_t *)mf;
1953 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
1954 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
1955 req->MsgContext = hdr->MsgContext;
1956 req->Operation = hard_reset ?
1957 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
1958 req->PhyNum = phy->identify.phy_identifier;
1959
Kashyap, Desai2f187862009-05-29 16:52:37 +05301960 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001961 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
1962
1963 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
1964 10 * HZ);
1965 if (!timeleft) {
1966 /* On timeout reset the board */
1967 mpt_free_msg_frame(ioc, mf);
1968 mpt_HardResetHandler(ioc, CAN_SLEEP);
1969 error = -ETIMEDOUT;
1970 goto out_unlock;
1971 }
1972
1973 /* a reply frame is expected */
1974 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301975 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001976 error = -ENXIO;
1977 goto out_unlock;
1978 }
1979
1980 /* process the completed Reply Message Frame */
1981 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
1982 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06001983 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07001984 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001985 error = -ENXIO;
1986 goto out_unlock;
1987 }
1988
1989 error = 0;
1990
1991 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05301992 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01001993 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001994 out:
1995 return error;
1996}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001997
Christoph Hellwige3094442006-02-16 13:25:36 +01001998static int
1999mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2000{
2001 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2002 int i, error;
2003 struct mptsas_portinfo *p;
2004 struct mptsas_enclosure enclosure_info;
2005 u64 enclosure_handle;
2006
2007 mutex_lock(&ioc->sas_topology_mutex);
2008 list_for_each_entry(p, &ioc->sas_topology, list) {
2009 for (i = 0; i < p->num_phys; i++) {
2010 if (p->phy_info[i].attached.sas_address ==
2011 rphy->identify.sas_address) {
2012 enclosure_handle = p->phy_info[i].
2013 attached.handle_enclosure;
2014 goto found_info;
2015 }
2016 }
2017 }
2018 mutex_unlock(&ioc->sas_topology_mutex);
2019 return -ENXIO;
2020
2021 found_info:
2022 mutex_unlock(&ioc->sas_topology_mutex);
2023 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002024 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002025 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2026 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2027 if (!error)
2028 *identifier = enclosure_info.enclosure_logical_id;
2029 return error;
2030}
2031
2032static int
2033mptsas_get_bay_identifier(struct sas_rphy *rphy)
2034{
2035 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2036 struct mptsas_portinfo *p;
2037 int i, rc;
2038
2039 mutex_lock(&ioc->sas_topology_mutex);
2040 list_for_each_entry(p, &ioc->sas_topology, list) {
2041 for (i = 0; i < p->num_phys; i++) {
2042 if (p->phy_info[i].attached.sas_address ==
2043 rphy->identify.sas_address) {
2044 rc = p->phy_info[i].attached.slot;
2045 goto out;
2046 }
2047 }
2048 }
2049 rc = -ENXIO;
2050 out:
2051 mutex_unlock(&ioc->sas_topology_mutex);
2052 return rc;
2053}
2054
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002055static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2056 struct request *req)
2057{
2058 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2059 MPT_FRAME_HDR *mf;
2060 SmpPassthroughRequest_t *smpreq;
2061 struct request *rsp = req->next_rq;
2062 int ret;
2063 int flagsLength;
2064 unsigned long timeleft;
2065 char *psge;
2066 dma_addr_t dma_addr_in = 0;
2067 dma_addr_t dma_addr_out = 0;
2068 u64 sas_address = 0;
2069
2070 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002071 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002072 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002073 return -EINVAL;
2074 }
2075
2076 /* do we need to support multiple segments? */
2077 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002078 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002079 ioc->name, __func__, req->bio->bi_vcnt, req->data_len,
Eric Moore29dd3602007-09-14 18:46:51 -06002080 rsp->bio->bi_vcnt, rsp->data_len);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002081 return -EINVAL;
2082 }
2083
2084 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2085 if (ret)
2086 goto out;
2087
2088 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2089 if (!mf) {
2090 ret = -ENOMEM;
2091 goto out_unlock;
2092 }
2093
2094 smpreq = (SmpPassthroughRequest_t *)mf;
2095 memset(smpreq, 0, sizeof(*smpreq));
2096
2097 smpreq->RequestDataLength = cpu_to_le16(req->data_len - 4);
2098 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2099
2100 if (rphy)
2101 sas_address = rphy->identify.sas_address;
2102 else {
2103 struct mptsas_portinfo *port_info;
2104
2105 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302106 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002107 if (port_info && port_info->phy_info)
2108 sas_address =
2109 port_info->phy_info[0].phy->identify.sas_address;
2110 mutex_unlock(&ioc->sas_topology_mutex);
2111 }
2112
2113 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2114
2115 psge = (char *)
2116 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2117
2118 /* request */
2119 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2120 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302121 MPI_SGE_FLAGS_DIRECTION)
2122 << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002123 flagsLength |= (req->data_len - 4);
2124
2125 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
2126 req->data_len, PCI_DMA_BIDIRECTIONAL);
2127 if (!dma_addr_out)
2128 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302129 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302130 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002131
2132 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302133 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2134 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2135 MPI_SGE_FLAGS_IOC_TO_HOST |
2136 MPI_SGE_FLAGS_END_OF_BUFFER;
2137
2138 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002139 flagsLength |= rsp->data_len + 4;
2140 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
2141 rsp->data_len, PCI_DMA_BIDIRECTIONAL);
2142 if (!dma_addr_in)
2143 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302144 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002145
Kashyap, Desai2f187862009-05-29 16:52:37 +05302146 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002147 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2148
2149 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2150 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002151 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002152 /* On timeout reset the board */
2153 mpt_HardResetHandler(ioc, CAN_SLEEP);
2154 ret = -ETIMEDOUT;
2155 goto unmap;
2156 }
2157 mf = NULL;
2158
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302159 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002160 SmpPassthroughReply_t *smprep;
2161
2162 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2163 memcpy(req->sense, smprep, sizeof(*smprep));
2164 req->sense_len = sizeof(*smprep);
FUJITA Tomonori38b31672007-12-30 19:34:52 +09002165 req->data_len = 0;
2166 rsp->data_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002167 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302168 printk(MYIOC_s_ERR_FMT
2169 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002170 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002171 ret = -ENXIO;
2172 }
2173unmap:
2174 if (dma_addr_out)
2175 pci_unmap_single(ioc->pcidev, dma_addr_out, req->data_len,
2176 PCI_DMA_BIDIRECTIONAL);
2177 if (dma_addr_in)
2178 pci_unmap_single(ioc->pcidev, dma_addr_in, rsp->data_len,
2179 PCI_DMA_BIDIRECTIONAL);
2180put_mf:
2181 if (mf)
2182 mpt_free_msg_frame(ioc, mf);
2183out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302184 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002185 mutex_unlock(&ioc->sas_mgmt.mutex);
2186out:
2187 return ret;
2188}
2189
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002190static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002191 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002192 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2193 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002194 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002195 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002196};
2197
2198static struct scsi_transport_template *mptsas_transport_template;
2199
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002200static int
2201mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2202{
2203 ConfigExtendedPageHeader_t hdr;
2204 CONFIGPARMS cfg;
2205 SasIOUnitPage0_t *buffer;
2206 dma_addr_t dma_handle;
2207 int error, i;
2208
2209 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2210 hdr.ExtPageLength = 0;
2211 hdr.PageNumber = 0;
2212 hdr.Reserved1 = 0;
2213 hdr.Reserved2 = 0;
2214 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2215 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2216
2217 cfg.cfghdr.ehdr = &hdr;
2218 cfg.physAddr = -1;
2219 cfg.pageAddr = 0;
2220 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2221 cfg.dir = 0; /* read */
2222 cfg.timeout = 10;
2223
2224 error = mpt_config(ioc, &cfg);
2225 if (error)
2226 goto out;
2227 if (!hdr.ExtPageLength) {
2228 error = -ENXIO;
2229 goto out;
2230 }
2231
2232 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2233 &dma_handle);
2234 if (!buffer) {
2235 error = -ENOMEM;
2236 goto out;
2237 }
2238
2239 cfg.physAddr = dma_handle;
2240 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2241
2242 error = mpt_config(ioc, &cfg);
2243 if (error)
2244 goto out_free_consistent;
2245
2246 port_info->num_phys = buffer->NumPhys;
2247 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302248 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002249 if (!port_info->phy_info) {
2250 error = -ENOMEM;
2251 goto out_free_consistent;
2252 }
2253
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302254 ioc->nvdata_version_persistent =
2255 le16_to_cpu(buffer->NvdataVersionPersistent);
2256 ioc->nvdata_version_default =
2257 le16_to_cpu(buffer->NvdataVersionDefault);
2258
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002259 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302260 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002261 port_info->phy_info[i].phy_id = i;
2262 port_info->phy_info[i].port_id =
2263 buffer->PhyData[i].Port;
2264 port_info->phy_info[i].negotiated_link_rate =
2265 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002266 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002267 port_info->phy_info[i].handle =
2268 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002269 }
2270
2271 out_free_consistent:
2272 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2273 buffer, dma_handle);
2274 out:
2275 return error;
2276}
2277
2278static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302279mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2280{
2281 ConfigExtendedPageHeader_t hdr;
2282 CONFIGPARMS cfg;
2283 SasIOUnitPage1_t *buffer;
2284 dma_addr_t dma_handle;
2285 int error;
2286 u16 device_missing_delay;
2287
2288 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2289 memset(&cfg, 0, sizeof(CONFIGPARMS));
2290
2291 cfg.cfghdr.ehdr = &hdr;
2292 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2293 cfg.timeout = 10;
2294 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2295 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2296 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2297 cfg.cfghdr.ehdr->PageNumber = 1;
2298
2299 error = mpt_config(ioc, &cfg);
2300 if (error)
2301 goto out;
2302 if (!hdr.ExtPageLength) {
2303 error = -ENXIO;
2304 goto out;
2305 }
2306
2307 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2308 &dma_handle);
2309 if (!buffer) {
2310 error = -ENOMEM;
2311 goto out;
2312 }
2313
2314 cfg.physAddr = dma_handle;
2315 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2316
2317 error = mpt_config(ioc, &cfg);
2318 if (error)
2319 goto out_free_consistent;
2320
2321 ioc->io_missing_delay =
2322 le16_to_cpu(buffer->IODeviceMissingDelay);
2323 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2324 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2325 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2326 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2327
2328 out_free_consistent:
2329 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2330 buffer, dma_handle);
2331 out:
2332 return error;
2333}
2334
2335static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002336mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2337 u32 form, u32 form_specific)
2338{
2339 ConfigExtendedPageHeader_t hdr;
2340 CONFIGPARMS cfg;
2341 SasPhyPage0_t *buffer;
2342 dma_addr_t dma_handle;
2343 int error;
2344
2345 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2346 hdr.ExtPageLength = 0;
2347 hdr.PageNumber = 0;
2348 hdr.Reserved1 = 0;
2349 hdr.Reserved2 = 0;
2350 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2351 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2352
2353 cfg.cfghdr.ehdr = &hdr;
2354 cfg.dir = 0; /* read */
2355 cfg.timeout = 10;
2356
2357 /* Get Phy Pg 0 for each Phy. */
2358 cfg.physAddr = -1;
2359 cfg.pageAddr = form + form_specific;
2360 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2361
2362 error = mpt_config(ioc, &cfg);
2363 if (error)
2364 goto out;
2365
2366 if (!hdr.ExtPageLength) {
2367 error = -ENXIO;
2368 goto out;
2369 }
2370
2371 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2372 &dma_handle);
2373 if (!buffer) {
2374 error = -ENOMEM;
2375 goto out;
2376 }
2377
2378 cfg.physAddr = dma_handle;
2379 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2380
2381 error = mpt_config(ioc, &cfg);
2382 if (error)
2383 goto out_free_consistent;
2384
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302385 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002386
2387 phy_info->hw_link_rate = buffer->HwLinkRate;
2388 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2389 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2390 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2391
2392 out_free_consistent:
2393 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2394 buffer, dma_handle);
2395 out:
2396 return error;
2397}
2398
2399static int
2400mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2401 u32 form, u32 form_specific)
2402{
2403 ConfigExtendedPageHeader_t hdr;
2404 CONFIGPARMS cfg;
2405 SasDevicePage0_t *buffer;
2406 dma_addr_t dma_handle;
2407 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002408 int error=0;
2409
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002410 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2411 hdr.ExtPageLength = 0;
2412 hdr.PageNumber = 0;
2413 hdr.Reserved1 = 0;
2414 hdr.Reserved2 = 0;
2415 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2416 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2417
2418 cfg.cfghdr.ehdr = &hdr;
2419 cfg.pageAddr = form + form_specific;
2420 cfg.physAddr = -1;
2421 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2422 cfg.dir = 0; /* read */
2423 cfg.timeout = 10;
2424
Moore, Ericdb9c9172006-03-14 09:14:18 -07002425 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002426 error = mpt_config(ioc, &cfg);
2427 if (error)
2428 goto out;
2429 if (!hdr.ExtPageLength) {
2430 error = -ENXIO;
2431 goto out;
2432 }
2433
2434 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2435 &dma_handle);
2436 if (!buffer) {
2437 error = -ENOMEM;
2438 goto out;
2439 }
2440
2441 cfg.physAddr = dma_handle;
2442 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2443
2444 error = mpt_config(ioc, &cfg);
2445 if (error)
2446 goto out_free_consistent;
2447
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302448 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002449
Kashyap, Desai2f187862009-05-29 16:52:37 +05302450 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002451 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002452 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002453 device_info->handle_enclosure =
2454 le16_to_cpu(buffer->EnclosureHandle);
2455 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002456 device_info->phy_id = buffer->PhyNum;
2457 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002458 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002459 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002460 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002461 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2462 device_info->sas_address = le64_to_cpu(sas_address);
2463 device_info->device_info =
2464 le32_to_cpu(buffer->DeviceInfo);
2465
2466 out_free_consistent:
2467 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2468 buffer, dma_handle);
2469 out:
2470 return error;
2471}
2472
2473static int
2474mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2475 u32 form, u32 form_specific)
2476{
2477 ConfigExtendedPageHeader_t hdr;
2478 CONFIGPARMS cfg;
2479 SasExpanderPage0_t *buffer;
2480 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002481 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302482 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002483
Kashyap, Desai2f187862009-05-29 16:52:37 +05302484 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002485 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2486 hdr.ExtPageLength = 0;
2487 hdr.PageNumber = 0;
2488 hdr.Reserved1 = 0;
2489 hdr.Reserved2 = 0;
2490 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2491 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2492
2493 cfg.cfghdr.ehdr = &hdr;
2494 cfg.physAddr = -1;
2495 cfg.pageAddr = form + form_specific;
2496 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2497 cfg.dir = 0; /* read */
2498 cfg.timeout = 10;
2499
Moore, Ericdb9c9172006-03-14 09:14:18 -07002500 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002501 error = mpt_config(ioc, &cfg);
2502 if (error)
2503 goto out;
2504
2505 if (!hdr.ExtPageLength) {
2506 error = -ENXIO;
2507 goto out;
2508 }
2509
2510 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2511 &dma_handle);
2512 if (!buffer) {
2513 error = -ENOMEM;
2514 goto out;
2515 }
2516
2517 cfg.physAddr = dma_handle;
2518 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2519
2520 error = mpt_config(ioc, &cfg);
2521 if (error)
2522 goto out_free_consistent;
2523
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002524 if (!buffer->NumPhys) {
2525 error = -ENODEV;
2526 goto out_free_consistent;
2527 }
2528
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002529 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302530 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002531 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302532 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002533 if (!port_info->phy_info) {
2534 error = -ENOMEM;
2535 goto out_free_consistent;
2536 }
2537
Kashyap, Desai2f187862009-05-29 16:52:37 +05302538 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002539 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002540 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002541 port_info->phy_info[i].handle =
2542 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302543 port_info->phy_info[i].identify.sas_address =
2544 le64_to_cpu(sas_address);
2545 port_info->phy_info[i].identify.handle_parent =
2546 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002547 }
Eric Moore547f9a22006-06-27 14:42:12 -06002548
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002549 out_free_consistent:
2550 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2551 buffer, dma_handle);
2552 out:
2553 return error;
2554}
2555
2556static int
2557mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2558 u32 form, u32 form_specific)
2559{
2560 ConfigExtendedPageHeader_t hdr;
2561 CONFIGPARMS cfg;
2562 SasExpanderPage1_t *buffer;
2563 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002564 int error=0;
2565
Kashyap, Desai2f187862009-05-29 16:52:37 +05302566 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002567 hdr.ExtPageLength = 0;
2568 hdr.PageNumber = 1;
2569 hdr.Reserved1 = 0;
2570 hdr.Reserved2 = 0;
2571 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2572 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2573
2574 cfg.cfghdr.ehdr = &hdr;
2575 cfg.physAddr = -1;
2576 cfg.pageAddr = form + form_specific;
2577 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2578 cfg.dir = 0; /* read */
2579 cfg.timeout = 10;
2580
2581 error = mpt_config(ioc, &cfg);
2582 if (error)
2583 goto out;
2584
2585 if (!hdr.ExtPageLength) {
2586 error = -ENXIO;
2587 goto out;
2588 }
2589
2590 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2591 &dma_handle);
2592 if (!buffer) {
2593 error = -ENOMEM;
2594 goto out;
2595 }
2596
2597 cfg.physAddr = dma_handle;
2598 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2599
2600 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302601
2602 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2603 error = -ENODEV;
2604 goto out;
2605 }
2606
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002607 if (error)
2608 goto out_free_consistent;
2609
2610
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302611 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002612
2613 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002614 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002615 phy_info->port_id = buffer->PhysicalPort;
2616 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2617 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2618 phy_info->hw_link_rate = buffer->HwLinkRate;
2619 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2620 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2621
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002622 out_free_consistent:
2623 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2624 buffer, dma_handle);
2625 out:
2626 return error;
2627}
2628
2629static void
2630mptsas_parse_device_info(struct sas_identify *identify,
2631 struct mptsas_devinfo *device_info)
2632{
2633 u16 protocols;
2634
2635 identify->sas_address = device_info->sas_address;
2636 identify->phy_identifier = device_info->phy_id;
2637
2638 /*
2639 * Fill in Phy Initiator Port Protocol.
2640 * Bits 6:3, more than one bit can be set, fall through cases.
2641 */
2642 protocols = device_info->device_info & 0x78;
2643 identify->initiator_port_protocols = 0;
2644 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2645 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2646 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2647 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2648 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2649 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2650 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2651 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2652
2653 /*
2654 * Fill in Phy Target Port Protocol.
2655 * Bits 10:7, more than one bit can be set, fall through cases.
2656 */
2657 protocols = device_info->device_info & 0x780;
2658 identify->target_port_protocols = 0;
2659 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2660 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2661 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2662 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2663 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2664 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2665 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2666 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2667
2668 /*
2669 * Fill in Attached device type.
2670 */
2671 switch (device_info->device_info &
2672 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2673 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2674 identify->device_type = SAS_PHY_UNUSED;
2675 break;
2676 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2677 identify->device_type = SAS_END_DEVICE;
2678 break;
2679 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2680 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2681 break;
2682 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2683 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2684 break;
2685 }
2686}
2687
2688static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002689 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002690{
Moore, Erice6b2d762006-03-14 09:14:24 -07002691 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002692 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002693 struct sas_port *port;
2694 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002695
Eric Moore547f9a22006-06-27 14:42:12 -06002696 if (!dev) {
2697 error = -ENODEV;
2698 goto out;
2699 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002700
2701 if (!phy_info->phy) {
2702 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002703 if (!phy) {
2704 error = -ENOMEM;
2705 goto out;
2706 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002707 } else
2708 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002709
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002710 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002711
2712 /*
2713 * Set Negotiated link rate.
2714 */
2715 switch (phy_info->negotiated_link_rate) {
2716 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002717 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002718 break;
2719 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002720 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002721 break;
2722 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002723 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002724 break;
2725 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002726 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002727 break;
2728 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2729 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2730 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002731 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002732 break;
2733 }
2734
2735 /*
2736 * Set Max hardware link rate.
2737 */
2738 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2739 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002740 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002741 break;
2742 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002743 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002744 break;
2745 default:
2746 break;
2747 }
2748
2749 /*
2750 * Set Max programmed link rate.
2751 */
2752 switch (phy_info->programmed_link_rate &
2753 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2754 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002755 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002756 break;
2757 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002758 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002759 break;
2760 default:
2761 break;
2762 }
2763
2764 /*
2765 * Set Min hardware link rate.
2766 */
2767 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
2768 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002769 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002770 break;
2771 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002772 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002773 break;
2774 default:
2775 break;
2776 }
2777
2778 /*
2779 * Set Min programmed link rate.
2780 */
2781 switch (phy_info->programmed_link_rate &
2782 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
2783 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002784 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002785 break;
2786 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002787 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002788 break;
2789 default:
2790 break;
2791 }
2792
Moore, Erice6b2d762006-03-14 09:14:24 -07002793 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002794
Moore, Erice6b2d762006-03-14 09:14:24 -07002795 error = sas_phy_add(phy);
2796 if (error) {
2797 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06002798 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07002799 }
2800 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002801 }
2802
Eric Moore547f9a22006-06-27 14:42:12 -06002803 if (!phy_info->attached.handle ||
2804 !phy_info->port_details)
2805 goto out;
2806
2807 port = mptsas_get_port(phy_info);
2808 ioc = phy_to_ioc(phy_info->phy);
2809
2810 if (phy_info->sas_port_add_phy) {
2811
2812 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06002813 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06002814 if (!port) {
2815 error = -ENOMEM;
2816 goto out;
2817 }
2818 error = sas_port_add(port);
2819 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302820 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002821 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002822 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002823 goto out;
2824 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302825 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302826 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
2827 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
2828 ioc->name, port->port_identifier,
2829 (unsigned long long)phy_info->
2830 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06002831 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302832 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
2833 "sas_port_add_phy: phy_id=%d\n",
2834 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06002835 sas_port_add_phy(port, phy_info->phy);
2836 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302837 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
2838 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
2839 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06002840 }
Eric Moore547f9a22006-06-27 14:42:12 -06002841 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002842
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002843 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05002844 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06002845 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002846
James Bottomley2686de22006-06-30 12:54:02 -05002847 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07002848 /*
2849 * Let the hotplug_work thread handle processing
2850 * the adding/removing of devices that occur
2851 * after start of day.
2852 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302853 if (mptsas_is_end_device(&phy_info->attached) &&
2854 phy_info->attached.handle_parent) {
2855 goto out;
2856 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002857
James Bottomleyf013db32006-03-18 14:54:36 -06002858 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05002859 if (scsi_is_host_device(parent)) {
2860 struct mptsas_portinfo *port_info;
2861 int i;
2862
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302863 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05002864
2865 for (i = 0; i < port_info->num_phys; i++)
2866 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002867 identify.sas_address) {
2868 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002869 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002870 }
James Bottomley2686de22006-06-30 12:54:02 -05002871
2872 } else if (scsi_is_sas_rphy(parent)) {
2873 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
2874 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04002875 parent_rphy->identify.sas_address) {
2876 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05002877 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04002878 }
James Bottomley2686de22006-06-30 12:54:02 -05002879 }
2880
James Bottomleyf013db32006-03-18 14:54:36 -06002881 switch (identify.device_type) {
2882 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002883 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06002884 break;
2885 case SAS_EDGE_EXPANDER_DEVICE:
2886 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06002887 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06002888 break;
2889 default:
2890 rphy = NULL;
2891 break;
2892 }
Eric Moore547f9a22006-06-27 14:42:12 -06002893 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302894 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002895 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002896 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002897 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002898 }
2899
Eric Moore547f9a22006-06-27 14:42:12 -06002900 rphy->identify = identify;
2901 error = sas_rphy_add(rphy);
2902 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302903 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06002904 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002905 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06002906 sas_rphy_free(rphy);
2907 goto out;
2908 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302909 mptsas_set_rphy(ioc, phy_info, rphy);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002910 }
2911
Eric Moore547f9a22006-06-27 14:42:12 -06002912 out:
2913 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002914}
2915
2916static int
Moore, Erice6b2d762006-03-14 09:14:24 -07002917mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002918{
Moore, Erice6b2d762006-03-14 09:14:24 -07002919 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002920 int error = -ENOMEM, i;
2921
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302922 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07002923 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002924 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002925
Moore, Erice6b2d762006-03-14 09:14:24 -07002926 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002927 if (error)
2928 goto out_free_port_info;
2929
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302930 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002931 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302932 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07002933 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302934 ioc->hba_port_info = port_info = hba;
2935 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07002936 list_add_tail(&port_info->list, &ioc->sas_topology);
2937 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07002938 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07002939 port_info->phy_info[i].negotiated_link_rate =
2940 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07002941 port_info->phy_info[i].handle =
2942 hba->phy_info[i].handle;
2943 port_info->phy_info[i].port_id =
2944 hba->phy_info[i].port_id;
2945 }
Eric Moore547f9a22006-06-27 14:42:12 -06002946 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07002947 kfree(hba);
2948 hba = NULL;
2949 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002950 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302951#if defined(CPQ_CIM)
2952 ioc->num_ports = port_info->num_phys;
2953#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002954 for (i = 0; i < port_info->num_phys; i++) {
2955 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
2956 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
2957 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302958 port_info->phy_info[i].identify.handle =
2959 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002960 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07002961 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2962 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302963 port_info->phy_info[i].identify.handle);
2964 if (!ioc->hba_port_sas_addr)
2965 ioc->hba_port_sas_addr =
2966 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02002967 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07002968 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06002969 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002970 mptsas_sas_device_pg0(ioc,
2971 &port_info->phy_info[i].attached,
2972 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
2973 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
2974 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06002975 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002976
Eric Moore547f9a22006-06-27 14:42:12 -06002977 mptsas_setup_wide_ports(ioc, port_info);
2978
2979 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002980 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07002981 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002982
2983 return 0;
2984
2985 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06002986 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002987 out:
2988 return error;
2989}
2990
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302991static void
2992mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002993{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302994 struct mptsas_portinfo *parent;
2995 struct device *parent_dev;
2996 struct sas_rphy *rphy;
2997 int i;
2998 u64 sas_address; /* expander sas address */
2999 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003000
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303001 handle = port_info->phy_info[0].handle;
3002 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003003 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003004 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303005 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3006 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003007
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303008 mptsas_sas_device_pg0(ioc,
3009 &port_info->phy_info[i].identify,
3010 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3011 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3012 port_info->phy_info[i].identify.handle);
3013 port_info->phy_info[i].identify.phy_id =
3014 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003015
3016 if (port_info->phy_info[i].attached.handle) {
3017 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303018 &port_info->phy_info[i].attached,
3019 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3020 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3021 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003022 port_info->phy_info[i].attached.phy_id =
3023 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003024 }
Eric Moore547f9a22006-06-27 14:42:12 -06003025 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003026
Moore, Erice6b2d762006-03-14 09:14:24 -07003027 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303028 parent = mptsas_find_portinfo_by_handle(ioc,
3029 port_info->phy_info[0].identify.handle_parent);
3030 if (!parent) {
3031 mutex_unlock(&ioc->sas_topology_mutex);
3032 return;
3033 }
3034 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3035 i++) {
3036 if (parent->phy_info[i].attached.sas_address == sas_address) {
3037 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3038 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003039 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003040 }
3041 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303042
3043 mptsas_setup_wide_ports(ioc, port_info);
3044 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3045 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3046 ioc->sas_index, 0);
3047}
3048
3049static void
3050mptsas_expander_event_add(MPT_ADAPTER *ioc,
3051 MpiEventDataSasExpanderStatusChange_t *expander_data)
3052{
3053 struct mptsas_portinfo *port_info;
3054 int i;
3055 __le64 sas_address;
3056
3057 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3058 if (!port_info)
3059 BUG();
3060 port_info->num_phys = (expander_data->NumPhys) ?
3061 expander_data->NumPhys : 1;
3062 port_info->phy_info = kcalloc(port_info->num_phys,
3063 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3064 if (!port_info->phy_info)
3065 BUG();
3066 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3067 for (i = 0; i < port_info->num_phys; i++) {
3068 port_info->phy_info[i].portinfo = port_info;
3069 port_info->phy_info[i].handle =
3070 le16_to_cpu(expander_data->DevHandle);
3071 port_info->phy_info[i].identify.sas_address =
3072 le64_to_cpu(sas_address);
3073 port_info->phy_info[i].identify.handle_parent =
3074 le16_to_cpu(expander_data->ParentDevHandle);
3075 }
3076
3077 mutex_lock(&ioc->sas_topology_mutex);
3078 list_add_tail(&port_info->list, &ioc->sas_topology);
3079 mutex_unlock(&ioc->sas_topology_mutex);
3080
3081 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3082 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3083 (unsigned long long)sas_address);
3084
3085 mptsas_expander_refresh(ioc, port_info);
3086}
3087
3088/**
3089 * mptsas_delete_expander_siblings - remove siblings attached to expander
3090 * @ioc: Pointer to MPT_ADAPTER structure
3091 * @parent: the parent port_info object
3092 * @expander: the expander port_info object
3093 **/
3094static void
3095mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3096 *parent, struct mptsas_portinfo *expander)
3097{
3098 struct mptsas_phyinfo *phy_info;
3099 struct mptsas_portinfo *port_info;
3100 struct sas_rphy *rphy;
3101 int i;
3102
3103 phy_info = expander->phy_info;
3104 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3105 rphy = mptsas_get_rphy(phy_info);
3106 if (!rphy)
3107 continue;
3108 if (rphy->identify.device_type == SAS_END_DEVICE)
3109 mptsas_del_end_device(ioc, phy_info);
3110 }
3111
3112 phy_info = expander->phy_info;
3113 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3114 rphy = mptsas_get_rphy(phy_info);
3115 if (!rphy)
3116 continue;
3117 if (rphy->identify.device_type ==
3118 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3119 rphy->identify.device_type ==
3120 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3121 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3122 rphy->identify.sas_address);
3123 if (!port_info)
3124 continue;
3125 if (port_info == parent) /* backlink rphy */
3126 continue;
3127 /*
3128 Delete this expander even if the expdevpage is exists
3129 because the parent expander is already deleted
3130 */
3131 mptsas_expander_delete(ioc, port_info, 1);
3132 }
3133 }
3134}
3135
3136
3137/**
3138 * mptsas_expander_delete - remove this expander
3139 * @ioc: Pointer to MPT_ADAPTER structure
3140 * @port_info: expander port_info struct
3141 * @force: Flag to forcefully delete the expander
3142 *
3143 **/
3144
3145static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3146 struct mptsas_portinfo *port_info, u8 force)
3147{
3148
3149 struct mptsas_portinfo *parent;
3150 int i;
3151 u64 expander_sas_address;
3152 struct mptsas_phyinfo *phy_info;
3153 struct mptsas_portinfo buffer;
3154 struct mptsas_portinfo_details *port_details;
3155 struct sas_port *port;
3156
3157 if (!port_info)
3158 return;
3159
3160 /* see if expander is still there before deleting */
3161 mptsas_sas_expander_pg0(ioc, &buffer,
3162 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3163 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3164 port_info->phy_info[0].identify.handle);
3165
3166 if (buffer.num_phys) {
3167 kfree(buffer.phy_info);
3168 if (!force)
3169 return;
3170 }
3171
3172
3173 /*
3174 * Obtain the port_info instance to the parent port
3175 */
3176 port_details = NULL;
3177 expander_sas_address =
3178 port_info->phy_info[0].identify.sas_address;
3179 parent = mptsas_find_portinfo_by_handle(ioc,
3180 port_info->phy_info[0].identify.handle_parent);
3181 mptsas_delete_expander_siblings(ioc, parent, port_info);
3182 if (!parent)
3183 goto out;
3184
3185 /*
3186 * Delete rphys in the parent that point
3187 * to this expander.
3188 */
3189 phy_info = parent->phy_info;
3190 port = NULL;
3191 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3192 if (!phy_info->phy)
3193 continue;
3194 if (phy_info->attached.sas_address !=
3195 expander_sas_address)
3196 continue;
3197 if (!port) {
3198 port = mptsas_get_port(phy_info);
3199 port_details = phy_info->port_details;
3200 }
3201 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3202 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3203 phy_info->phy_id, phy_info->phy);
3204 sas_port_delete_phy(port, phy_info->phy);
3205 }
3206 if (port) {
3207 dev_printk(KERN_DEBUG, &port->dev,
3208 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3209 ioc->name, port->port_identifier,
3210 (unsigned long long)expander_sas_address);
3211 sas_port_delete(port);
3212 mptsas_port_delete(ioc, port_details);
3213 }
3214 out:
3215
3216 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3217 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3218 (unsigned long long)expander_sas_address);
3219
3220 /*
3221 * free link
3222 */
3223 list_del(&port_info->list);
3224 kfree(port_info->phy_info);
3225 kfree(port_info);
3226}
3227
3228
3229/**
3230 * mptsas_send_expander_event - expanders events
3231 * @ioc: Pointer to MPT_ADAPTER structure
3232 * @expander_data: event data
3233 *
3234 *
3235 * This function handles adding, removing, and refreshing
3236 * device handles within the expander objects.
3237 */
3238static void
3239mptsas_send_expander_event(struct fw_event_work *fw_event)
3240{
3241 MPT_ADAPTER *ioc;
3242 MpiEventDataSasExpanderStatusChange_t *expander_data;
3243 struct mptsas_portinfo *port_info;
3244 __le64 sas_address;
3245 int i;
3246
3247 ioc = fw_event->ioc;
3248 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3249 fw_event->event_data;
3250 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3251 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3252
3253 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3254 if (port_info) {
3255 for (i = 0; i < port_info->num_phys; i++) {
3256 port_info->phy_info[i].portinfo = port_info;
3257 port_info->phy_info[i].handle =
3258 le16_to_cpu(expander_data->DevHandle);
3259 port_info->phy_info[i].identify.sas_address =
3260 le64_to_cpu(sas_address);
3261 port_info->phy_info[i].identify.handle_parent =
3262 le16_to_cpu(expander_data->ParentDevHandle);
3263 }
3264 mptsas_expander_refresh(ioc, port_info);
3265 } else if (!port_info && expander_data->NumPhys)
3266 mptsas_expander_event_add(ioc, expander_data);
3267 } else if (expander_data->ReasonCode ==
3268 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3269 mptsas_expander_delete(ioc, port_info, 0);
3270
3271 mptsas_free_fw_event(ioc, fw_event);
3272}
3273
3274
3275/**
3276 * mptsas_expander_add -
3277 * @ioc: Pointer to MPT_ADAPTER structure
3278 * @handle:
3279 *
3280 */
3281struct mptsas_portinfo *
3282mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3283{
3284 struct mptsas_portinfo buffer, *port_info;
3285 int i;
3286
3287 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3288 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3289 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3290 return NULL;
3291
3292 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3293 if (!port_info) {
3294 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3295 "%s: exit at line=%d\n", ioc->name,
3296 __func__, __LINE__));
3297 return NULL;
3298 }
3299 port_info->num_phys = buffer.num_phys;
3300 port_info->phy_info = buffer.phy_info;
3301 for (i = 0; i < port_info->num_phys; i++)
3302 port_info->phy_info[i].portinfo = port_info;
3303 mutex_lock(&ioc->sas_topology_mutex);
3304 list_add_tail(&port_info->list, &ioc->sas_topology);
3305 mutex_unlock(&ioc->sas_topology_mutex);
3306 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3307 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3308 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3309 mptsas_expander_refresh(ioc, port_info);
3310 return port_info;
3311}
3312
3313static void
3314mptsas_send_link_status_event(struct fw_event_work *fw_event)
3315{
3316 MPT_ADAPTER *ioc;
3317 MpiEventDataSasPhyLinkStatus_t *link_data;
3318 struct mptsas_portinfo *port_info;
3319 struct mptsas_phyinfo *phy_info = NULL;
3320 __le64 sas_address;
3321 u8 phy_num;
3322 u8 link_rate;
3323
3324 ioc = fw_event->ioc;
3325 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3326
3327 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3328 sas_address = le64_to_cpu(sas_address);
3329 link_rate = link_data->LinkRates >> 4;
3330 phy_num = link_data->PhyNum;
3331
3332 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3333 if (port_info) {
3334 phy_info = &port_info->phy_info[phy_num];
3335 if (phy_info)
3336 phy_info->negotiated_link_rate = link_rate;
3337 }
3338
3339 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3340 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3341
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303342 if (!port_info) {
3343 if (ioc->old_sas_discovery_protocal) {
3344 port_info = mptsas_expander_add(ioc,
3345 le16_to_cpu(link_data->DevHandle));
3346 if (port_info)
3347 goto out;
3348 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303349 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303350 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303351
3352 if (port_info == ioc->hba_port_info)
3353 mptsas_probe_hba_phys(ioc);
3354 else
3355 mptsas_expander_refresh(ioc, port_info);
3356 } else if (phy_info && phy_info->phy) {
3357 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3358 phy_info->phy->negotiated_linkrate =
3359 SAS_PHY_DISABLED;
3360 else if (link_rate ==
3361 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3362 phy_info->phy->negotiated_linkrate =
3363 SAS_LINK_RATE_FAILED;
3364 else
3365 phy_info->phy->negotiated_linkrate =
3366 SAS_LINK_RATE_UNKNOWN;
3367 }
3368 out:
3369 mptsas_free_fw_event(ioc, fw_event);
3370}
3371
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303372static void
3373mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3374{
3375 struct mptsas_portinfo buffer, *port_info;
3376 struct mptsas_device_info *sas_info;
3377 struct mptsas_devinfo sas_device;
3378 u32 handle;
3379 VirtTarget *vtarget = NULL;
3380 struct mptsas_phyinfo *phy_info;
3381 u8 found_expander;
3382 int retval, retry_count;
3383 unsigned long flags;
3384
3385 mpt_findImVolumes(ioc);
3386
3387 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3388 if (ioc->ioc_reset_in_progress) {
3389 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3390 "%s: exiting due to a parallel reset \n", ioc->name,
3391 __func__));
3392 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3393 return;
3394 }
3395 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3396
3397 /* devices, logical volumes */
3398 mutex_lock(&ioc->sas_device_info_mutex);
3399 redo_device_scan:
3400 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303401 if (!sas_info->is_logical_volume) {
3402 sas_device.handle = 0;
3403 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303404retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303405 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303406 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3407 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3408 (sas_info->fw.channel << 8) +
3409 sas_info->fw.id);
3410
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303411 if (sas_device.handle)
3412 continue;
3413 if (retval == -EBUSY) {
3414 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3415 if (ioc->ioc_reset_in_progress) {
3416 dfailprintk(ioc,
3417 printk(MYIOC_s_DEBUG_FMT
3418 "%s: exiting due to reset\n",
3419 ioc->name, __func__));
3420 spin_unlock_irqrestore
3421 (&ioc->taskmgmt_lock, flags);
3422 mutex_unlock(&ioc->
3423 sas_device_info_mutex);
3424 return;
3425 }
3426 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3427 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303428 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303429
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303430 if (retval && (retval != -ENODEV)) {
3431 if (retry_count < 10) {
3432 retry_count++;
3433 goto retry_page;
3434 } else {
3435 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3436 "%s: Config page retry exceeded retry "
3437 "count deleting device 0x%llx\n",
3438 ioc->name, __func__,
3439 sas_info->sas_address));
3440 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303441 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303442
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303443 /* delete device */
3444 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303445 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303446
3447 if (vtarget)
3448 vtarget->deleted = 1;
3449
3450 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3451 sas_info->sas_address);
3452
3453 if (phy_info) {
3454 mptsas_del_end_device(ioc, phy_info);
3455 goto redo_device_scan;
3456 }
3457 } else
3458 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303459 }
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303460 mutex_lock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303461
3462 /* expanders */
3463 mutex_lock(&ioc->sas_topology_mutex);
3464 redo_expander_scan:
3465 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3466
3467 if (port_info->phy_info &&
3468 (!(port_info->phy_info[0].identify.device_info &
3469 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3470 continue;
3471 found_expander = 0;
3472 handle = 0xFFFF;
3473 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3474 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3475 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3476 !found_expander) {
3477
3478 handle = buffer.phy_info[0].handle;
3479 if (buffer.phy_info[0].identify.sas_address ==
3480 port_info->phy_info[0].identify.sas_address) {
3481 found_expander = 1;
3482 }
3483 kfree(buffer.phy_info);
3484 }
3485
3486 if (!found_expander) {
3487 mptsas_expander_delete(ioc, port_info, 0);
3488 goto redo_expander_scan;
3489 }
3490 }
3491 mutex_lock(&ioc->sas_topology_mutex);
3492}
3493
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303494/**
3495 * mptsas_probe_expanders - adding expanders
3496 * @ioc: Pointer to MPT_ADAPTER structure
3497 *
3498 **/
3499static void
3500mptsas_probe_expanders(MPT_ADAPTER *ioc)
3501{
3502 struct mptsas_portinfo buffer, *port_info;
3503 u32 handle;
3504 int i;
3505
3506 handle = 0xFFFF;
3507 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3508 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3509 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3510
3511 handle = buffer.phy_info[0].handle;
3512 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3513 buffer.phy_info[0].identify.sas_address);
3514
3515 if (port_info) {
3516 /* refreshing handles */
3517 for (i = 0; i < buffer.num_phys; i++) {
3518 port_info->phy_info[i].handle = handle;
3519 port_info->phy_info[i].identify.handle_parent =
3520 buffer.phy_info[0].identify.handle_parent;
3521 }
3522 mptsas_expander_refresh(ioc, port_info);
3523 kfree(buffer.phy_info);
3524 continue;
3525 }
3526
3527 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3528 if (!port_info) {
3529 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3530 "%s: exit at line=%d\n", ioc->name,
3531 __func__, __LINE__));
3532 return;
3533 }
3534 port_info->num_phys = buffer.num_phys;
3535 port_info->phy_info = buffer.phy_info;
3536 for (i = 0; i < port_info->num_phys; i++)
3537 port_info->phy_info[i].portinfo = port_info;
3538 mutex_lock(&ioc->sas_topology_mutex);
3539 list_add_tail(&port_info->list, &ioc->sas_topology);
3540 mutex_unlock(&ioc->sas_topology_mutex);
3541 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3542 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3543 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3544 mptsas_expander_refresh(ioc, port_info);
3545 }
3546}
3547
3548static void
3549mptsas_probe_devices(MPT_ADAPTER *ioc)
3550{
3551 u16 handle;
3552 struct mptsas_devinfo sas_device;
3553 struct mptsas_phyinfo *phy_info;
3554
3555 handle = 0xFFFF;
3556 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3557 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3558
3559 handle = sas_device.handle;
3560
3561 if ((sas_device.device_info &
3562 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3563 MPI_SAS_DEVICE_INFO_STP_TARGET |
3564 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3565 continue;
3566
3567 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3568 if (!phy_info)
3569 continue;
3570
3571 if (mptsas_get_rphy(phy_info))
3572 continue;
3573
3574 mptsas_add_end_device(ioc, phy_info);
3575 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003576}
3577
Kashyap, Desai2f187862009-05-29 16:52:37 +05303578/**
3579 * mptsas_scan_sas_topology -
3580 * @ioc: Pointer to MPT_ADAPTER structure
3581 * @sas_address:
3582 *
3583 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003584static void
3585mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3586{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303587 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003588 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003589
Moore, Erice6b2d762006-03-14 09:14:24 -07003590 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303591 mptsas_probe_expanders(ioc);
3592 mptsas_probe_devices(ioc);
3593
Moore, Ericf44e5462006-03-14 09:14:21 -07003594 /*
3595 Reporting RAID volumes.
3596 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303597 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3598 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3599 return;
Eric Moore793955f2007-01-29 09:42:20 -07003600 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303601 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3602 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3603 if (sdev) {
3604 scsi_device_put(sdev);
3605 continue;
3606 }
3607 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3608 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3609 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003610 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003611 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3612 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003613}
3614
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003615static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003616mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003617{
3618 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003619 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003620 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003621
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003622 mutex_lock(&ioc->sas_topology_mutex);
3623 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3624 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003625 if (!mptsas_is_end_device(
3626 &port_info->phy_info[i].attached))
3627 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003628 if (port_info->phy_info[i].attached.sas_address
3629 != sas_address)
3630 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003631 phy_info = &port_info->phy_info[i];
3632 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003633 }
3634 }
3635 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003636 return phy_info;
3637}
3638
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303639/**
3640 * mptsas_find_phyinfo_by_phys_disk_num -
3641 * @ioc: Pointer to MPT_ADAPTER structure
3642 * @phys_disk_num:
3643 * @channel:
3644 * @id:
3645 *
3646 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003647static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303648mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3649 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003650{
Eric Mooreb506ade2007-01-29 09:45:37 -07003651 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303652 struct mptsas_portinfo *port_info;
3653 RaidPhysDiskPage1_t *phys_disk = NULL;
3654 int num_paths;
3655 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003656 int i;
3657
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303658 phy_info = NULL;
3659 if (!ioc->raid_data.pIocPg3)
3660 return NULL;
3661 /* dual port support */
3662 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
3663 if (!num_paths)
3664 goto out;
3665 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
3666 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
3667 if (!phys_disk)
3668 goto out;
3669 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
3670 for (i = 0; i < num_paths; i++) {
3671 if ((phys_disk->Path[i].Flags & 1) != 0)
3672 /* entry no longer valid */
3673 continue;
3674 if ((id == phys_disk->Path[i].PhysDiskID) &&
3675 (channel == phys_disk->Path[i].PhysDiskBus)) {
3676 memcpy(&sas_address, &phys_disk->Path[i].WWID,
3677 sizeof(u64));
3678 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3679 sas_address);
3680 goto out;
3681 }
3682 }
3683
3684 out:
3685 kfree(phys_disk);
3686 if (phy_info)
3687 return phy_info;
3688
3689 /*
3690 * Extra code to handle RAID0 case, where the sas_address is not updated
3691 * in phys_disk_page_1 when hotswapped
3692 */
Eric Mooreb506ade2007-01-29 09:45:37 -07003693 mutex_lock(&ioc->sas_topology_mutex);
3694 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303695 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07003696 if (!mptsas_is_end_device(
3697 &port_info->phy_info[i].attached))
3698 continue;
3699 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
3700 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303701 if ((port_info->phy_info[i].attached.phys_disk_num ==
3702 phys_disk_num) &&
3703 (port_info->phy_info[i].attached.id == id) &&
3704 (port_info->phy_info[i].attached.channel ==
3705 channel))
3706 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06003707 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003708 }
3709 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003710 return phy_info;
3711}
3712
3713static void
Moore, Ericf44e5462006-03-14 09:14:21 -07003714mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
3715{
Eric Mooref99be432007-01-04 20:46:54 -07003716 int rc;
3717
Moore, Ericf44e5462006-03-14 09:14:21 -07003718 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07003719 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07003720}
3721
3722static void
3723mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
3724{
3725 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
3726 mptsas_reprobe_lun);
3727}
3728
Eric Mooreb506ade2007-01-29 09:45:37 -07003729static void
3730mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
3731{
3732 CONFIGPARMS cfg;
3733 ConfigPageHeader_t hdr;
3734 dma_addr_t dma_handle;
3735 pRaidVolumePage0_t buffer = NULL;
3736 RaidPhysDiskPage0_t phys_disk;
3737 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303738 struct mptsas_phyinfo *phy_info;
3739 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07003740
3741 memset(&cfg, 0 , sizeof(CONFIGPARMS));
3742 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
3743 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
3744 cfg.pageAddr = (channel << 8) + id;
3745 cfg.cfghdr.hdr = &hdr;
3746 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
3747
3748 if (mpt_config(ioc, &cfg) != 0)
3749 goto out;
3750
3751 if (!hdr.PageLength)
3752 goto out;
3753
3754 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
3755 &dma_handle);
3756
3757 if (!buffer)
3758 goto out;
3759
3760 cfg.physAddr = dma_handle;
3761 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
3762
3763 if (mpt_config(ioc, &cfg) != 0)
3764 goto out;
3765
3766 if (!(buffer->VolumeStatus.Flags &
3767 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
3768 goto out;
3769
3770 if (!buffer->NumPhysDisks)
3771 goto out;
3772
3773 for (i = 0; i < buffer->NumPhysDisks; i++) {
3774
3775 if (mpt_raid_phys_disk_pg0(ioc,
3776 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
3777 continue;
3778
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303779 if (mptsas_sas_device_pg0(ioc, &sas_device,
3780 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3781 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3782 (phys_disk.PhysDiskBus << 8) +
3783 phys_disk.PhysDiskID))
3784 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003785
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303786 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3787 sas_device.sas_address);
3788 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07003789 }
3790
3791 out:
3792 if (buffer)
3793 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
3794 dma_handle);
3795}
Moore, Erice6b2d762006-03-14 09:14:24 -07003796/*
3797 * Work queue thread to handle SAS hotplug events
3798 */
Moore, Ericf44e5462006-03-14 09:14:21 -07003799static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303800mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
3801 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003802{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003803 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06003804 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07003805 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07003806 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303807 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06003808
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303809 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003810
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303811 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07003812
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303813 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07003814 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07003815
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303816 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
3817 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
3818 hot_plug_info->id) {
3819 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
3820 "to add hidden disk - target_id matchs "
3821 "volume_id\n", ioc->name);
3822 mptsas_free_fw_event(ioc, fw_event);
3823 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07003824 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003825 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303826 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003827
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003828 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303829 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
3830 mptsas_sas_device_pg0(ioc, &sas_device,
3831 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3832 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3833 (hot_plug_info->channel << 8) +
3834 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003835
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303836 if (!sas_device.handle)
3837 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06003838
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303839 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3840 if (!phy_info)
3841 break;
3842
3843 if (mptsas_get_rphy(phy_info))
3844 break;
3845
3846 mptsas_add_end_device(ioc, phy_info);
3847 break;
3848
3849 case MPTSAS_DEL_DEVICE:
3850 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3851 hot_plug_info->sas_address);
3852 mptsas_del_end_device(ioc, phy_info);
3853 break;
3854
3855 case MPTSAS_DEL_PHYSDISK:
3856
3857 mpt_findImVolumes(ioc);
3858
3859 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303860 ioc, hot_plug_info->phys_disk_num,
3861 hot_plug_info->channel,
3862 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303863 mptsas_del_end_device(ioc, phy_info);
3864 break;
3865
3866 case MPTSAS_ADD_PHYSDISK_REPROBE:
3867
Christoph Hellwige3094442006-02-16 13:25:36 +01003868 if (mptsas_sas_device_pg0(ioc, &sas_device,
3869 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07003870 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303871 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
3872 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3873 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3874 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01003875 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07003876 }
3877
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303878 phy_info = mptsas_find_phyinfo_by_sas_address(
3879 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07003880
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303881 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303882 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303883 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3884 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003885 break;
3886 }
3887
3888 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303889 if (!starget) {
3890 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3891 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3892 __func__, hot_plug_info->id, __LINE__));
3893 break;
3894 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003895
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303896 vtarget = starget->hostdata;
3897 if (!vtarget) {
3898 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3899 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3900 __func__, hot_plug_info->id, __LINE__));
3901 break;
3902 }
Eric Moore547f9a22006-06-27 14:42:12 -06003903
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303904 mpt_findImVolumes(ioc);
3905
3906 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
3907 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3908 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3909 hot_plug_info->phys_disk_num, (unsigned long long)
3910 sas_device.sas_address);
3911
3912 vtarget->id = hot_plug_info->phys_disk_num;
3913 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
3914 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
3915 mptsas_reprobe_target(starget, 1);
3916 break;
3917
3918 case MPTSAS_DEL_PHYSDISK_REPROBE:
3919
3920 if (mptsas_sas_device_pg0(ioc, &sas_device,
3921 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
3922 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3923 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303924 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303925 "%s: fw_id=%d exit at line=%d\n",
3926 ioc->name, __func__,
3927 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003928 break;
3929 }
3930
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303931 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3932 sas_device.sas_address);
3933 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303934 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303935 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3936 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003937 break;
Eric Moore547f9a22006-06-27 14:42:12 -06003938 }
Eric Mooreb506ade2007-01-29 09:45:37 -07003939
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303940 starget = mptsas_get_starget(phy_info);
3941 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303942 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303943 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3944 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003945 break;
3946 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003947
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303948 vtarget = starget->hostdata;
3949 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303950 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303951 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3952 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003953 break;
3954 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303955
3956 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
3957 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3958 "%s: fw_id=%d exit at line=%d\n", ioc->name,
3959 __func__, hot_plug_info->id, __LINE__));
3960 break;
3961 }
3962
3963 mpt_findImVolumes(ioc);
3964
3965 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
3966 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
3967 ioc->name, hot_plug_info->channel, hot_plug_info->id,
3968 hot_plug_info->phys_disk_num, (unsigned long long)
3969 sas_device.sas_address);
3970
3971 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
3972 vtarget->id = hot_plug_info->id;
3973 phy_info->attached.phys_disk_num = ~0;
3974 mptsas_reprobe_target(starget, 0);
3975 mptsas_add_device_component_by_fw(ioc,
3976 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003977 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303978
Moore, Ericc73787ee2006-01-26 16:20:06 -07003979 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303980
Moore, Ericc73787ee2006-01-26 16:20:06 -07003981 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303982 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3983 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3984 hot_plug_info->id);
3985 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
3986 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003987 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303988
Moore, Ericc73787ee2006-01-26 16:20:06 -07003989 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303990
Moore, Ericc73787ee2006-01-26 16:20:06 -07003991 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303992 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
3993 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3994 hot_plug_info->id);
3995 scsi_remove_device(hot_plug_info->sdev);
3996 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07003997 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05303998
Eric Mooreb506ade2007-01-29 09:45:37 -07003999 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304000
4001 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004002 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304003 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004004 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304005
Moore, Ericbd23e942006-04-17 12:43:04 -06004006 default:
4007 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004008 }
4009
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304010 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004011}
4012
4013static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304014mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004015{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304016 MPT_ADAPTER *ioc;
4017 struct mptsas_hotplug_event hot_plug_info;
4018 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4019 u32 device_info;
4020 u64 sas_address;
4021
4022 ioc = fw_event->ioc;
4023 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4024 fw_event->event_data;
4025 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004026
4027 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304028 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4029 MPI_SAS_DEVICE_INFO_STP_TARGET |
4030 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4031 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004032 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304033 }
4034
4035 if (sas_event_data->ReasonCode ==
4036 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4037 mptbase_sas_persist_operation(ioc,
4038 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4039 mptsas_free_fw_event(ioc, fw_event);
4040 return;
4041 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004042
Moore, Eric4b766472006-03-14 09:14:12 -07004043 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004044 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004045 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304046 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4047 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4048 hot_plug_info.channel = sas_event_data->Bus;
4049 hot_plug_info.id = sas_event_data->TargetID;
4050 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004051 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304052 sizeof(u64));
4053 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4054 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004055 if (sas_event_data->ReasonCode &
4056 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304057 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004058 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304059 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4060 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004061 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304062
Moore, Eric4b766472006-03-14 09:14:12 -07004063 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304064 mptbase_sas_persist_operation(ioc,
4065 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4066 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004067 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304068
Moore, Eric4b766472006-03-14 09:14:12 -07004069 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304070 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004071 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304072 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004073 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304074 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004075 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004076 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004077}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304078
Moore, Ericc73787ee2006-01-26 16:20:06 -07004079static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304080mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004081{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304082 MPT_ADAPTER *ioc;
4083 EVENT_DATA_RAID *raid_event_data;
4084 struct mptsas_hotplug_event hot_plug_info;
4085 int status;
4086 int state;
4087 struct scsi_device *sdev = NULL;
4088 VirtDevice *vdevice = NULL;
4089 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004090
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304091 ioc = fw_event->ioc;
4092 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4093 status = le32_to_cpu(raid_event_data->SettingsStatus);
4094 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004095
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304096 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4097 hot_plug_info.id = raid_event_data->VolumeID;
4098 hot_plug_info.channel = raid_event_data->VolumeBus;
4099 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4100
4101 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4102 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4103 raid_event_data->ReasonCode ==
4104 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4105 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4106 hot_plug_info.id, 0);
4107 hot_plug_info.sdev = sdev;
4108 if (sdev)
4109 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004110 }
4111
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304112 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4113 "ReasonCode=%02x\n", ioc->name, __func__,
4114 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004115
4116 switch (raid_event_data->ReasonCode) {
4117 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304118 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004119 break;
4120 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304121 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004122 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004123 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4124 switch (state) {
4125 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004126 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304127 mpt_raid_phys_disk_pg0(ioc,
4128 raid_event_data->PhysDiskNum, &phys_disk);
4129 hot_plug_info.id = phys_disk.PhysDiskID;
4130 hot_plug_info.channel = phys_disk.PhysDiskBus;
4131 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004132 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304133 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004134 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004135 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4136 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4137 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304138 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004139 break;
4140 default:
4141 break;
4142 }
4143 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004144 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304145 if (!sdev)
4146 break;
4147 vdevice->vtarget->deleted = 1; /* block IO */
4148 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004149 break;
4150 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304151 if (sdev) {
4152 scsi_device_put(sdev);
4153 break;
4154 }
4155 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004156 break;
4157 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304158 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4159 if (!sdev)
4160 break;
4161 vdevice->vtarget->deleted = 1; /* block IO */
4162 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4163 break;
4164 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004165 switch (state) {
4166 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4167 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304168 if (!sdev)
4169 break;
4170 vdevice->vtarget->deleted = 1; /* block IO */
4171 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004172 break;
4173 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4174 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304175 if (sdev) {
4176 scsi_device_put(sdev);
4177 break;
4178 }
4179 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004180 break;
4181 default:
4182 break;
4183 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004184 break;
4185 default:
4186 break;
4187 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304188
4189 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4190 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4191 else
4192 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004193}
4194
Eric Mooreb506ade2007-01-29 09:45:37 -07004195/*
4196 * mptsas_send_ir2_event - handle exposing hidden disk when
4197 * an inactive raid volume is added
4198 *
4199 * @ioc: Pointer to MPT_ADAPTER structure
4200 * @ir2_data
4201 *
4202 */
4203static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304204mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004205{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304206 MPT_ADAPTER *ioc;
4207 struct mptsas_hotplug_event hot_plug_info;
4208 MPI_EVENT_DATA_IR2 *ir2_data;
4209 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304210 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004211
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304212 ioc = fw_event->ioc;
4213 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4214 reasonCode = ir2_data->ReasonCode;
4215
4216 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4217 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4218
4219 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4220 hot_plug_info.id = ir2_data->TargetID;
4221 hot_plug_info.channel = ir2_data->Bus;
4222 switch (reasonCode) {
4223 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4224 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4225 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304226 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4227 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4228 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4229 break;
4230 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4231 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4232 mpt_raid_phys_disk_pg0(ioc,
4233 ir2_data->PhysDiskNum, &phys_disk);
4234 hot_plug_info.id = phys_disk.PhysDiskID;
4235 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4236 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304237 default:
4238 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004239 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304240 }
4241 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4242}
Moore, Erice6b2d762006-03-14 09:14:24 -07004243
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004244static int
4245mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4246{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304247 u32 event = le32_to_cpu(reply->Event);
4248 int sz, event_data_sz;
4249 struct fw_event_work *fw_event;
4250 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004251
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304252 /* events turned off due to host reset or driver unloading */
4253 if (ioc->fw_events_off)
4254 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004255
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304256 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004257 switch (event) {
4258 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304259 {
4260 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4261 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4262
4263 if (sas_event_data->ReasonCode ==
4264 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4265 mptsas_target_reset_queue(ioc, sas_event_data);
4266 return 0;
4267 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004268 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304269 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304270 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4271 {
4272 MpiEventDataSasExpanderStatusChange_t *expander_data =
4273 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4274
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304275 if (ioc->old_sas_discovery_protocal)
4276 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304277
4278 if (expander_data->ReasonCode ==
4279 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4280 ioc->device_missing_delay)
4281 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004282 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304283 }
4284 case MPI_EVENT_SAS_DISCOVERY:
4285 {
4286 u32 discovery_status;
4287 EventDataSasDiscovery_t *discovery_data =
4288 (EventDataSasDiscovery_t *)reply->Data;
4289
4290 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4291 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304292 if (ioc->old_sas_discovery_protocal && !discovery_status)
4293 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304294 return 0;
4295 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304296 case MPI_EVENT_INTEGRATED_RAID:
4297 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004298 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304299 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4300 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004301 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004302 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304303 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004304 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004305
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304306 event_data_sz = ((reply->MsgLength * 4) -
4307 offsetof(EventNotificationReply_t, Data));
4308 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4309 fw_event = kzalloc(sz, GFP_ATOMIC);
4310 if (!fw_event) {
4311 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4312 __func__, __LINE__);
4313 return 0;
4314 }
4315 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4316 fw_event->event = event;
4317 fw_event->ioc = ioc;
4318 mptsas_add_fw_event(ioc, fw_event, delay);
4319 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004320}
4321
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304322/* Delete a volume when no longer listed in ioc pg2
4323 */
4324static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4325{
4326 struct scsi_device *sdev;
4327 int i;
4328
4329 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4330 if (!sdev)
4331 return;
4332 if (!ioc->raid_data.pIocPg2)
4333 goto out;
4334 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4335 goto out;
4336 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4337 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4338 goto release_sdev;
4339 out:
4340 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4341 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4342 scsi_remove_device(sdev);
4343 release_sdev:
4344 scsi_device_put(sdev);
4345}
4346
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004347static int
4348mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4349{
4350 struct Scsi_Host *sh;
4351 MPT_SCSI_HOST *hd;
4352 MPT_ADAPTER *ioc;
4353 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004354 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004355 int numSGE = 0;
4356 int scale;
4357 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004358 int error=0;
4359 int r;
4360
4361 r = mpt_attach(pdev,id);
4362 if (r)
4363 return r;
4364
4365 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304366 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004367 ioc->DoneCtx = mptsasDoneCtx;
4368 ioc->TaskCtx = mptsasTaskCtx;
4369 ioc->InternalCtx = mptsasInternalCtx;
4370
4371 /* Added sanity check on readiness of the MPT adapter.
4372 */
4373 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4374 printk(MYIOC_s_WARN_FMT
4375 "Skipping because it's not operational!\n",
4376 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004377 error = -ENODEV;
4378 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004379 }
4380
4381 if (!ioc->active) {
4382 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4383 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004384 error = -ENODEV;
4385 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004386 }
4387
4388 /* Sanity check - ensure at least 1 port is INITIATOR capable
4389 */
4390 ioc_cap = 0;
4391 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4392 if (ioc->pfacts[ii].ProtocolFlags &
4393 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4394 ioc_cap++;
4395 }
4396
4397 if (!ioc_cap) {
4398 printk(MYIOC_s_WARN_FMT
4399 "Skipping ioc=%p because SCSI Initiator mode "
4400 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004401 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004402 }
4403
4404 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4405 if (!sh) {
4406 printk(MYIOC_s_WARN_FMT
4407 "Unable to register controller with SCSI subsystem\n",
4408 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004409 error = -1;
4410 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004411 }
4412
4413 spin_lock_irqsave(&ioc->FreeQlock, flags);
4414
4415 /* Attach the SCSI Host to the IOC structure
4416 */
4417 ioc->sh = sh;
4418
4419 sh->io_port = 0;
4420 sh->n_io_port = 0;
4421 sh->irq = 0;
4422
4423 /* set 16 byte cdb's */
4424 sh->max_cmd_len = 16;
4425
Eric Moore793955f2007-01-29 09:42:20 -07004426 sh->max_id = ioc->pfacts[0].PortSCSIID;
4427 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004428
4429 sh->transportt = mptsas_transport_template;
4430
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004431 /* Required entry.
4432 */
4433 sh->unique_id = ioc->id;
4434
4435 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004436 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004437 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004438 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004439 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004440
4441 /* Verify that we won't exceed the maximum
4442 * number of chain buffers
4443 * We can optimize: ZZ = req_sz/sizeof(SGE)
4444 * For 32bit SGE's:
4445 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4446 * + (req_sz - 64)/sizeof(SGE)
4447 * A slightly different algorithm is required for
4448 * 64bit SGEs.
4449 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304450 scale = ioc->req_sz/ioc->SGE_size;
4451 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004452 numSGE = (scale - 1) *
4453 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304454 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004455 } else {
4456 numSGE = 1 + (scale - 1) *
4457 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304458 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004459 }
4460
4461 if (numSGE < sh->sg_tablesize) {
4462 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304463 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004464 "Resetting sg_tablesize to %d from %d\n",
4465 ioc->name, numSGE, sh->sg_tablesize));
4466 sh->sg_tablesize = numSGE;
4467 }
4468
Eric Mooree7eae9f2007-09-29 10:15:59 -06004469 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004470 hd->ioc = ioc;
4471
4472 /* SCSI needs scsi_cmnd lookup table!
4473 * (with size equal to req_depth*PtrSz!)
4474 */
Eric Mooree8206382007-09-29 10:16:53 -06004475 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
4476 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004477 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06004478 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004479 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004480 }
Eric Mooree8206382007-09-29 10:16:53 -06004481 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004482
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304483 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06004484 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004485
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004486 /* Clear the TM flags
4487 */
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004488 hd->abortSCpnt = NULL;
4489
4490 /* Clear the pointer used to store
4491 * single-threaded commands, i.e., those
4492 * issued during a bus scan, dv and
4493 * configuration pages.
4494 */
4495 hd->cmdPtr = NULL;
4496
4497 /* Initialize this SCSI Hosts' timers
4498 * To use, set the timer expires field
4499 * and add_timer
4500 */
4501 init_timer(&hd->timer);
4502 hd->timer.data = (unsigned long) hd;
4503 hd->timer.function = mptscsih_timer_expired;
4504
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004505 ioc->sas_data.ptClear = mpt_pt_clear;
4506
Eric Mooredf9e0622007-01-29 09:46:21 -07004507 hd->last_queue_full = 0;
4508 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304509 INIT_LIST_HEAD(&ioc->sas_device_info_list);
4510 mutex_init(&ioc->sas_device_info_mutex);
4511
Eric Mooredf9e0622007-01-29 09:46:21 -07004512 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
4513
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004514 if (ioc->sas_data.ptClear==1) {
4515 mptbase_sas_persist_operation(
4516 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
4517 }
4518
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004519 error = scsi_add_host(sh, &ioc->pcidev->dev);
4520 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06004521 dprintk(ioc, printk(MYIOC_s_ERR_FMT
4522 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004523 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004524 }
4525
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304526 /* older firmware doesn't support expander events */
4527 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
4528 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004529 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304530 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004531 return 0;
4532
Eric Moore547f9a22006-06-27 14:42:12 -06004533 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004534
4535 mptscsih_remove(pdev);
4536 return error;
4537}
4538
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304539void
4540mptsas_shutdown(struct pci_dev *pdev)
4541{
4542 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4543
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304544 mptsas_fw_event_off(ioc);
4545 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304546}
4547
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004548static void __devexit mptsas_remove(struct pci_dev *pdev)
4549{
4550 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
4551 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06004552 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004553
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304554 mptsas_shutdown(pdev);
4555
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304556 mptsas_del_device_components(ioc);
4557
Eric Mooreb506ade2007-01-29 09:45:37 -07004558 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004559 sas_remove_host(ioc->sh);
4560
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004561 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004562 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
4563 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06004564 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304565 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304566
Eric Moore547f9a22006-06-27 14:42:12 -06004567 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004568 kfree(p);
4569 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004570 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304571 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004572 mptscsih_remove(pdev);
4573}
4574
4575static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06004576 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004577 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004578 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004579 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004580 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004581 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004582 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004583 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06004584 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004585 PCI_ANY_ID, PCI_ANY_ID },
4586 {0} /* Terminating entry */
4587};
4588MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
4589
4590
4591static struct pci_driver mptsas_driver = {
4592 .name = "mptsas",
4593 .id_table = mptsas_pci_table,
4594 .probe = mptsas_probe,
4595 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05304596 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004597#ifdef CONFIG_PM
4598 .suspend = mptscsih_suspend,
4599 .resume = mptscsih_resume,
4600#endif
4601};
4602
4603static int __init
4604mptsas_init(void)
4605{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304606 int error;
4607
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004608 show_mptmod_ver(my_NAME, my_VERSION);
4609
4610 mptsas_transport_template =
4611 sas_attach_transport(&mptsas_transport_functions);
4612 if (!mptsas_transport_template)
4613 return -ENODEV;
4614
4615 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304616 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004617 mptsasInternalCtx =
4618 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004619 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304620 mptsasDeviceResetCtx =
4621 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004622
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304623 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
4624 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004625
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05304626 error = pci_register_driver(&mptsas_driver);
4627 if (error)
4628 sas_release_transport(mptsas_transport_template);
4629
4630 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004631}
4632
4633static void __exit
4634mptsas_exit(void)
4635{
4636 pci_unregister_driver(&mptsas_driver);
4637 sas_release_transport(mptsas_transport_template);
4638
4639 mpt_reset_deregister(mptsasDoneCtx);
4640 mpt_event_deregister(mptsasDoneCtx);
4641
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004642 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004643 mpt_deregister(mptsasInternalCtx);
4644 mpt_deregister(mptsasTaskCtx);
4645 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05304646 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004647}
4648
4649module_init(mptsas_init);
4650module_exit(mptsas_exit);