blob: c20bbe45da82d4811d57618cb1144fa8af44f662 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
9/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 NO WARRANTY
21 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 solely responsible for determining the appropriateness of using and
26 distributing the Program and assumes all risks associated with its
27 exercise of rights under this Agreement, including but not limited to
28 the risks and costs of program errors, damage to or loss of data,
29 programs or equipment, and unavailability or interruption of operations.
30
31 DISCLAIMER OF LIABILITY
32 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43*/
44/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45
46#include <linux/module.h>
47#include <linux/kernel.h>
48#include <linux/init.h>
49#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080050#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020051#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060052#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020053
Eric Moore547f9a22006-06-27 14:42:12 -060054#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020055#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
57#include <scsi/scsi_host.h>
58#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060059#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020060
61#include "mptbase.h"
62#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053063#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020064
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Kashyap, Desai4b976502009-08-05 12:52:03 +053075#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020076MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070079MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081static int mpt_pt_clear;
82module_param(mpt_pt_clear, int, 0);
83MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060084 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020085 "(default=MPTSCSIH_PT_CLEAR=0)");
86
Eric Moore793955f2007-01-29 09:42:20 -070087/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
88#define MPTSAS_MAX_LUN (16895)
89static int max_lun = MPTSAS_MAX_LUN;
90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92
Prakash, Sathyaf606f572007-08-14 16:12:53 +053093static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
96static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053097static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Kashyap, Desai3eb08222009-05-29 16:47:26 +053099static void mptsas_firmware_event_work(struct work_struct *work);
100static void mptsas_send_sas_event(struct fw_event_work *fw_event);
101static void mptsas_send_raid_event(struct fw_event_work *fw_event);
102static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
103static void mptsas_parse_device_info(struct sas_identify *identify,
104 struct mptsas_devinfo *device_info);
105static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
106 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
107static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
108 (MPT_ADAPTER *ioc, u64 sas_address);
109static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
110 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
111static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
112 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
113static int mptsas_add_end_device(MPT_ADAPTER *ioc,
114 struct mptsas_phyinfo *phy_info);
115static void mptsas_del_end_device(MPT_ADAPTER *ioc,
116 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530117static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
118static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
119 (MPT_ADAPTER *ioc, u64 sas_address);
120static void mptsas_expander_delete(MPT_ADAPTER *ioc,
121 struct mptsas_portinfo *port_info, u8 force);
122static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530123static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
124static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530125static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530126static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530127static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200128
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530129static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
130 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200131{
Eric Moore29dd3602007-09-14 18:46:51 -0600132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
133 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
135 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
137 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
139 ioc->name, phy_data->Port));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
141 ioc->name, phy_data->PortFlags));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
143 ioc->name, phy_data->PhyFlags));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
145 ioc->name, phy_data->NegotiatedLinkRate));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
147 "Controller PHY Device Info=0x%X\n", ioc->name,
148 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
149 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
150 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200151}
152
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530153static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200154{
155 __le64 sas_address;
156
157 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
158
Eric Moore29dd3602007-09-14 18:46:51 -0600159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
160 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
162 "Attached Device Handle=0x%X\n", ioc->name,
163 le16_to_cpu(pg0->AttachedDevHandle)));
164 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
165 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
166 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
167 "Attached PHY Identifier=0x%X\n", ioc->name,
168 pg0->AttachedPhyIdentifier));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
170 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
172 ioc->name, pg0->ProgrammedLinkRate));
173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
174 ioc->name, pg0->ChangeCount));
175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
176 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200177}
178
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530179static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200180{
Eric Moore29dd3602007-09-14 18:46:51 -0600181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
182 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
184 ioc->name, pg1->InvalidDwordCount));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
186 "Running Disparity Error Count=0x%x\n", ioc->name,
187 pg1->RunningDisparityErrorCount));
188 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
189 "Loss Dword Synch Count=0x%x\n", ioc->name,
190 pg1->LossDwordSynchCount));
191 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
192 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
193 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200194}
195
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530196static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200197{
198 __le64 sas_address;
199
200 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
201
Eric Moore29dd3602007-09-14 18:46:51 -0600202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
203 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
205 ioc->name, le16_to_cpu(pg0->DevHandle)));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
207 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
209 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
211 ioc->name, le16_to_cpu(pg0->Slot)));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
213 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
215 ioc->name, pg0->TargetID));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
217 ioc->name, pg0->Bus));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
219 ioc->name, pg0->PhyNum));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
221 ioc->name, le16_to_cpu(pg0->AccessStatus)));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
223 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
224 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
225 ioc->name, le16_to_cpu(pg0->Flags)));
226 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
227 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200228}
229
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530230static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200231{
Eric Moore29dd3602007-09-14 18:46:51 -0600232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
233 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
235 ioc->name, pg1->PhysicalPort));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
237 ioc->name, pg1->PhyIdentifier));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
239 ioc->name, pg1->NegotiatedLinkRate));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
241 ioc->name, pg1->ProgrammedLinkRate));
242 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
243 ioc->name, pg1->HwLinkRate));
244 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
245 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
246 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
247 "Attached Device Handle=0x%X\n\n", ioc->name,
248 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200249}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200250
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530251/* inhibit sas firmware event handling */
252static void
253mptsas_fw_event_off(MPT_ADAPTER *ioc)
254{
255 unsigned long flags;
256
257 spin_lock_irqsave(&ioc->fw_event_lock, flags);
258 ioc->fw_events_off = 1;
259 ioc->sas_discovery_quiesce_io = 0;
260 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
261
262}
263
264/* enable sas firmware event handling */
265static void
266mptsas_fw_event_on(MPT_ADAPTER *ioc)
267{
268 unsigned long flags;
269
270 spin_lock_irqsave(&ioc->fw_event_lock, flags);
271 ioc->fw_events_off = 0;
272 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
273}
274
275/* queue a sas firmware event */
276static void
277mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
278 unsigned long delay)
279{
280 unsigned long flags;
281
282 spin_lock_irqsave(&ioc->fw_event_lock, flags);
283 list_add_tail(&fw_event->list, &ioc->fw_event_list);
284 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
285 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
286 ioc->name, __func__, fw_event));
287 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
288 delay);
289 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
290}
291
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530292/* requeue a sas firmware event */
293static void
294mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
295 unsigned long delay)
296{
297 unsigned long flags;
298 spin_lock_irqsave(&ioc->fw_event_lock, flags);
299 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
300 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
301 fw_event->retries++;
302 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
303 msecs_to_jiffies(delay));
304 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
305}
306
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530307/* free memory assoicated to a sas firmware event */
308static void
309mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
310{
311 unsigned long flags;
312
313 spin_lock_irqsave(&ioc->fw_event_lock, flags);
314 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
315 ioc->name, __func__, fw_event));
316 list_del(&fw_event->list);
317 kfree(fw_event);
318 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
319}
320
321/* walk the firmware event queue, and either stop or wait for
322 * outstanding events to complete */
323static void
324mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
325{
326 struct fw_event_work *fw_event, *next;
327 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530328 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
329
330 /* flush the target_reset_list */
331 if (!list_empty(&hd->target_reset_list)) {
332 list_for_each_entry_safe(target_reset_list, n,
333 &hd->target_reset_list, list) {
334 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
335 "%s: removing target reset for id=%d\n",
336 ioc->name, __func__,
337 target_reset_list->sas_event_data.TargetID));
338 list_del(&target_reset_list->list);
339 kfree(target_reset_list);
340 }
341 }
342
343 if (list_empty(&ioc->fw_event_list) ||
344 !ioc->fw_event_q || in_interrupt())
345 return;
346
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530347 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
348 if (cancel_delayed_work(&fw_event->work))
349 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530350 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530351}
352
353
Christoph Hellwige3094442006-02-16 13:25:36 +0100354static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
355{
356 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
357 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
358}
359
360static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
361{
362 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
363 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
364}
365
Moore, Erice6b2d762006-03-14 09:14:24 -0700366/*
367 * mptsas_find_portinfo_by_handle
368 *
369 * This function should be called with the sas_topology_mutex already held
370 */
371static struct mptsas_portinfo *
372mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
373{
374 struct mptsas_portinfo *port_info, *rc=NULL;
375 int i;
376
377 list_for_each_entry(port_info, &ioc->sas_topology, list)
378 for (i = 0; i < port_info->num_phys; i++)
379 if (port_info->phy_info[i].identify.handle == handle) {
380 rc = port_info;
381 goto out;
382 }
383 out:
384 return rc;
385}
386
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530387/**
388 * mptsas_find_portinfo_by_sas_address -
389 * @ioc: Pointer to MPT_ADAPTER structure
390 * @handle:
391 *
392 * This function should be called with the sas_topology_mutex already held
393 *
394 **/
395static struct mptsas_portinfo *
396mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
397{
398 struct mptsas_portinfo *port_info, *rc = NULL;
399 int i;
400
401 if (sas_address >= ioc->hba_port_sas_addr &&
402 sas_address < (ioc->hba_port_sas_addr +
403 ioc->hba_port_num_phy))
404 return ioc->hba_port_info;
405
406 mutex_lock(&ioc->sas_topology_mutex);
407 list_for_each_entry(port_info, &ioc->sas_topology, list)
408 for (i = 0; i < port_info->num_phys; i++)
409 if (port_info->phy_info[i].identify.sas_address ==
410 sas_address) {
411 rc = port_info;
412 goto out;
413 }
414 out:
415 mutex_unlock(&ioc->sas_topology_mutex);
416 return rc;
417}
418
Moore, Ericbd23e942006-04-17 12:43:04 -0600419/*
420 * Returns true if there is a scsi end device
421 */
422static inline int
423mptsas_is_end_device(struct mptsas_devinfo * attached)
424{
Eric Moore547f9a22006-06-27 14:42:12 -0600425 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600426 (attached->device_info &
427 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
428 ((attached->device_info &
429 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
430 (attached->device_info &
431 MPI_SAS_DEVICE_INFO_STP_TARGET) |
432 (attached->device_info &
433 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
434 return 1;
435 else
436 return 0;
437}
438
Eric Moore547f9a22006-06-27 14:42:12 -0600439/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600440static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530441mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600442{
443 struct mptsas_portinfo *port_info;
444 struct mptsas_phyinfo *phy_info;
445 u8 i;
446
447 if (!port_details)
448 return;
449
450 port_info = port_details->port_info;
451 phy_info = port_info->phy_info;
452
Eric Moore29dd3602007-09-14 18:46:51 -0600453 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700454 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700455 port_details->num_phys, (unsigned long long)
456 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600457
458 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
459 if(phy_info->port_details != port_details)
460 continue;
461 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530462 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600463 phy_info->port_details = NULL;
464 }
465 kfree(port_details);
466}
467
468static inline struct sas_rphy *
469mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
470{
471 if (phy_info->port_details)
472 return phy_info->port_details->rphy;
473 else
474 return NULL;
475}
476
477static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530478mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600479{
480 if (phy_info->port_details) {
481 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600482 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
483 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600484 }
485
Eric Moore547f9a22006-06-27 14:42:12 -0600486 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600487 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
488 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600489 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
490 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600491 }
Eric Moore547f9a22006-06-27 14:42:12 -0600492}
493
494static inline struct sas_port *
495mptsas_get_port(struct mptsas_phyinfo *phy_info)
496{
497 if (phy_info->port_details)
498 return phy_info->port_details->port;
499 else
500 return NULL;
501}
502
503static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530504mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600505{
506 if (phy_info->port_details)
507 phy_info->port_details->port = port;
508
Eric Moore547f9a22006-06-27 14:42:12 -0600509 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600510 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
511 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600512 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
513 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600514 }
Eric Moore547f9a22006-06-27 14:42:12 -0600515}
516
517static inline struct scsi_target *
518mptsas_get_starget(struct mptsas_phyinfo *phy_info)
519{
520 if (phy_info->port_details)
521 return phy_info->port_details->starget;
522 else
523 return NULL;
524}
525
526static inline void
527mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
528starget)
529{
530 if (phy_info->port_details)
531 phy_info->port_details->starget = starget;
532}
533
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530534/**
535 * mptsas_add_device_component -
536 * @ioc: Pointer to MPT_ADAPTER structure
537 * @channel: fw mapped id's
538 * @id:
539 * @sas_address:
540 * @device_info:
541 *
542 **/
543static void
544mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
545 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
546{
547 struct mptsas_device_info *sas_info, *next;
548 struct scsi_device *sdev;
549 struct scsi_target *starget;
550 struct sas_rphy *rphy;
551
552 /*
553 * Delete all matching devices out of the list
554 */
555 mutex_lock(&ioc->sas_device_info_mutex);
556 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
557 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530558 if (!sas_info->is_logical_volume &&
559 (sas_info->sas_address == sas_address ||
560 (sas_info->fw.channel == channel &&
561 sas_info->fw.id == id))) {
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530562 list_del(&sas_info->list);
563 kfree(sas_info);
564 }
565 }
566
567 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
568 if (!sas_info)
569 goto out;
570
571 /*
572 * Set Firmware mapping
573 */
574 sas_info->fw.id = id;
575 sas_info->fw.channel = channel;
576
577 sas_info->sas_address = sas_address;
578 sas_info->device_info = device_info;
579 sas_info->slot = slot;
580 sas_info->enclosure_logical_id = enclosure_logical_id;
581 INIT_LIST_HEAD(&sas_info->list);
582 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
583
584 /*
585 * Set OS mapping
586 */
587 shost_for_each_device(sdev, ioc->sh) {
588 starget = scsi_target(sdev);
589 rphy = dev_to_rphy(starget->dev.parent);
590 if (rphy->identify.sas_address == sas_address) {
591 sas_info->os.id = starget->id;
592 sas_info->os.channel = starget->channel;
593 }
594 }
595
596 out:
597 mutex_unlock(&ioc->sas_device_info_mutex);
598 return;
599}
600
601/**
602 * mptsas_add_device_component_by_fw -
603 * @ioc: Pointer to MPT_ADAPTER structure
604 * @channel: fw mapped id's
605 * @id:
606 *
607 **/
608static void
609mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
610{
611 struct mptsas_devinfo sas_device;
612 struct mptsas_enclosure enclosure_info;
613 int rc;
614
615 rc = mptsas_sas_device_pg0(ioc, &sas_device,
616 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
617 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
618 (channel << 8) + id);
619 if (rc)
620 return;
621
622 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
623 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
624 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
625 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
626 sas_device.handle_enclosure);
627
628 mptsas_add_device_component(ioc, sas_device.channel,
629 sas_device.id, sas_device.sas_address, sas_device.device_info,
630 sas_device.slot, enclosure_info.enclosure_logical_id);
631}
632
633/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000634 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530635 * @ioc: Pointer to MPT_ADAPTER structure
636 * @channel: fw mapped id's
637 * @id:
638 *
639 **/
640static void
641mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
642 struct scsi_target *starget)
643{
644 CONFIGPARMS cfg;
645 ConfigPageHeader_t hdr;
646 dma_addr_t dma_handle;
647 pRaidVolumePage0_t buffer = NULL;
648 int i;
649 RaidPhysDiskPage0_t phys_disk;
650 struct mptsas_device_info *sas_info, *next;
651
652 memset(&cfg, 0 , sizeof(CONFIGPARMS));
653 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
654 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
655 /* assumption that all volumes on channel = 0 */
656 cfg.pageAddr = starget->id;
657 cfg.cfghdr.hdr = &hdr;
658 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530659 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530660
661 if (mpt_config(ioc, &cfg) != 0)
662 goto out;
663
664 if (!hdr.PageLength)
665 goto out;
666
667 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
668 &dma_handle);
669
670 if (!buffer)
671 goto out;
672
673 cfg.physAddr = dma_handle;
674 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
675
676 if (mpt_config(ioc, &cfg) != 0)
677 goto out;
678
679 if (!buffer->NumPhysDisks)
680 goto out;
681
682 /*
683 * Adding entry for hidden components
684 */
685 for (i = 0; i < buffer->NumPhysDisks; i++) {
686
687 if (mpt_raid_phys_disk_pg0(ioc,
688 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
689 continue;
690
691 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
692 phys_disk.PhysDiskID);
693
Kashyap, Desai57e98512009-05-29 16:55:09 +0530694 mutex_lock(&ioc->sas_device_info_mutex);
695 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
696 list) {
697 if (!sas_info->is_logical_volume &&
698 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
699 sas_info->fw.id == phys_disk.PhysDiskID)) {
700 sas_info->is_hidden_raid_component = 1;
701 sas_info->volume_id = starget->id;
702 }
703 }
704 mutex_unlock(&ioc->sas_device_info_mutex);
705
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530706 }
707
708 /*
709 * Delete all matching devices out of the list
710 */
711 mutex_lock(&ioc->sas_device_info_mutex);
712 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
713 list) {
714 if (sas_info->is_logical_volume && sas_info->fw.id ==
715 starget->id) {
716 list_del(&sas_info->list);
717 kfree(sas_info);
718 }
719 }
720
721 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
722 if (sas_info) {
723 sas_info->fw.id = starget->id;
724 sas_info->os.id = starget->id;
725 sas_info->os.channel = starget->channel;
726 sas_info->is_logical_volume = 1;
727 INIT_LIST_HEAD(&sas_info->list);
728 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
729 }
730 mutex_unlock(&ioc->sas_device_info_mutex);
731
732 out:
733 if (buffer)
734 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
735 dma_handle);
736}
737
738/**
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530739 * mptsas_add_device_component_starget -
740 * @ioc: Pointer to MPT_ADAPTER structure
741 * @starget:
742 *
743 **/
744static void
745mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
746 struct scsi_target *starget)
747{
748 VirtTarget *vtarget;
749 struct sas_rphy *rphy;
750 struct mptsas_phyinfo *phy_info = NULL;
751 struct mptsas_enclosure enclosure_info;
752
753 rphy = dev_to_rphy(starget->dev.parent);
754 vtarget = starget->hostdata;
755 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
756 rphy->identify.sas_address);
757 if (!phy_info)
758 return;
759
760 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
761 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
762 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
763 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
764 phy_info->attached.handle_enclosure);
765
766 mptsas_add_device_component(ioc, phy_info->attached.channel,
767 phy_info->attached.id, phy_info->attached.sas_address,
768 phy_info->attached.device_info,
769 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
770}
771
772/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000773 * mptsas_del_device_component_by_os - Once a device has been removed, we mark the entry in the list as being cached
Kashyap, Desai57e98512009-05-29 16:55:09 +0530774 * @ioc: Pointer to MPT_ADAPTER structure
775 * @channel: os mapped id's
776 * @id:
777 *
778 **/
779static void
780mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
781{
782 struct mptsas_device_info *sas_info, *next;
783
784 /*
785 * Set is_cached flag
786 */
787 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
788 list) {
789 if (sas_info->os.channel == channel && sas_info->os.id == id)
790 sas_info->is_cached = 1;
791 }
792}
793
794/**
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530795 * mptsas_del_device_components - Cleaning the list
796 * @ioc: Pointer to MPT_ADAPTER structure
797 *
798 **/
799static void
800mptsas_del_device_components(MPT_ADAPTER *ioc)
801{
802 struct mptsas_device_info *sas_info, *next;
803
804 mutex_lock(&ioc->sas_device_info_mutex);
805 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
806 list) {
807 list_del(&sas_info->list);
808 kfree(sas_info);
809 }
810 mutex_unlock(&ioc->sas_device_info_mutex);
811}
812
Eric Moore547f9a22006-06-27 14:42:12 -0600813
814/*
815 * mptsas_setup_wide_ports
816 *
817 * Updates for new and existing narrow/wide port configuration
818 * in the sas_topology
819 */
Eric Moore376ac832006-06-29 17:36:26 -0600820static void
Eric Moore547f9a22006-06-27 14:42:12 -0600821mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
822{
823 struct mptsas_portinfo_details * port_details;
824 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
825 u64 sas_address;
826 int i, j;
827
828 mutex_lock(&ioc->sas_topology_mutex);
829
830 phy_info = port_info->phy_info;
831 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
832 if (phy_info->attached.handle)
833 continue;
834 port_details = phy_info->port_details;
835 if (!port_details)
836 continue;
837 if (port_details->num_phys < 2)
838 continue;
839 /*
840 * Removing a phy from a port, letting the last
841 * phy be removed by firmware events.
842 */
Eric Moore29dd3602007-09-14 18:46:51 -0600843 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
844 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700845 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600846 port_details->num_phys--;
847 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
848 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530849 if (phy_info->phy) {
850 devtprintk(ioc, dev_printk(KERN_DEBUG,
851 &phy_info->phy->dev, MYIOC_s_FMT
852 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
853 phy_info->phy_id, phy_info->phy));
854 sas_port_delete_phy(port_details->port, phy_info->phy);
855 }
Eric Moore547f9a22006-06-27 14:42:12 -0600856 phy_info->port_details = NULL;
857 }
858
859 /*
860 * Populate and refresh the tree
861 */
862 phy_info = port_info->phy_info;
863 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
864 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600865 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
866 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600867 if (!sas_address)
868 continue;
869 port_details = phy_info->port_details;
870 /*
871 * Forming a port
872 */
873 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530874 port_details = kzalloc(sizeof(struct
875 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600876 if (!port_details)
877 goto out;
878 port_details->num_phys = 1;
879 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600880 if (phy_info->phy_id < 64 )
881 port_details->phy_bitmask |=
882 (1 << phy_info->phy_id);
883 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600884 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700885 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600886 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600887 phy_info->port_details = port_details;
888 }
889
890 if (i == port_info->num_phys - 1)
891 continue;
892 phy_info_cmp = &port_info->phy_info[i + 1];
893 for (j = i + 1 ; j < port_info->num_phys ; j++,
894 phy_info_cmp++) {
895 if (!phy_info_cmp->attached.sas_address)
896 continue;
897 if (sas_address != phy_info_cmp->attached.sas_address)
898 continue;
899 if (phy_info_cmp->port_details == port_details )
900 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600901 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700902 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600903 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700904 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600905 if (phy_info_cmp->port_details) {
906 port_details->rphy =
907 mptsas_get_rphy(phy_info_cmp);
908 port_details->port =
909 mptsas_get_port(phy_info_cmp);
910 port_details->starget =
911 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600912 port_details->num_phys =
913 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600914 if (!phy_info_cmp->port_details->num_phys)
915 kfree(phy_info_cmp->port_details);
916 } else
917 phy_info_cmp->sas_port_add_phy=1;
918 /*
919 * Adding a phy to a port
920 */
921 phy_info_cmp->port_details = port_details;
922 if (phy_info_cmp->phy_id < 64 )
923 port_details->phy_bitmask |=
924 (1 << phy_info_cmp->phy_id);
925 port_details->num_phys++;
926 }
927 }
928
929 out:
930
Eric Moore547f9a22006-06-27 14:42:12 -0600931 for (i = 0; i < port_info->num_phys; i++) {
932 port_details = port_info->phy_info[i].port_details;
933 if (!port_details)
934 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600935 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700936 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700937 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700938 port_details, i, port_details->num_phys,
939 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600940 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
941 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600942 }
Eric Moore29dd3602007-09-14 18:46:51 -0600943 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600944 mutex_unlock(&ioc->sas_topology_mutex);
945}
946
Eric Mooredf9e0622007-01-29 09:46:21 -0700947/**
948 * csmisas_find_vtarget
949 *
950 * @ioc
951 * @volume_id
952 * @volume_bus
953 *
954 **/
955static VirtTarget *
956mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600957{
Eric Mooredf9e0622007-01-29 09:46:21 -0700958 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600959 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700960 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600961
Eric Mooredf9e0622007-01-29 09:46:21 -0700962 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530963 vdevice = sdev->hostdata;
964 if ((vdevice == NULL) ||
965 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700966 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530967 if ((vdevice->vtarget->tflags &
968 MPT_TARGET_FLAGS_RAID_COMPONENT ||
969 vdevice->vtarget->raidVolume))
970 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600971 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530972 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600973 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600974 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700975 return vtarget;
976}
977
Kashyap, Desai3eb08222009-05-29 16:47:26 +0530978static void
979mptsas_queue_device_delete(MPT_ADAPTER *ioc,
980 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
981{
982 struct fw_event_work *fw_event;
983 int sz;
984
985 sz = offsetof(struct fw_event_work, event_data) +
986 sizeof(MpiEventDataSasDeviceStatusChange_t);
987 fw_event = kzalloc(sz, GFP_ATOMIC);
988 if (!fw_event) {
989 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
990 ioc->name, __func__, __LINE__);
991 return;
992 }
993 memcpy(fw_event->event_data, sas_event_data,
994 sizeof(MpiEventDataSasDeviceStatusChange_t));
995 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
996 fw_event->ioc = ioc;
997 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
998}
999
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301000static void
1001mptsas_queue_rescan(MPT_ADAPTER *ioc)
1002{
1003 struct fw_event_work *fw_event;
1004 int sz;
1005
1006 sz = offsetof(struct fw_event_work, event_data);
1007 fw_event = kzalloc(sz, GFP_ATOMIC);
1008 if (!fw_event) {
1009 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1010 ioc->name, __func__, __LINE__);
1011 return;
1012 }
1013 fw_event->event = -1;
1014 fw_event->ioc = ioc;
1015 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1016}
1017
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301018
Eric Mooredf9e0622007-01-29 09:46:21 -07001019/**
1020 * mptsas_target_reset
1021 *
1022 * Issues TARGET_RESET to end device using handshaking method
1023 *
1024 * @ioc
1025 * @channel
1026 * @id
1027 *
1028 * Returns (1) success
1029 * (0) failure
1030 *
1031 **/
1032static int
1033mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1034{
1035 MPT_FRAME_HDR *mf;
1036 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301037 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1038 return 0;
1039
Eric Mooredf9e0622007-01-29 09:46:21 -07001040
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301041 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1042 if (mf == NULL) {
1043 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301044 "%s, no msg frames @%d!!\n", ioc->name,
1045 __func__, __LINE__));
1046 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001047 }
1048
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301049 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1050 ioc->name, mf));
1051
Eric Mooredf9e0622007-01-29 09:46:21 -07001052 /* Format the Request
1053 */
1054 pScsiTm = (SCSITaskMgmt_t *) mf;
1055 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1056 pScsiTm->TargetID = id;
1057 pScsiTm->Bus = channel;
1058 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1059 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1060 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1061
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301062 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001063
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301064 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1065 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1066 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1067
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301068 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001069
1070 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301071
1072 out_fail:
1073
1074 mpt_clear_taskmgmt_in_progress_flag(ioc);
1075 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001076}
1077
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301078static void
1079mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1080{
1081 scsi_device_set_state(sdev, SDEV_BLOCK);
1082}
1083
1084static void
1085mptsas_block_io_starget(struct scsi_target *starget)
1086{
1087 if (starget)
1088 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1089}
1090
Eric Mooredf9e0622007-01-29 09:46:21 -07001091/**
1092 * mptsas_target_reset_queue
1093 *
1094 * Receive request for TARGET_RESET after recieving an firmware
1095 * event NOT_RESPONDING_EVENT, then put command in link list
1096 * and queue if task_queue already in use.
1097 *
1098 * @ioc
1099 * @sas_event_data
1100 *
1101 **/
1102static void
1103mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1104 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1105{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001106 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001107 VirtTarget *vtarget = NULL;
1108 struct mptsas_target_reset_event *target_reset_list;
1109 u8 id, channel;
1110
1111 id = sas_event_data->TargetID;
1112 channel = sas_event_data->Bus;
1113
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301114 vtarget = mptsas_find_vtarget(ioc, channel, id);
1115 if (vtarget) {
1116 mptsas_block_io_starget(vtarget->starget);
1117 vtarget->deleted = 1; /* block IO */
1118 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001119
Kashyap, Desai2f187862009-05-29 16:52:37 +05301120 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001121 GFP_ATOMIC);
1122 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301123 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1124 "%s, failed to allocate mem @%d..!!\n",
1125 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001126 return;
1127 }
1128
1129 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1130 sizeof(*sas_event_data));
1131 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1132
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301133 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001134
1135 if (mptsas_target_reset(ioc, channel, id)) {
1136 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001137 }
1138}
1139
1140/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001141 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301142 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001143 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001144 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1145 * queue to finish off removing device from upper layers. then send next
1146 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001147 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301148static int
1149mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001150{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001151 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001152 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001153 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301154 struct mptsas_target_reset_event *target_reset_list;
1155 SCSITaskMgmtReply_t *pScsiTmReply;
1156
1157 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1158 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1159
1160 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1161 if (pScsiTmReply) {
1162 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1163 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1164 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1165 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1166 "term_cmnds = %d\n", ioc->name,
1167 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1168 pScsiTmReply->TaskType,
1169 le16_to_cpu(pScsiTmReply->IOCStatus),
1170 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1171 pScsiTmReply->ResponseCode,
1172 le32_to_cpu(pScsiTmReply->TerminationCount)));
1173
1174 if (pScsiTmReply->ResponseCode)
1175 mptscsih_taskmgmt_response_code(ioc,
1176 pScsiTmReply->ResponseCode);
1177 }
1178
1179 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1180 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1181 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1182 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1183 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1184 memcpy(ioc->taskmgmt_cmds.reply, mr,
1185 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1186 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1187 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1188 complete(&ioc->taskmgmt_cmds.done);
1189 return 1;
1190 }
1191 return 0;
1192 }
1193
1194 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001195
1196 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301197 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001198
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301199 target_reset_list = list_entry(head->next,
1200 struct mptsas_target_reset_event, list);
1201
1202 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1203 "TaskMgmt: completed (%d seconds)\n",
1204 ioc->name, jiffies_to_msecs(jiffies -
1205 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001206
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301207 id = pScsiTmReply->TargetID;
1208 channel = pScsiTmReply->Bus;
1209 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001210
1211 /*
1212 * retry target reset
1213 */
1214 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301215 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001216 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301217 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001218 }
1219
1220 /*
1221 * enable work queue to remove device from upper layers
1222 */
1223 list_del(&target_reset_list->list);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301224 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1225 mptsas_queue_device_delete(ioc,
1226 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301227
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301228
Eric Mooredf9e0622007-01-29 09:46:21 -07001229 /*
1230 * issue target reset to next device in the queue
1231 */
1232
1233 head = &hd->target_reset_list;
1234 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301235 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001236
1237 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1238 list);
1239
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301240 id = target_reset_list->sas_event_data.TargetID;
1241 channel = target_reset_list->sas_event_data.Bus;
1242 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001243
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301244 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001245 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001246
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301247 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001248}
1249
1250/**
1251 * mptscsih_ioc_reset
1252 *
1253 * @ioc
1254 * @reset_phase
1255 *
1256 **/
1257static int
1258mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1259{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001260 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001261 int rc;
1262
1263 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301264 if ((ioc->bus_type != SAS) || (!rc))
1265 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001266
Eric Mooree7eae9f2007-09-29 10:15:59 -06001267 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001268 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001269 goto out;
1270
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301271 switch (reset_phase) {
1272 case MPT_IOC_SETUP_RESET:
1273 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1274 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1275 mptsas_fw_event_off(ioc);
1276 break;
1277 case MPT_IOC_PRE_RESET:
1278 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1279 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1280 break;
1281 case MPT_IOC_POST_RESET:
1282 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1283 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1284 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1285 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1286 complete(&ioc->sas_mgmt.done);
1287 }
1288 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301289 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301290 break;
1291 default:
1292 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001293 }
1294
1295 out:
1296 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001297}
1298
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301299
1300/**
1301 * enum device_state -
1302 * @DEVICE_RETRY: need to retry the TUR
1303 * @DEVICE_ERROR: TUR return error, don't add device
1304 * @DEVICE_READY: device can be added
1305 *
1306 */
1307enum device_state{
1308 DEVICE_RETRY,
1309 DEVICE_ERROR,
1310 DEVICE_READY,
1311};
1312
Christoph Hellwige3094442006-02-16 13:25:36 +01001313static int
Moore, Eric52435432006-03-14 09:14:15 -07001314mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001315 u32 form, u32 form_specific)
1316{
1317 ConfigExtendedPageHeader_t hdr;
1318 CONFIGPARMS cfg;
1319 SasEnclosurePage0_t *buffer;
1320 dma_addr_t dma_handle;
1321 int error;
1322 __le64 le_identifier;
1323
1324 memset(&hdr, 0, sizeof(hdr));
1325 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1326 hdr.PageNumber = 0;
1327 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1328 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1329
1330 cfg.cfghdr.ehdr = &hdr;
1331 cfg.physAddr = -1;
1332 cfg.pageAddr = form + form_specific;
1333 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1334 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301335 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001336
1337 error = mpt_config(ioc, &cfg);
1338 if (error)
1339 goto out;
1340 if (!hdr.ExtPageLength) {
1341 error = -ENXIO;
1342 goto out;
1343 }
1344
1345 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1346 &dma_handle);
1347 if (!buffer) {
1348 error = -ENOMEM;
1349 goto out;
1350 }
1351
1352 cfg.physAddr = dma_handle;
1353 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1354
1355 error = mpt_config(ioc, &cfg);
1356 if (error)
1357 goto out_free_consistent;
1358
1359 /* save config data */
1360 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1361 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1362 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1363 enclosure->flags = le16_to_cpu(buffer->Flags);
1364 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1365 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1366 enclosure->start_id = buffer->StartTargetID;
1367 enclosure->start_channel = buffer->StartBus;
1368 enclosure->sep_id = buffer->SEPTargetID;
1369 enclosure->sep_channel = buffer->SEPBus;
1370
1371 out_free_consistent:
1372 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1373 buffer, dma_handle);
1374 out:
1375 return error;
1376}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001377
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301378/**
1379 * mptsas_add_end_device - report a new end device to sas transport layer
1380 * @ioc: Pointer to MPT_ADAPTER structure
1381 * @phy_info: decribes attached device
1382 *
1383 * return (0) success (1) failure
1384 *
1385 **/
1386static int
1387mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1388{
1389 struct sas_rphy *rphy;
1390 struct sas_port *port;
1391 struct sas_identify identify;
1392 char *ds = NULL;
1393 u8 fw_id;
1394
1395 if (!phy_info) {
1396 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1397 "%s: exit at line=%d\n", ioc->name,
1398 __func__, __LINE__));
1399 return 1;
1400 }
1401
1402 fw_id = phy_info->attached.id;
1403
1404 if (mptsas_get_rphy(phy_info)) {
1405 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1406 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1407 __func__, fw_id, __LINE__));
1408 return 2;
1409 }
1410
1411 port = mptsas_get_port(phy_info);
1412 if (!port) {
1413 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1414 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1415 __func__, fw_id, __LINE__));
1416 return 3;
1417 }
1418
1419 if (phy_info->attached.device_info &
1420 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1421 ds = "ssp";
1422 if (phy_info->attached.device_info &
1423 MPI_SAS_DEVICE_INFO_STP_TARGET)
1424 ds = "stp";
1425 if (phy_info->attached.device_info &
1426 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1427 ds = "sata";
1428
1429 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1430 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1431 phy_info->attached.channel, phy_info->attached.id,
1432 phy_info->attached.phy_id, (unsigned long long)
1433 phy_info->attached.sas_address);
1434
1435 mptsas_parse_device_info(&identify, &phy_info->attached);
1436 rphy = sas_end_device_alloc(port);
1437 if (!rphy) {
1438 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1439 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1440 __func__, fw_id, __LINE__));
1441 return 5; /* non-fatal: an rphy can be added later */
1442 }
1443
1444 rphy->identify = identify;
1445 if (sas_rphy_add(rphy)) {
1446 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1447 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1448 __func__, fw_id, __LINE__));
1449 sas_rphy_free(rphy);
1450 return 6;
1451 }
1452 mptsas_set_rphy(ioc, phy_info, rphy);
1453 return 0;
1454}
1455
1456/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001457 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301458 * @ioc: Pointer to MPT_ADAPTER structure
1459 * @phy_info: decribes attached device
1460 *
1461 **/
1462static void
1463mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1464{
1465 struct sas_rphy *rphy;
1466 struct sas_port *port;
1467 struct mptsas_portinfo *port_info;
1468 struct mptsas_phyinfo *phy_info_parent;
1469 int i;
1470 char *ds = NULL;
1471 u8 fw_id;
1472 u64 sas_address;
1473
1474 if (!phy_info)
1475 return;
1476
1477 fw_id = phy_info->attached.id;
1478 sas_address = phy_info->attached.sas_address;
1479
1480 if (!phy_info->port_details) {
1481 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1482 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1483 __func__, fw_id, __LINE__));
1484 return;
1485 }
1486 rphy = mptsas_get_rphy(phy_info);
1487 if (!rphy) {
1488 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1489 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1490 __func__, fw_id, __LINE__));
1491 return;
1492 }
1493
1494 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1495 || phy_info->attached.device_info
1496 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1497 || phy_info->attached.device_info
1498 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1499 ds = "initiator";
1500 if (phy_info->attached.device_info &
1501 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1502 ds = "ssp";
1503 if (phy_info->attached.device_info &
1504 MPI_SAS_DEVICE_INFO_STP_TARGET)
1505 ds = "stp";
1506 if (phy_info->attached.device_info &
1507 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1508 ds = "sata";
1509
1510 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1511 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1512 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1513 phy_info->attached.id, phy_info->attached.phy_id,
1514 (unsigned long long) sas_address);
1515
1516 port = mptsas_get_port(phy_info);
1517 if (!port) {
1518 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1519 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1520 __func__, fw_id, __LINE__));
1521 return;
1522 }
1523 port_info = phy_info->portinfo;
1524 phy_info_parent = port_info->phy_info;
1525 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1526 if (!phy_info_parent->phy)
1527 continue;
1528 if (phy_info_parent->attached.sas_address !=
1529 sas_address)
1530 continue;
1531 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1532 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1533 ioc->name, phy_info_parent->phy_id,
1534 phy_info_parent->phy);
1535 sas_port_delete_phy(port, phy_info_parent->phy);
1536 }
1537
1538 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1539 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1540 port->port_identifier, (unsigned long long)sas_address);
1541 sas_port_delete(port);
1542 mptsas_set_port(ioc, phy_info, NULL);
1543 mptsas_port_delete(ioc, phy_info->port_details);
1544}
1545
1546struct mptsas_phyinfo *
1547mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1548 struct mptsas_devinfo *sas_device)
1549{
1550 struct mptsas_phyinfo *phy_info;
1551 struct mptsas_portinfo *port_info;
1552 int i;
1553
1554 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1555 sas_device->sas_address);
1556 if (!phy_info)
1557 goto out;
1558 port_info = phy_info->portinfo;
1559 if (!port_info)
1560 goto out;
1561 mutex_lock(&ioc->sas_topology_mutex);
1562 for (i = 0; i < port_info->num_phys; i++) {
1563 if (port_info->phy_info[i].attached.sas_address !=
1564 sas_device->sas_address)
1565 continue;
1566 port_info->phy_info[i].attached.channel = sas_device->channel;
1567 port_info->phy_info[i].attached.id = sas_device->id;
1568 port_info->phy_info[i].attached.sas_address =
1569 sas_device->sas_address;
1570 port_info->phy_info[i].attached.handle = sas_device->handle;
1571 port_info->phy_info[i].attached.handle_parent =
1572 sas_device->handle_parent;
1573 port_info->phy_info[i].attached.handle_enclosure =
1574 sas_device->handle_enclosure;
1575 }
1576 mutex_unlock(&ioc->sas_topology_mutex);
1577 out:
1578 return phy_info;
1579}
1580
1581/**
1582 * mptsas_firmware_event_work - work thread for processing fw events
1583 * @work: work queue payload containing info describing the event
1584 * Context: user
1585 *
1586 */
1587static void
1588mptsas_firmware_event_work(struct work_struct *work)
1589{
1590 struct fw_event_work *fw_event =
1591 container_of(work, struct fw_event_work, work.work);
1592 MPT_ADAPTER *ioc = fw_event->ioc;
1593
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301594 /* special rescan topology handling */
1595 if (fw_event->event == -1) {
1596 if (ioc->in_rescan) {
1597 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1598 "%s: rescan ignored as it is in progress\n",
1599 ioc->name, __func__));
1600 return;
1601 }
1602 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1603 "reset\n", ioc->name, __func__));
1604 ioc->in_rescan = 1;
1605 mptsas_not_responding_devices(ioc);
1606 mptsas_scan_sas_topology(ioc);
1607 ioc->in_rescan = 0;
1608 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301609 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301610 return;
1611 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301612
1613 /* events handling turned off during host reset */
1614 if (ioc->fw_events_off) {
1615 mptsas_free_fw_event(ioc, fw_event);
1616 return;
1617 }
1618
1619 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1620 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1621 (fw_event->event & 0xFF)));
1622
1623 switch (fw_event->event) {
1624 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1625 mptsas_send_sas_event(fw_event);
1626 break;
1627 case MPI_EVENT_INTEGRATED_RAID:
1628 mptsas_send_raid_event(fw_event);
1629 break;
1630 case MPI_EVENT_IR2:
1631 mptsas_send_ir2_event(fw_event);
1632 break;
1633 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1634 mptbase_sas_persist_operation(ioc,
1635 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1636 mptsas_free_fw_event(ioc, fw_event);
1637 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301638 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1639 mptsas_broadcast_primative_work(fw_event);
1640 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301641 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1642 mptsas_send_expander_event(fw_event);
1643 break;
1644 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1645 mptsas_send_link_status_event(fw_event);
1646 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301647 case MPI_EVENT_QUEUE_FULL:
1648 mptsas_handle_queue_full_event(fw_event);
1649 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301650 }
1651}
1652
1653
1654
James Bottomleyf013db32006-03-18 14:54:36 -06001655static int
1656mptsas_slave_configure(struct scsi_device *sdev)
1657{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301658 struct Scsi_Host *host = sdev->host;
1659 MPT_SCSI_HOST *hd = shost_priv(host);
1660 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301661 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001662
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301663 if (vdevice->vtarget->deleted) {
1664 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1665 vdevice->vtarget->deleted = 0;
1666 }
1667
1668 /*
1669 * RAID volumes placed beyond the last expected port.
1670 * Ignore sending sas mode pages in that case..
1671 */
1672 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1673 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001674 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301675 }
James Bottomleyf013db32006-03-18 14:54:36 -06001676
James Bottomleye8bf3942006-07-11 17:49:34 -04001677 sas_read_port_mode_page(sdev);
1678
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301679 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1680
James Bottomleye8bf3942006-07-11 17:49:34 -04001681 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001682 return mptscsih_slave_configure(sdev);
1683}
1684
Eric Moore547f9a22006-06-27 14:42:12 -06001685static int
1686mptsas_target_alloc(struct scsi_target *starget)
1687{
1688 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001689 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001690 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001691 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001692 struct sas_rphy *rphy;
1693 struct mptsas_portinfo *p;
1694 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001695 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001696
1697 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1698 if (!vtarget)
1699 return -ENOMEM;
1700
1701 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001702 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001703 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1704 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001705 channel = 0;
1706
Eric Moore793955f2007-01-29 09:42:20 -07001707 /*
1708 * RAID volumes placed beyond the last expected port.
1709 */
1710 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301711 if (!ioc->raid_data.pIocPg2) {
1712 kfree(vtarget);
1713 return -ENXIO;
1714 }
1715 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1716 if (id == ioc->raid_data.pIocPg2->
1717 RaidVolume[i].VolumeID) {
1718 channel = ioc->raid_data.pIocPg2->
1719 RaidVolume[i].VolumeBus;
1720 }
1721 }
1722 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001723 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001724 }
Eric Moore547f9a22006-06-27 14:42:12 -06001725
1726 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001727 mutex_lock(&ioc->sas_topology_mutex);
1728 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001729 for (i = 0; i < p->num_phys; i++) {
1730 if (p->phy_info[i].attached.sas_address !=
1731 rphy->identify.sas_address)
1732 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001733 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001734 channel = p->phy_info[i].attached.channel;
1735 mptsas_set_starget(&p->phy_info[i], starget);
1736
1737 /*
1738 * Exposing hidden raid components
1739 */
Eric Mooree80b0022007-09-14 18:49:03 -06001740 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1741 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001742 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001743 vtarget->tflags |=
1744 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001745 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001746 }
Eric Mooree80b0022007-09-14 18:49:03 -06001747 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001748 goto out;
1749 }
1750 }
Eric Mooree80b0022007-09-14 18:49:03 -06001751 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001752
1753 kfree(vtarget);
1754 return -ENXIO;
1755
1756 out:
Eric Moore793955f2007-01-29 09:42:20 -07001757 vtarget->id = id;
1758 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001759 starget->hostdata = vtarget;
1760 return 0;
1761}
1762
1763static void
1764mptsas_target_destroy(struct scsi_target *starget)
1765{
1766 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001767 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001768 struct sas_rphy *rphy;
1769 struct mptsas_portinfo *p;
1770 int i;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301771 MPT_ADAPTER *ioc = hd->ioc;
1772 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001773
1774 if (!starget->hostdata)
1775 return;
1776
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301777 vtarget = starget->hostdata;
1778
Kashyap, Desai57e98512009-05-29 16:55:09 +05301779 mptsas_del_device_component_by_os(ioc, starget->channel,
1780 starget->id);
1781
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301782
James Bottomleye8bf3942006-07-11 17:49:34 -04001783 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001784 goto out;
1785
1786 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001787 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001788 for (i = 0; i < p->num_phys; i++) {
1789 if (p->phy_info[i].attached.sas_address !=
1790 rphy->identify.sas_address)
1791 continue;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301792
1793 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1794 "delete device: fw_channel %d, fw_id %d, phy %d, "
1795 "sas_addr 0x%llx\n", ioc->name,
1796 p->phy_info[i].attached.channel,
1797 p->phy_info[i].attached.id,
1798 p->phy_info[i].attached.phy_id, (unsigned long long)
1799 p->phy_info[i].attached.sas_address);
1800
Eric Moore547f9a22006-06-27 14:42:12 -06001801 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001802 }
1803 }
1804
1805 out:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301806 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001807 kfree(starget->hostdata);
1808 starget->hostdata = NULL;
1809}
1810
1811
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001812static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001813mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001814{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001815 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001816 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001817 struct sas_rphy *rphy;
1818 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001819 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001820 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001821 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001822 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001823
Eric Moorea69de502007-09-14 18:48:19 -06001824 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1825 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001826 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001827 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001828 return -ENOMEM;
1829 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001830 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001831 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001832
James Bottomleye8bf3942006-07-11 17:49:34 -04001833 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001834 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001835
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001836 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001837 mutex_lock(&ioc->sas_topology_mutex);
1838 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001839 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001840 if (p->phy_info[i].attached.sas_address !=
1841 rphy->identify.sas_address)
1842 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001843 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001844 /*
1845 * Exposing hidden raid components
1846 */
Eric Mooree80b0022007-09-14 18:49:03 -06001847 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001848 p->phy_info[i].attached.channel,
1849 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001850 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001851 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001852 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001853 }
1854 }
Eric Mooree80b0022007-09-14 18:49:03 -06001855 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001856
Eric Moorea69de502007-09-14 18:48:19 -06001857 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001858 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001859
1860 out:
Eric Moorea69de502007-09-14 18:48:19 -06001861 vdevice->vtarget->num_luns++;
1862 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001863 return 0;
1864}
1865
Eric Moore547f9a22006-06-27 14:42:12 -06001866static int
1867mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001868{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301869 MPT_SCSI_HOST *hd;
1870 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001871 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001872
Eric Moorea69de502007-09-14 18:48:19 -06001873 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001874 SCpnt->result = DID_NO_CONNECT << 16;
1875 done(SCpnt);
1876 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001877 }
Eric Moore547f9a22006-06-27 14:42:12 -06001878
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301879 hd = shost_priv(SCpnt->device->host);
1880 ioc = hd->ioc;
1881
1882 if (ioc->sas_discovery_quiesce_io)
1883 return SCSI_MLQUEUE_HOST_BUSY;
1884
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301885 if (ioc->debug_level & MPT_DEBUG_SCSI)
1886 scsi_print_command(SCpnt);
Eric Moore793955f2007-01-29 09:42:20 -07001887
Eric Moore547f9a22006-06-27 14:42:12 -06001888 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001889}
1890
Eric Moore547f9a22006-06-27 14:42:12 -06001891
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001892static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001893 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001894 .proc_name = "mptsas",
1895 .proc_info = mptscsih_proc_info,
1896 .name = "MPT SPI Host",
1897 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001898 .queuecommand = mptsas_qcmd,
1899 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001900 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001901 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001902 .target_destroy = mptsas_target_destroy,
1903 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001904 .change_queue_depth = mptscsih_change_queue_depth,
1905 .eh_abort_handler = mptscsih_abort,
1906 .eh_device_reset_handler = mptscsih_dev_reset,
1907 .eh_bus_reset_handler = mptscsih_bus_reset,
1908 .eh_host_reset_handler = mptscsih_host_reset,
1909 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301910 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001911 .this_id = -1,
1912 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1913 .max_sectors = 8192,
1914 .cmd_per_lun = 7,
1915 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301916 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001917};
1918
Christoph Hellwigb5141122005-10-28 22:07:41 +02001919static int mptsas_get_linkerrors(struct sas_phy *phy)
1920{
1921 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1922 ConfigExtendedPageHeader_t hdr;
1923 CONFIGPARMS cfg;
1924 SasPhyPage1_t *buffer;
1925 dma_addr_t dma_handle;
1926 int error;
1927
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001928 /* FIXME: only have link errors on local phys */
1929 if (!scsi_is_sas_phy_local(phy))
1930 return -EINVAL;
1931
Christoph Hellwigb5141122005-10-28 22:07:41 +02001932 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1933 hdr.ExtPageLength = 0;
1934 hdr.PageNumber = 1 /* page number 1*/;
1935 hdr.Reserved1 = 0;
1936 hdr.Reserved2 = 0;
1937 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1938 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1939
1940 cfg.cfghdr.ehdr = &hdr;
1941 cfg.physAddr = -1;
1942 cfg.pageAddr = phy->identify.phy_identifier;
1943 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1944 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301945 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02001946
1947 error = mpt_config(ioc, &cfg);
1948 if (error)
1949 return error;
1950 if (!hdr.ExtPageLength)
1951 return -ENXIO;
1952
1953 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1954 &dma_handle);
1955 if (!buffer)
1956 return -ENOMEM;
1957
1958 cfg.physAddr = dma_handle;
1959 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1960
1961 error = mpt_config(ioc, &cfg);
1962 if (error)
1963 goto out_free_consistent;
1964
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301965 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001966
1967 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1968 phy->running_disparity_error_count =
1969 le32_to_cpu(buffer->RunningDisparityErrorCount);
1970 phy->loss_of_dword_sync_count =
1971 le32_to_cpu(buffer->LossDwordSynchCount);
1972 phy->phy_reset_problem_count =
1973 le32_to_cpu(buffer->PhyResetProblemCount);
1974
1975 out_free_consistent:
1976 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1977 buffer, dma_handle);
1978 return error;
1979}
1980
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001981static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1982 MPT_FRAME_HDR *reply)
1983{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301984 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001985 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301986 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001987 memcpy(ioc->sas_mgmt.reply, reply,
1988 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1989 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301990
1991 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1992 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1993 complete(&ioc->sas_mgmt.done);
1994 return 1;
1995 }
1996 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001997}
1998
1999static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2000{
2001 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2002 SasIoUnitControlRequest_t *req;
2003 SasIoUnitControlReply_t *reply;
2004 MPT_FRAME_HDR *mf;
2005 MPIHeader_t *hdr;
2006 unsigned long timeleft;
2007 int error = -ERESTARTSYS;
2008
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002009 /* FIXME: fusion doesn't allow non-local phy reset */
2010 if (!scsi_is_sas_phy_local(phy))
2011 return -EINVAL;
2012
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002013 /* not implemented for expanders */
2014 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2015 return -ENXIO;
2016
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002017 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002018 goto out;
2019
2020 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2021 if (!mf) {
2022 error = -ENOMEM;
2023 goto out_unlock;
2024 }
2025
2026 hdr = (MPIHeader_t *) mf;
2027 req = (SasIoUnitControlRequest_t *)mf;
2028 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2029 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2030 req->MsgContext = hdr->MsgContext;
2031 req->Operation = hard_reset ?
2032 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2033 req->PhyNum = phy->identify.phy_identifier;
2034
Kashyap, Desai2f187862009-05-29 16:52:37 +05302035 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002036 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2037
2038 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2039 10 * HZ);
2040 if (!timeleft) {
2041 /* On timeout reset the board */
2042 mpt_free_msg_frame(ioc, mf);
2043 mpt_HardResetHandler(ioc, CAN_SLEEP);
2044 error = -ETIMEDOUT;
2045 goto out_unlock;
2046 }
2047
2048 /* a reply frame is expected */
2049 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302050 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002051 error = -ENXIO;
2052 goto out_unlock;
2053 }
2054
2055 /* process the completed Reply Message Frame */
2056 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2057 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002058 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002059 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002060 error = -ENXIO;
2061 goto out_unlock;
2062 }
2063
2064 error = 0;
2065
2066 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302067 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002068 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002069 out:
2070 return error;
2071}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002072
Christoph Hellwige3094442006-02-16 13:25:36 +01002073static int
2074mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2075{
2076 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2077 int i, error;
2078 struct mptsas_portinfo *p;
2079 struct mptsas_enclosure enclosure_info;
2080 u64 enclosure_handle;
2081
2082 mutex_lock(&ioc->sas_topology_mutex);
2083 list_for_each_entry(p, &ioc->sas_topology, list) {
2084 for (i = 0; i < p->num_phys; i++) {
2085 if (p->phy_info[i].attached.sas_address ==
2086 rphy->identify.sas_address) {
2087 enclosure_handle = p->phy_info[i].
2088 attached.handle_enclosure;
2089 goto found_info;
2090 }
2091 }
2092 }
2093 mutex_unlock(&ioc->sas_topology_mutex);
2094 return -ENXIO;
2095
2096 found_info:
2097 mutex_unlock(&ioc->sas_topology_mutex);
2098 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002099 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002100 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2101 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2102 if (!error)
2103 *identifier = enclosure_info.enclosure_logical_id;
2104 return error;
2105}
2106
2107static int
2108mptsas_get_bay_identifier(struct sas_rphy *rphy)
2109{
2110 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2111 struct mptsas_portinfo *p;
2112 int i, rc;
2113
2114 mutex_lock(&ioc->sas_topology_mutex);
2115 list_for_each_entry(p, &ioc->sas_topology, list) {
2116 for (i = 0; i < p->num_phys; i++) {
2117 if (p->phy_info[i].attached.sas_address ==
2118 rphy->identify.sas_address) {
2119 rc = p->phy_info[i].attached.slot;
2120 goto out;
2121 }
2122 }
2123 }
2124 rc = -ENXIO;
2125 out:
2126 mutex_unlock(&ioc->sas_topology_mutex);
2127 return rc;
2128}
2129
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002130static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2131 struct request *req)
2132{
2133 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2134 MPT_FRAME_HDR *mf;
2135 SmpPassthroughRequest_t *smpreq;
2136 struct request *rsp = req->next_rq;
2137 int ret;
2138 int flagsLength;
2139 unsigned long timeleft;
2140 char *psge;
2141 dma_addr_t dma_addr_in = 0;
2142 dma_addr_t dma_addr_out = 0;
2143 u64 sas_address = 0;
2144
2145 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002146 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002147 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002148 return -EINVAL;
2149 }
2150
2151 /* do we need to support multiple segments? */
2152 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002153 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002154 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2155 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002156 return -EINVAL;
2157 }
2158
2159 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2160 if (ret)
2161 goto out;
2162
2163 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2164 if (!mf) {
2165 ret = -ENOMEM;
2166 goto out_unlock;
2167 }
2168
2169 smpreq = (SmpPassthroughRequest_t *)mf;
2170 memset(smpreq, 0, sizeof(*smpreq));
2171
Tejun Heob0790412009-05-07 22:24:42 +09002172 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002173 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2174
2175 if (rphy)
2176 sas_address = rphy->identify.sas_address;
2177 else {
2178 struct mptsas_portinfo *port_info;
2179
2180 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302181 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002182 if (port_info && port_info->phy_info)
2183 sas_address =
2184 port_info->phy_info[0].phy->identify.sas_address;
2185 mutex_unlock(&ioc->sas_topology_mutex);
2186 }
2187
2188 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2189
2190 psge = (char *)
2191 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2192
2193 /* request */
2194 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2195 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302196 MPI_SGE_FLAGS_DIRECTION)
2197 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002198 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002199
2200 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002201 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002202 if (!dma_addr_out)
2203 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302204 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302205 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002206
2207 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302208 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2209 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2210 MPI_SGE_FLAGS_IOC_TO_HOST |
2211 MPI_SGE_FLAGS_END_OF_BUFFER;
2212
2213 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002214 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002215 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002216 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002217 if (!dma_addr_in)
2218 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302219 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002220
Kashyap, Desai2f187862009-05-29 16:52:37 +05302221 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002222 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2223
2224 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2225 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002226 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002227 /* On timeout reset the board */
2228 mpt_HardResetHandler(ioc, CAN_SLEEP);
2229 ret = -ETIMEDOUT;
2230 goto unmap;
2231 }
2232 mf = NULL;
2233
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302234 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002235 SmpPassthroughReply_t *smprep;
2236
2237 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2238 memcpy(req->sense, smprep, sizeof(*smprep));
2239 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002240 req->resid_len = 0;
2241 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002242 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302243 printk(MYIOC_s_ERR_FMT
2244 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002245 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002246 ret = -ENXIO;
2247 }
2248unmap:
2249 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002250 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002251 PCI_DMA_BIDIRECTIONAL);
2252 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002253 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002254 PCI_DMA_BIDIRECTIONAL);
2255put_mf:
2256 if (mf)
2257 mpt_free_msg_frame(ioc, mf);
2258out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302259 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002260 mutex_unlock(&ioc->sas_mgmt.mutex);
2261out:
2262 return ret;
2263}
2264
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002265static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002266 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002267 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2268 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002269 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002270 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002271};
2272
2273static struct scsi_transport_template *mptsas_transport_template;
2274
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002275static int
2276mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2277{
2278 ConfigExtendedPageHeader_t hdr;
2279 CONFIGPARMS cfg;
2280 SasIOUnitPage0_t *buffer;
2281 dma_addr_t dma_handle;
2282 int error, i;
2283
2284 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2285 hdr.ExtPageLength = 0;
2286 hdr.PageNumber = 0;
2287 hdr.Reserved1 = 0;
2288 hdr.Reserved2 = 0;
2289 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2290 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2291
2292 cfg.cfghdr.ehdr = &hdr;
2293 cfg.physAddr = -1;
2294 cfg.pageAddr = 0;
2295 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2296 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302297 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002298
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 port_info->num_phys = buffer->NumPhys;
2322 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302323 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002324 if (!port_info->phy_info) {
2325 error = -ENOMEM;
2326 goto out_free_consistent;
2327 }
2328
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302329 ioc->nvdata_version_persistent =
2330 le16_to_cpu(buffer->NvdataVersionPersistent);
2331 ioc->nvdata_version_default =
2332 le16_to_cpu(buffer->NvdataVersionDefault);
2333
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002334 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302335 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002336 port_info->phy_info[i].phy_id = i;
2337 port_info->phy_info[i].port_id =
2338 buffer->PhyData[i].Port;
2339 port_info->phy_info[i].negotiated_link_rate =
2340 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002341 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002342 port_info->phy_info[i].handle =
2343 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002344 }
2345
2346 out_free_consistent:
2347 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2348 buffer, dma_handle);
2349 out:
2350 return error;
2351}
2352
2353static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302354mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2355{
2356 ConfigExtendedPageHeader_t hdr;
2357 CONFIGPARMS cfg;
2358 SasIOUnitPage1_t *buffer;
2359 dma_addr_t dma_handle;
2360 int error;
2361 u16 device_missing_delay;
2362
2363 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2364 memset(&cfg, 0, sizeof(CONFIGPARMS));
2365
2366 cfg.cfghdr.ehdr = &hdr;
2367 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302368 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302369 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2370 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2371 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2372 cfg.cfghdr.ehdr->PageNumber = 1;
2373
2374 error = mpt_config(ioc, &cfg);
2375 if (error)
2376 goto out;
2377 if (!hdr.ExtPageLength) {
2378 error = -ENXIO;
2379 goto out;
2380 }
2381
2382 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2383 &dma_handle);
2384 if (!buffer) {
2385 error = -ENOMEM;
2386 goto out;
2387 }
2388
2389 cfg.physAddr = dma_handle;
2390 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2391
2392 error = mpt_config(ioc, &cfg);
2393 if (error)
2394 goto out_free_consistent;
2395
2396 ioc->io_missing_delay =
2397 le16_to_cpu(buffer->IODeviceMissingDelay);
2398 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2399 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2400 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2401 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2402
2403 out_free_consistent:
2404 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2405 buffer, dma_handle);
2406 out:
2407 return error;
2408}
2409
2410static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002411mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2412 u32 form, u32 form_specific)
2413{
2414 ConfigExtendedPageHeader_t hdr;
2415 CONFIGPARMS cfg;
2416 SasPhyPage0_t *buffer;
2417 dma_addr_t dma_handle;
2418 int error;
2419
2420 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2421 hdr.ExtPageLength = 0;
2422 hdr.PageNumber = 0;
2423 hdr.Reserved1 = 0;
2424 hdr.Reserved2 = 0;
2425 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2426 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2427
2428 cfg.cfghdr.ehdr = &hdr;
2429 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302430 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002431
2432 /* Get Phy Pg 0 for each Phy. */
2433 cfg.physAddr = -1;
2434 cfg.pageAddr = form + form_specific;
2435 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2436
2437 error = mpt_config(ioc, &cfg);
2438 if (error)
2439 goto out;
2440
2441 if (!hdr.ExtPageLength) {
2442 error = -ENXIO;
2443 goto out;
2444 }
2445
2446 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2447 &dma_handle);
2448 if (!buffer) {
2449 error = -ENOMEM;
2450 goto out;
2451 }
2452
2453 cfg.physAddr = dma_handle;
2454 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2455
2456 error = mpt_config(ioc, &cfg);
2457 if (error)
2458 goto out_free_consistent;
2459
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302460 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002461
2462 phy_info->hw_link_rate = buffer->HwLinkRate;
2463 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2464 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2465 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2466
2467 out_free_consistent:
2468 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2469 buffer, dma_handle);
2470 out:
2471 return error;
2472}
2473
2474static int
2475mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2476 u32 form, u32 form_specific)
2477{
2478 ConfigExtendedPageHeader_t hdr;
2479 CONFIGPARMS cfg;
2480 SasDevicePage0_t *buffer;
2481 dma_addr_t dma_handle;
2482 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002483 int error=0;
2484
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002485 hdr.PageVersion = MPI_SASDEVICE0_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_DEVICE;
2492
2493 cfg.cfghdr.ehdr = &hdr;
2494 cfg.pageAddr = form + form_specific;
2495 cfg.physAddr = -1;
2496 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2497 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302498 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002499
Moore, Ericdb9c9172006-03-14 09:14:18 -07002500 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002501 error = mpt_config(ioc, &cfg);
2502 if (error)
2503 goto out;
2504 if (!hdr.ExtPageLength) {
2505 error = -ENXIO;
2506 goto out;
2507 }
2508
2509 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2510 &dma_handle);
2511 if (!buffer) {
2512 error = -ENOMEM;
2513 goto out;
2514 }
2515
2516 cfg.physAddr = dma_handle;
2517 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2518
2519 error = mpt_config(ioc, &cfg);
2520 if (error)
2521 goto out_free_consistent;
2522
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302523 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002524
Kashyap, Desai2f187862009-05-29 16:52:37 +05302525 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002526 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787e2006-01-26 16:20:06 -07002527 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002528 device_info->handle_enclosure =
2529 le16_to_cpu(buffer->EnclosureHandle);
2530 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002531 device_info->phy_id = buffer->PhyNum;
2532 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002533 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002534 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002535 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002536 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2537 device_info->sas_address = le64_to_cpu(sas_address);
2538 device_info->device_info =
2539 le32_to_cpu(buffer->DeviceInfo);
2540
2541 out_free_consistent:
2542 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2543 buffer, dma_handle);
2544 out:
2545 return error;
2546}
2547
2548static int
2549mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2550 u32 form, u32 form_specific)
2551{
2552 ConfigExtendedPageHeader_t hdr;
2553 CONFIGPARMS cfg;
2554 SasExpanderPage0_t *buffer;
2555 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002556 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302557 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002558
Kashyap, Desai2f187862009-05-29 16:52:37 +05302559 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002560 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2561 hdr.ExtPageLength = 0;
2562 hdr.PageNumber = 0;
2563 hdr.Reserved1 = 0;
2564 hdr.Reserved2 = 0;
2565 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2566 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2567
2568 cfg.cfghdr.ehdr = &hdr;
2569 cfg.physAddr = -1;
2570 cfg.pageAddr = form + form_specific;
2571 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2572 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302573 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002574
Moore, Ericdb9c9172006-03-14 09:14:18 -07002575 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002576 error = mpt_config(ioc, &cfg);
2577 if (error)
2578 goto out;
2579
2580 if (!hdr.ExtPageLength) {
2581 error = -ENXIO;
2582 goto out;
2583 }
2584
2585 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2586 &dma_handle);
2587 if (!buffer) {
2588 error = -ENOMEM;
2589 goto out;
2590 }
2591
2592 cfg.physAddr = dma_handle;
2593 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2594
2595 error = mpt_config(ioc, &cfg);
2596 if (error)
2597 goto out_free_consistent;
2598
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002599 if (!buffer->NumPhys) {
2600 error = -ENODEV;
2601 goto out_free_consistent;
2602 }
2603
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002604 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302605 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002606 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302607 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002608 if (!port_info->phy_info) {
2609 error = -ENOMEM;
2610 goto out_free_consistent;
2611 }
2612
Kashyap, Desai2f187862009-05-29 16:52:37 +05302613 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002614 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002615 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002616 port_info->phy_info[i].handle =
2617 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302618 port_info->phy_info[i].identify.sas_address =
2619 le64_to_cpu(sas_address);
2620 port_info->phy_info[i].identify.handle_parent =
2621 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002622 }
Eric Moore547f9a22006-06-27 14:42:12 -06002623
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002624 out_free_consistent:
2625 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2626 buffer, dma_handle);
2627 out:
2628 return error;
2629}
2630
2631static int
2632mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2633 u32 form, u32 form_specific)
2634{
2635 ConfigExtendedPageHeader_t hdr;
2636 CONFIGPARMS cfg;
2637 SasExpanderPage1_t *buffer;
2638 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002639 int error=0;
2640
Kashyap, Desai2f187862009-05-29 16:52:37 +05302641 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002642 hdr.ExtPageLength = 0;
2643 hdr.PageNumber = 1;
2644 hdr.Reserved1 = 0;
2645 hdr.Reserved2 = 0;
2646 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2647 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2648
2649 cfg.cfghdr.ehdr = &hdr;
2650 cfg.physAddr = -1;
2651 cfg.pageAddr = form + form_specific;
2652 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2653 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302654 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002655
2656 error = mpt_config(ioc, &cfg);
2657 if (error)
2658 goto out;
2659
2660 if (!hdr.ExtPageLength) {
2661 error = -ENXIO;
2662 goto out;
2663 }
2664
2665 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2666 &dma_handle);
2667 if (!buffer) {
2668 error = -ENOMEM;
2669 goto out;
2670 }
2671
2672 cfg.physAddr = dma_handle;
2673 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2674
2675 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302676
2677 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2678 error = -ENODEV;
2679 goto out;
2680 }
2681
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002682 if (error)
2683 goto out_free_consistent;
2684
2685
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302686 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002687
2688 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002689 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002690 phy_info->port_id = buffer->PhysicalPort;
2691 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2692 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2693 phy_info->hw_link_rate = buffer->HwLinkRate;
2694 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2695 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2696
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002697 out_free_consistent:
2698 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2699 buffer, dma_handle);
2700 out:
2701 return error;
2702}
2703
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302704struct rep_manu_request{
2705 u8 smp_frame_type;
2706 u8 function;
2707 u8 reserved;
2708 u8 request_length;
2709};
2710
2711struct rep_manu_reply{
2712 u8 smp_frame_type; /* 0x41 */
2713 u8 function; /* 0x01 */
2714 u8 function_result;
2715 u8 response_length;
2716 u16 expander_change_count;
2717 u8 reserved0[2];
2718 u8 sas_format:1;
2719 u8 reserved1:7;
2720 u8 reserved2[3];
2721 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2722 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2723 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2724 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2725 u16 component_id;
2726 u8 component_revision_id;
2727 u8 reserved3;
2728 u8 vendor_specific[8];
2729};
2730
2731/**
2732 * mptsas_exp_repmanufacture_info -
2733 * @ioc: per adapter object
2734 * @sas_address: expander sas address
2735 * @edev: the sas_expander_device object
2736 *
2737 * Fills in the sas_expander_device object when SMP port is created.
2738 *
2739 * Returns 0 for success, non-zero for failure.
2740 */
2741static int
2742mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2743 u64 sas_address, struct sas_expander_device *edev)
2744{
2745 MPT_FRAME_HDR *mf;
2746 SmpPassthroughRequest_t *smpreq;
2747 SmpPassthroughReply_t *smprep;
2748 struct rep_manu_reply *manufacture_reply;
2749 struct rep_manu_request *manufacture_request;
2750 int ret;
2751 int flagsLength;
2752 unsigned long timeleft;
2753 char *psge;
2754 unsigned long flags;
2755 void *data_out = NULL;
2756 dma_addr_t data_out_dma = 0;
2757 u32 sz;
2758
2759 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2760 if (ioc->ioc_reset_in_progress) {
2761 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2762 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2763 __func__, ioc->name);
2764 return -EFAULT;
2765 }
2766 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2767
2768 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2769 if (ret)
2770 goto out;
2771
2772 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2773 if (!mf) {
2774 ret = -ENOMEM;
2775 goto out_unlock;
2776 }
2777
2778 smpreq = (SmpPassthroughRequest_t *)mf;
2779 memset(smpreq, 0, sizeof(*smpreq));
2780
2781 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2782
2783 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2784 if (!data_out) {
2785 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2786 __FILE__, __LINE__, __func__);
2787 ret = -ENOMEM;
2788 goto put_mf;
2789 }
2790
2791 manufacture_request = data_out;
2792 manufacture_request->smp_frame_type = 0x40;
2793 manufacture_request->function = 1;
2794 manufacture_request->reserved = 0;
2795 manufacture_request->request_length = 0;
2796
2797 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2798 smpreq->PhysicalPort = 0xFF;
2799 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2800 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2801
2802 psge = (char *)
2803 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2804
2805 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2806 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2807 MPI_SGE_FLAGS_HOST_TO_IOC |
2808 MPI_SGE_FLAGS_END_OF_BUFFER;
2809 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2810 flagsLength |= sizeof(struct rep_manu_request);
2811
2812 ioc->add_sge(psge, flagsLength, data_out_dma);
2813 psge += ioc->SGE_size;
2814
2815 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2816 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2817 MPI_SGE_FLAGS_IOC_TO_HOST |
2818 MPI_SGE_FLAGS_END_OF_BUFFER;
2819 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2820 flagsLength |= sizeof(struct rep_manu_reply);
2821 ioc->add_sge(psge, flagsLength, data_out_dma +
2822 sizeof(struct rep_manu_request));
2823
2824 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2825 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2826
2827 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2828 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2829 ret = -ETIME;
2830 mpt_free_msg_frame(ioc, mf);
2831 mf = NULL;
2832 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2833 goto out_free;
2834 if (!timeleft)
2835 mpt_HardResetHandler(ioc, CAN_SLEEP);
2836 goto out_free;
2837 }
2838
2839 mf = NULL;
2840
2841 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2842 u8 *tmp;
2843
2844 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2845 if (le16_to_cpu(smprep->ResponseDataLength) !=
2846 sizeof(struct rep_manu_reply))
2847 goto out_free;
2848
2849 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2850 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2851 SAS_EXPANDER_VENDOR_ID_LEN);
2852 strncpy(edev->product_id, manufacture_reply->product_id,
2853 SAS_EXPANDER_PRODUCT_ID_LEN);
2854 strncpy(edev->product_rev, manufacture_reply->product_rev,
2855 SAS_EXPANDER_PRODUCT_REV_LEN);
2856 edev->level = manufacture_reply->sas_format;
2857 if (manufacture_reply->sas_format) {
2858 strncpy(edev->component_vendor_id,
2859 manufacture_reply->component_vendor_id,
2860 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2861 tmp = (u8 *)&manufacture_reply->component_id;
2862 edev->component_id = tmp[0] << 8 | tmp[1];
2863 edev->component_revision_id =
2864 manufacture_reply->component_revision_id;
2865 }
2866 } else {
2867 printk(MYIOC_s_ERR_FMT
2868 "%s: smp passthru reply failed to be returned\n",
2869 ioc->name, __func__);
2870 ret = -ENXIO;
2871 }
2872out_free:
2873 if (data_out_dma)
2874 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2875put_mf:
2876 if (mf)
2877 mpt_free_msg_frame(ioc, mf);
2878out_unlock:
2879 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2880 mutex_unlock(&ioc->sas_mgmt.mutex);
2881out:
2882 return ret;
2883 }
2884
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002885static void
2886mptsas_parse_device_info(struct sas_identify *identify,
2887 struct mptsas_devinfo *device_info)
2888{
2889 u16 protocols;
2890
2891 identify->sas_address = device_info->sas_address;
2892 identify->phy_identifier = device_info->phy_id;
2893
2894 /*
2895 * Fill in Phy Initiator Port Protocol.
2896 * Bits 6:3, more than one bit can be set, fall through cases.
2897 */
2898 protocols = device_info->device_info & 0x78;
2899 identify->initiator_port_protocols = 0;
2900 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2901 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2902 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2903 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2904 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2905 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2906 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2907 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2908
2909 /*
2910 * Fill in Phy Target Port Protocol.
2911 * Bits 10:7, more than one bit can be set, fall through cases.
2912 */
2913 protocols = device_info->device_info & 0x780;
2914 identify->target_port_protocols = 0;
2915 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2916 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2917 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2918 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2919 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2920 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2921 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2922 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2923
2924 /*
2925 * Fill in Attached device type.
2926 */
2927 switch (device_info->device_info &
2928 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2929 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2930 identify->device_type = SAS_PHY_UNUSED;
2931 break;
2932 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2933 identify->device_type = SAS_END_DEVICE;
2934 break;
2935 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2936 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2937 break;
2938 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2939 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2940 break;
2941 }
2942}
2943
2944static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002945 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002946{
Moore, Erice6b2d762006-03-14 09:14:24 -07002947 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002948 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002949 struct sas_port *port;
2950 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002951
Eric Moore547f9a22006-06-27 14:42:12 -06002952 if (!dev) {
2953 error = -ENODEV;
2954 goto out;
2955 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002956
2957 if (!phy_info->phy) {
2958 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002959 if (!phy) {
2960 error = -ENOMEM;
2961 goto out;
2962 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002963 } else
2964 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002965
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002966 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002967
2968 /*
2969 * Set Negotiated link rate.
2970 */
2971 switch (phy_info->negotiated_link_rate) {
2972 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002973 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002974 break;
2975 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002976 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002977 break;
2978 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002979 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002980 break;
2981 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002982 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002983 break;
2984 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2985 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2986 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002987 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002988 break;
2989 }
2990
2991 /*
2992 * Set Max hardware link rate.
2993 */
2994 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2995 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002996 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002997 break;
2998 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002999 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003000 break;
3001 default:
3002 break;
3003 }
3004
3005 /*
3006 * Set Max programmed link rate.
3007 */
3008 switch (phy_info->programmed_link_rate &
3009 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3010 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003011 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003012 break;
3013 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003014 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003015 break;
3016 default:
3017 break;
3018 }
3019
3020 /*
3021 * Set Min hardware link rate.
3022 */
3023 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3024 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003025 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003026 break;
3027 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003028 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003029 break;
3030 default:
3031 break;
3032 }
3033
3034 /*
3035 * Set Min programmed link rate.
3036 */
3037 switch (phy_info->programmed_link_rate &
3038 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3039 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003040 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003041 break;
3042 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003043 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003044 break;
3045 default:
3046 break;
3047 }
3048
Moore, Erice6b2d762006-03-14 09:14:24 -07003049 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003050
Moore, Erice6b2d762006-03-14 09:14:24 -07003051 error = sas_phy_add(phy);
3052 if (error) {
3053 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003054 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003055 }
3056 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003057 }
3058
Eric Moore547f9a22006-06-27 14:42:12 -06003059 if (!phy_info->attached.handle ||
3060 !phy_info->port_details)
3061 goto out;
3062
3063 port = mptsas_get_port(phy_info);
3064 ioc = phy_to_ioc(phy_info->phy);
3065
3066 if (phy_info->sas_port_add_phy) {
3067
3068 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003069 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003070 if (!port) {
3071 error = -ENOMEM;
3072 goto out;
3073 }
3074 error = sas_port_add(port);
3075 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303076 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003077 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003078 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003079 goto out;
3080 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303081 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303082 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3083 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3084 ioc->name, port->port_identifier,
3085 (unsigned long long)phy_info->
3086 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003087 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303088 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3089 "sas_port_add_phy: phy_id=%d\n",
3090 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003091 sas_port_add_phy(port, phy_info->phy);
3092 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303093 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3094 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3095 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003096 }
Eric Moore547f9a22006-06-27 14:42:12 -06003097 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003098
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003099 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003100 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003101 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003102
James Bottomley2686de22006-06-30 12:54:02 -05003103 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003104 /*
3105 * Let the hotplug_work thread handle processing
3106 * the adding/removing of devices that occur
3107 * after start of day.
3108 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303109 if (mptsas_is_end_device(&phy_info->attached) &&
3110 phy_info->attached.handle_parent) {
3111 goto out;
3112 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003113
James Bottomleyf013db32006-03-18 14:54:36 -06003114 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003115 if (scsi_is_host_device(parent)) {
3116 struct mptsas_portinfo *port_info;
3117 int i;
3118
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303119 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003120
3121 for (i = 0; i < port_info->num_phys; i++)
3122 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003123 identify.sas_address) {
3124 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003125 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003126 }
James Bottomley2686de22006-06-30 12:54:02 -05003127
3128 } else if (scsi_is_sas_rphy(parent)) {
3129 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3130 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003131 parent_rphy->identify.sas_address) {
3132 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003133 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003134 }
James Bottomley2686de22006-06-30 12:54:02 -05003135 }
3136
James Bottomleyf013db32006-03-18 14:54:36 -06003137 switch (identify.device_type) {
3138 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003139 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003140 break;
3141 case SAS_EDGE_EXPANDER_DEVICE:
3142 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003143 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003144 break;
3145 default:
3146 rphy = NULL;
3147 break;
3148 }
Eric Moore547f9a22006-06-27 14:42:12 -06003149 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303150 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003151 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003152 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003153 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003154 }
3155
Eric Moore547f9a22006-06-27 14:42:12 -06003156 rphy->identify = identify;
3157 error = sas_rphy_add(rphy);
3158 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303159 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003160 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003161 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003162 sas_rphy_free(rphy);
3163 goto out;
3164 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303165 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303166 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3167 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3168 mptsas_exp_repmanufacture_info(ioc,
3169 identify.sas_address,
3170 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003171 }
3172
Eric Moore547f9a22006-06-27 14:42:12 -06003173 out:
3174 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003175}
3176
3177static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003178mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003179{
Moore, Erice6b2d762006-03-14 09:14:24 -07003180 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003181 int error = -ENOMEM, i;
3182
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303183 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003184 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003185 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003186
Moore, Erice6b2d762006-03-14 09:14:24 -07003187 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003188 if (error)
3189 goto out_free_port_info;
3190
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303191 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003192 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303193 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003194 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303195 ioc->hba_port_info = port_info = hba;
3196 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003197 list_add_tail(&port_info->list, &ioc->sas_topology);
3198 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003199 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003200 port_info->phy_info[i].negotiated_link_rate =
3201 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003202 port_info->phy_info[i].handle =
3203 hba->phy_info[i].handle;
3204 port_info->phy_info[i].port_id =
3205 hba->phy_info[i].port_id;
3206 }
Eric Moore547f9a22006-06-27 14:42:12 -06003207 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003208 kfree(hba);
3209 hba = NULL;
3210 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003211 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303212#if defined(CPQ_CIM)
3213 ioc->num_ports = port_info->num_phys;
3214#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003215 for (i = 0; i < port_info->num_phys; i++) {
3216 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3217 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3218 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303219 port_info->phy_info[i].identify.handle =
3220 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003221 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003222 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3223 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303224 port_info->phy_info[i].identify.handle);
3225 if (!ioc->hba_port_sas_addr)
3226 ioc->hba_port_sas_addr =
3227 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003228 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003229 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003230 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003231 mptsas_sas_device_pg0(ioc,
3232 &port_info->phy_info[i].attached,
3233 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3234 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3235 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003236 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003237
Eric Moore547f9a22006-06-27 14:42:12 -06003238 mptsas_setup_wide_ports(ioc, port_info);
3239
3240 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003241 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003242 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003243
3244 return 0;
3245
3246 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003247 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003248 out:
3249 return error;
3250}
3251
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303252static void
3253mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003254{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303255 struct mptsas_portinfo *parent;
3256 struct device *parent_dev;
3257 struct sas_rphy *rphy;
3258 int i;
3259 u64 sas_address; /* expander sas address */
3260 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303262 handle = port_info->phy_info[0].handle;
3263 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003264 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003265 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303266 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3267 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003268
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303269 mptsas_sas_device_pg0(ioc,
3270 &port_info->phy_info[i].identify,
3271 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3272 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3273 port_info->phy_info[i].identify.handle);
3274 port_info->phy_info[i].identify.phy_id =
3275 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003276
3277 if (port_info->phy_info[i].attached.handle) {
3278 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303279 &port_info->phy_info[i].attached,
3280 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3281 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3282 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003283 port_info->phy_info[i].attached.phy_id =
3284 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003285 }
Eric Moore547f9a22006-06-27 14:42:12 -06003286 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003287
Moore, Erice6b2d762006-03-14 09:14:24 -07003288 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303289 parent = mptsas_find_portinfo_by_handle(ioc,
3290 port_info->phy_info[0].identify.handle_parent);
3291 if (!parent) {
3292 mutex_unlock(&ioc->sas_topology_mutex);
3293 return;
3294 }
3295 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3296 i++) {
3297 if (parent->phy_info[i].attached.sas_address == sas_address) {
3298 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3299 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003300 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003301 }
3302 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303303
3304 mptsas_setup_wide_ports(ioc, port_info);
3305 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3306 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3307 ioc->sas_index, 0);
3308}
3309
3310static void
3311mptsas_expander_event_add(MPT_ADAPTER *ioc,
3312 MpiEventDataSasExpanderStatusChange_t *expander_data)
3313{
3314 struct mptsas_portinfo *port_info;
3315 int i;
3316 __le64 sas_address;
3317
3318 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3319 if (!port_info)
3320 BUG();
3321 port_info->num_phys = (expander_data->NumPhys) ?
3322 expander_data->NumPhys : 1;
3323 port_info->phy_info = kcalloc(port_info->num_phys,
3324 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3325 if (!port_info->phy_info)
3326 BUG();
3327 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3328 for (i = 0; i < port_info->num_phys; i++) {
3329 port_info->phy_info[i].portinfo = port_info;
3330 port_info->phy_info[i].handle =
3331 le16_to_cpu(expander_data->DevHandle);
3332 port_info->phy_info[i].identify.sas_address =
3333 le64_to_cpu(sas_address);
3334 port_info->phy_info[i].identify.handle_parent =
3335 le16_to_cpu(expander_data->ParentDevHandle);
3336 }
3337
3338 mutex_lock(&ioc->sas_topology_mutex);
3339 list_add_tail(&port_info->list, &ioc->sas_topology);
3340 mutex_unlock(&ioc->sas_topology_mutex);
3341
3342 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3343 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3344 (unsigned long long)sas_address);
3345
3346 mptsas_expander_refresh(ioc, port_info);
3347}
3348
3349/**
3350 * mptsas_delete_expander_siblings - remove siblings attached to expander
3351 * @ioc: Pointer to MPT_ADAPTER structure
3352 * @parent: the parent port_info object
3353 * @expander: the expander port_info object
3354 **/
3355static void
3356mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3357 *parent, struct mptsas_portinfo *expander)
3358{
3359 struct mptsas_phyinfo *phy_info;
3360 struct mptsas_portinfo *port_info;
3361 struct sas_rphy *rphy;
3362 int i;
3363
3364 phy_info = expander->phy_info;
3365 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3366 rphy = mptsas_get_rphy(phy_info);
3367 if (!rphy)
3368 continue;
3369 if (rphy->identify.device_type == SAS_END_DEVICE)
3370 mptsas_del_end_device(ioc, phy_info);
3371 }
3372
3373 phy_info = expander->phy_info;
3374 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3375 rphy = mptsas_get_rphy(phy_info);
3376 if (!rphy)
3377 continue;
3378 if (rphy->identify.device_type ==
3379 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3380 rphy->identify.device_type ==
3381 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3382 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3383 rphy->identify.sas_address);
3384 if (!port_info)
3385 continue;
3386 if (port_info == parent) /* backlink rphy */
3387 continue;
3388 /*
3389 Delete this expander even if the expdevpage is exists
3390 because the parent expander is already deleted
3391 */
3392 mptsas_expander_delete(ioc, port_info, 1);
3393 }
3394 }
3395}
3396
3397
3398/**
3399 * mptsas_expander_delete - remove this expander
3400 * @ioc: Pointer to MPT_ADAPTER structure
3401 * @port_info: expander port_info struct
3402 * @force: Flag to forcefully delete the expander
3403 *
3404 **/
3405
3406static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3407 struct mptsas_portinfo *port_info, u8 force)
3408{
3409
3410 struct mptsas_portinfo *parent;
3411 int i;
3412 u64 expander_sas_address;
3413 struct mptsas_phyinfo *phy_info;
3414 struct mptsas_portinfo buffer;
3415 struct mptsas_portinfo_details *port_details;
3416 struct sas_port *port;
3417
3418 if (!port_info)
3419 return;
3420
3421 /* see if expander is still there before deleting */
3422 mptsas_sas_expander_pg0(ioc, &buffer,
3423 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3424 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3425 port_info->phy_info[0].identify.handle);
3426
3427 if (buffer.num_phys) {
3428 kfree(buffer.phy_info);
3429 if (!force)
3430 return;
3431 }
3432
3433
3434 /*
3435 * Obtain the port_info instance to the parent port
3436 */
3437 port_details = NULL;
3438 expander_sas_address =
3439 port_info->phy_info[0].identify.sas_address;
3440 parent = mptsas_find_portinfo_by_handle(ioc,
3441 port_info->phy_info[0].identify.handle_parent);
3442 mptsas_delete_expander_siblings(ioc, parent, port_info);
3443 if (!parent)
3444 goto out;
3445
3446 /*
3447 * Delete rphys in the parent that point
3448 * to this expander.
3449 */
3450 phy_info = parent->phy_info;
3451 port = NULL;
3452 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3453 if (!phy_info->phy)
3454 continue;
3455 if (phy_info->attached.sas_address !=
3456 expander_sas_address)
3457 continue;
3458 if (!port) {
3459 port = mptsas_get_port(phy_info);
3460 port_details = phy_info->port_details;
3461 }
3462 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3463 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3464 phy_info->phy_id, phy_info->phy);
3465 sas_port_delete_phy(port, phy_info->phy);
3466 }
3467 if (port) {
3468 dev_printk(KERN_DEBUG, &port->dev,
3469 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3470 ioc->name, port->port_identifier,
3471 (unsigned long long)expander_sas_address);
3472 sas_port_delete(port);
3473 mptsas_port_delete(ioc, port_details);
3474 }
3475 out:
3476
3477 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3478 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3479 (unsigned long long)expander_sas_address);
3480
3481 /*
3482 * free link
3483 */
3484 list_del(&port_info->list);
3485 kfree(port_info->phy_info);
3486 kfree(port_info);
3487}
3488
3489
3490/**
3491 * mptsas_send_expander_event - expanders events
3492 * @ioc: Pointer to MPT_ADAPTER structure
3493 * @expander_data: event data
3494 *
3495 *
3496 * This function handles adding, removing, and refreshing
3497 * device handles within the expander objects.
3498 */
3499static void
3500mptsas_send_expander_event(struct fw_event_work *fw_event)
3501{
3502 MPT_ADAPTER *ioc;
3503 MpiEventDataSasExpanderStatusChange_t *expander_data;
3504 struct mptsas_portinfo *port_info;
3505 __le64 sas_address;
3506 int i;
3507
3508 ioc = fw_event->ioc;
3509 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3510 fw_event->event_data;
3511 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303512 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303513 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3514
3515 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3516 if (port_info) {
3517 for (i = 0; i < port_info->num_phys; i++) {
3518 port_info->phy_info[i].portinfo = port_info;
3519 port_info->phy_info[i].handle =
3520 le16_to_cpu(expander_data->DevHandle);
3521 port_info->phy_info[i].identify.sas_address =
3522 le64_to_cpu(sas_address);
3523 port_info->phy_info[i].identify.handle_parent =
3524 le16_to_cpu(expander_data->ParentDevHandle);
3525 }
3526 mptsas_expander_refresh(ioc, port_info);
3527 } else if (!port_info && expander_data->NumPhys)
3528 mptsas_expander_event_add(ioc, expander_data);
3529 } else if (expander_data->ReasonCode ==
3530 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3531 mptsas_expander_delete(ioc, port_info, 0);
3532
3533 mptsas_free_fw_event(ioc, fw_event);
3534}
3535
3536
3537/**
3538 * mptsas_expander_add -
3539 * @ioc: Pointer to MPT_ADAPTER structure
3540 * @handle:
3541 *
3542 */
3543struct mptsas_portinfo *
3544mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3545{
3546 struct mptsas_portinfo buffer, *port_info;
3547 int i;
3548
3549 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3550 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3551 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3552 return NULL;
3553
3554 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3555 if (!port_info) {
3556 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3557 "%s: exit at line=%d\n", ioc->name,
3558 __func__, __LINE__));
3559 return NULL;
3560 }
3561 port_info->num_phys = buffer.num_phys;
3562 port_info->phy_info = buffer.phy_info;
3563 for (i = 0; i < port_info->num_phys; i++)
3564 port_info->phy_info[i].portinfo = port_info;
3565 mutex_lock(&ioc->sas_topology_mutex);
3566 list_add_tail(&port_info->list, &ioc->sas_topology);
3567 mutex_unlock(&ioc->sas_topology_mutex);
3568 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3569 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3570 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3571 mptsas_expander_refresh(ioc, port_info);
3572 return port_info;
3573}
3574
3575static void
3576mptsas_send_link_status_event(struct fw_event_work *fw_event)
3577{
3578 MPT_ADAPTER *ioc;
3579 MpiEventDataSasPhyLinkStatus_t *link_data;
3580 struct mptsas_portinfo *port_info;
3581 struct mptsas_phyinfo *phy_info = NULL;
3582 __le64 sas_address;
3583 u8 phy_num;
3584 u8 link_rate;
3585
3586 ioc = fw_event->ioc;
3587 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3588
3589 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3590 sas_address = le64_to_cpu(sas_address);
3591 link_rate = link_data->LinkRates >> 4;
3592 phy_num = link_data->PhyNum;
3593
3594 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3595 if (port_info) {
3596 phy_info = &port_info->phy_info[phy_num];
3597 if (phy_info)
3598 phy_info->negotiated_link_rate = link_rate;
3599 }
3600
3601 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3602 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3603
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303604 if (!port_info) {
3605 if (ioc->old_sas_discovery_protocal) {
3606 port_info = mptsas_expander_add(ioc,
3607 le16_to_cpu(link_data->DevHandle));
3608 if (port_info)
3609 goto out;
3610 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303611 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303612 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303613
3614 if (port_info == ioc->hba_port_info)
3615 mptsas_probe_hba_phys(ioc);
3616 else
3617 mptsas_expander_refresh(ioc, port_info);
3618 } else if (phy_info && phy_info->phy) {
3619 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3620 phy_info->phy->negotiated_linkrate =
3621 SAS_PHY_DISABLED;
3622 else if (link_rate ==
3623 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3624 phy_info->phy->negotiated_linkrate =
3625 SAS_LINK_RATE_FAILED;
3626 else
3627 phy_info->phy->negotiated_linkrate =
3628 SAS_LINK_RATE_UNKNOWN;
3629 }
3630 out:
3631 mptsas_free_fw_event(ioc, fw_event);
3632}
3633
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303634static void
3635mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3636{
3637 struct mptsas_portinfo buffer, *port_info;
3638 struct mptsas_device_info *sas_info;
3639 struct mptsas_devinfo sas_device;
3640 u32 handle;
3641 VirtTarget *vtarget = NULL;
3642 struct mptsas_phyinfo *phy_info;
3643 u8 found_expander;
3644 int retval, retry_count;
3645 unsigned long flags;
3646
3647 mpt_findImVolumes(ioc);
3648
3649 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3650 if (ioc->ioc_reset_in_progress) {
3651 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3652 "%s: exiting due to a parallel reset \n", ioc->name,
3653 __func__));
3654 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3655 return;
3656 }
3657 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3658
3659 /* devices, logical volumes */
3660 mutex_lock(&ioc->sas_device_info_mutex);
3661 redo_device_scan:
3662 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303663 if (sas_info->is_cached)
3664 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303665 if (!sas_info->is_logical_volume) {
3666 sas_device.handle = 0;
3667 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303668retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303669 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303670 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3671 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3672 (sas_info->fw.channel << 8) +
3673 sas_info->fw.id);
3674
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303675 if (sas_device.handle)
3676 continue;
3677 if (retval == -EBUSY) {
3678 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3679 if (ioc->ioc_reset_in_progress) {
3680 dfailprintk(ioc,
3681 printk(MYIOC_s_DEBUG_FMT
3682 "%s: exiting due to reset\n",
3683 ioc->name, __func__));
3684 spin_unlock_irqrestore
3685 (&ioc->taskmgmt_lock, flags);
3686 mutex_unlock(&ioc->
3687 sas_device_info_mutex);
3688 return;
3689 }
3690 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3691 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303692 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303693
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303694 if (retval && (retval != -ENODEV)) {
3695 if (retry_count < 10) {
3696 retry_count++;
3697 goto retry_page;
3698 } else {
3699 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3700 "%s: Config page retry exceeded retry "
3701 "count deleting device 0x%llx\n",
3702 ioc->name, __func__,
3703 sas_info->sas_address));
3704 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303705 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303706
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303707 /* delete device */
3708 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303709 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303710
3711 if (vtarget)
3712 vtarget->deleted = 1;
3713
3714 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3715 sas_info->sas_address);
3716
3717 if (phy_info) {
3718 mptsas_del_end_device(ioc, phy_info);
3719 goto redo_device_scan;
3720 }
3721 } else
3722 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303723 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003724 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303725
3726 /* expanders */
3727 mutex_lock(&ioc->sas_topology_mutex);
3728 redo_expander_scan:
3729 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3730
3731 if (port_info->phy_info &&
3732 (!(port_info->phy_info[0].identify.device_info &
3733 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3734 continue;
3735 found_expander = 0;
3736 handle = 0xFFFF;
3737 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3738 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3739 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3740 !found_expander) {
3741
3742 handle = buffer.phy_info[0].handle;
3743 if (buffer.phy_info[0].identify.sas_address ==
3744 port_info->phy_info[0].identify.sas_address) {
3745 found_expander = 1;
3746 }
3747 kfree(buffer.phy_info);
3748 }
3749
3750 if (!found_expander) {
3751 mptsas_expander_delete(ioc, port_info, 0);
3752 goto redo_expander_scan;
3753 }
3754 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003755 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303756}
3757
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303758/**
3759 * mptsas_probe_expanders - adding expanders
3760 * @ioc: Pointer to MPT_ADAPTER structure
3761 *
3762 **/
3763static void
3764mptsas_probe_expanders(MPT_ADAPTER *ioc)
3765{
3766 struct mptsas_portinfo buffer, *port_info;
3767 u32 handle;
3768 int i;
3769
3770 handle = 0xFFFF;
3771 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3772 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3773 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3774
3775 handle = buffer.phy_info[0].handle;
3776 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3777 buffer.phy_info[0].identify.sas_address);
3778
3779 if (port_info) {
3780 /* refreshing handles */
3781 for (i = 0; i < buffer.num_phys; i++) {
3782 port_info->phy_info[i].handle = handle;
3783 port_info->phy_info[i].identify.handle_parent =
3784 buffer.phy_info[0].identify.handle_parent;
3785 }
3786 mptsas_expander_refresh(ioc, port_info);
3787 kfree(buffer.phy_info);
3788 continue;
3789 }
3790
3791 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3792 if (!port_info) {
3793 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3794 "%s: exit at line=%d\n", ioc->name,
3795 __func__, __LINE__));
3796 return;
3797 }
3798 port_info->num_phys = buffer.num_phys;
3799 port_info->phy_info = buffer.phy_info;
3800 for (i = 0; i < port_info->num_phys; i++)
3801 port_info->phy_info[i].portinfo = port_info;
3802 mutex_lock(&ioc->sas_topology_mutex);
3803 list_add_tail(&port_info->list, &ioc->sas_topology);
3804 mutex_unlock(&ioc->sas_topology_mutex);
3805 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3806 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3807 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3808 mptsas_expander_refresh(ioc, port_info);
3809 }
3810}
3811
3812static void
3813mptsas_probe_devices(MPT_ADAPTER *ioc)
3814{
3815 u16 handle;
3816 struct mptsas_devinfo sas_device;
3817 struct mptsas_phyinfo *phy_info;
3818
3819 handle = 0xFFFF;
3820 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3821 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3822
3823 handle = sas_device.handle;
3824
3825 if ((sas_device.device_info &
3826 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3827 MPI_SAS_DEVICE_INFO_STP_TARGET |
3828 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3829 continue;
3830
3831 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3832 if (!phy_info)
3833 continue;
3834
3835 if (mptsas_get_rphy(phy_info))
3836 continue;
3837
3838 mptsas_add_end_device(ioc, phy_info);
3839 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003840}
3841
Kashyap, Desai2f187862009-05-29 16:52:37 +05303842/**
3843 * mptsas_scan_sas_topology -
3844 * @ioc: Pointer to MPT_ADAPTER structure
3845 * @sas_address:
3846 *
3847 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003848static void
3849mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3850{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303851 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003852 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003853
Moore, Erice6b2d762006-03-14 09:14:24 -07003854 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303855 mptsas_probe_expanders(ioc);
3856 mptsas_probe_devices(ioc);
3857
Moore, Ericf44e5462006-03-14 09:14:21 -07003858 /*
3859 Reporting RAID volumes.
3860 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303861 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3862 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3863 return;
Eric Moore793955f2007-01-29 09:42:20 -07003864 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303865 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3866 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3867 if (sdev) {
3868 scsi_device_put(sdev);
3869 continue;
3870 }
3871 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3872 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3873 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003874 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003875 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3876 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003877}
3878
Kashyap, Desai57e98512009-05-29 16:55:09 +05303879
3880static void
3881mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3882{
3883 MPT_ADAPTER *ioc;
3884 EventDataQueueFull_t *qfull_data;
3885 struct mptsas_device_info *sas_info;
3886 struct scsi_device *sdev;
3887 int depth;
3888 int id = -1;
3889 int channel = -1;
3890 int fw_id, fw_channel;
3891 u16 current_depth;
3892
3893
3894 ioc = fw_event->ioc;
3895 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3896 fw_id = qfull_data->TargetID;
3897 fw_channel = qfull_data->Bus;
3898 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3899
3900 /* if hidden raid component, look for the volume id */
3901 mutex_lock(&ioc->sas_device_info_mutex);
3902 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3903 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3904 list) {
3905 if (sas_info->is_cached ||
3906 sas_info->is_logical_volume)
3907 continue;
3908 if (sas_info->is_hidden_raid_component &&
3909 (sas_info->fw.channel == fw_channel &&
3910 sas_info->fw.id == fw_id)) {
3911 id = sas_info->volume_id;
3912 channel = MPTSAS_RAID_CHANNEL;
3913 goto out;
3914 }
3915 }
3916 } else {
3917 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3918 list) {
3919 if (sas_info->is_cached ||
3920 sas_info->is_hidden_raid_component ||
3921 sas_info->is_logical_volume)
3922 continue;
3923 if (sas_info->fw.channel == fw_channel &&
3924 sas_info->fw.id == fw_id) {
3925 id = sas_info->os.id;
3926 channel = sas_info->os.channel;
3927 goto out;
3928 }
3929 }
3930
3931 }
3932
3933 out:
3934 mutex_unlock(&ioc->sas_device_info_mutex);
3935
3936 if (id != -1) {
3937 shost_for_each_device(sdev, ioc->sh) {
3938 if (sdev->id == id && sdev->channel == channel) {
3939 if (current_depth > sdev->queue_depth) {
3940 sdev_printk(KERN_INFO, sdev,
3941 "strange observation, the queue "
3942 "depth is (%d) meanwhile fw queue "
3943 "depth (%d)\n", sdev->queue_depth,
3944 current_depth);
3945 continue;
3946 }
3947 depth = scsi_track_queue_full(sdev,
3948 current_depth - 1);
3949 if (depth > 0)
3950 sdev_printk(KERN_INFO, sdev,
3951 "Queue depth reduced to (%d)\n",
3952 depth);
3953 else if (depth < 0)
3954 sdev_printk(KERN_INFO, sdev,
3955 "Tagged Command Queueing is being "
3956 "disabled\n");
3957 else if (depth == 0)
3958 sdev_printk(KERN_INFO, sdev,
3959 "Queue depth not changed yet\n");
3960 }
3961 }
3962 }
3963
3964 mptsas_free_fw_event(ioc, fw_event);
3965}
3966
3967
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003968static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003969mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003970{
3971 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003972 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003973 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003974
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003975 mutex_lock(&ioc->sas_topology_mutex);
3976 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3977 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003978 if (!mptsas_is_end_device(
3979 &port_info->phy_info[i].attached))
3980 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003981 if (port_info->phy_info[i].attached.sas_address
3982 != sas_address)
3983 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003984 phy_info = &port_info->phy_info[i];
3985 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003986 }
3987 }
3988 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003989 return phy_info;
3990}
3991
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303992/**
3993 * mptsas_find_phyinfo_by_phys_disk_num -
3994 * @ioc: Pointer to MPT_ADAPTER structure
3995 * @phys_disk_num:
3996 * @channel:
3997 * @id:
3998 *
3999 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004000static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304001mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4002 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004003{
Eric Mooreb506ade2007-01-29 09:45:37 -07004004 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304005 struct mptsas_portinfo *port_info;
4006 RaidPhysDiskPage1_t *phys_disk = NULL;
4007 int num_paths;
4008 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004009 int i;
4010
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304011 phy_info = NULL;
4012 if (!ioc->raid_data.pIocPg3)
4013 return NULL;
4014 /* dual port support */
4015 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4016 if (!num_paths)
4017 goto out;
4018 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4019 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4020 if (!phys_disk)
4021 goto out;
4022 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4023 for (i = 0; i < num_paths; i++) {
4024 if ((phys_disk->Path[i].Flags & 1) != 0)
4025 /* entry no longer valid */
4026 continue;
4027 if ((id == phys_disk->Path[i].PhysDiskID) &&
4028 (channel == phys_disk->Path[i].PhysDiskBus)) {
4029 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4030 sizeof(u64));
4031 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4032 sas_address);
4033 goto out;
4034 }
4035 }
4036
4037 out:
4038 kfree(phys_disk);
4039 if (phy_info)
4040 return phy_info;
4041
4042 /*
4043 * Extra code to handle RAID0 case, where the sas_address is not updated
4044 * in phys_disk_page_1 when hotswapped
4045 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004046 mutex_lock(&ioc->sas_topology_mutex);
4047 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304048 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004049 if (!mptsas_is_end_device(
4050 &port_info->phy_info[i].attached))
4051 continue;
4052 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4053 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304054 if ((port_info->phy_info[i].attached.phys_disk_num ==
4055 phys_disk_num) &&
4056 (port_info->phy_info[i].attached.id == id) &&
4057 (port_info->phy_info[i].attached.channel ==
4058 channel))
4059 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004060 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004061 }
4062 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004063 return phy_info;
4064}
4065
4066static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004067mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4068{
Eric Mooref99be432007-01-04 20:46:54 -07004069 int rc;
4070
Moore, Ericf44e5462006-03-14 09:14:21 -07004071 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004072 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004073}
4074
4075static void
4076mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4077{
4078 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4079 mptsas_reprobe_lun);
4080}
4081
Eric Mooreb506ade2007-01-29 09:45:37 -07004082static void
4083mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4084{
4085 CONFIGPARMS cfg;
4086 ConfigPageHeader_t hdr;
4087 dma_addr_t dma_handle;
4088 pRaidVolumePage0_t buffer = NULL;
4089 RaidPhysDiskPage0_t phys_disk;
4090 int i;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304091 struct mptsas_phyinfo *phy_info;
4092 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004093
4094 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4095 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4096 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4097 cfg.pageAddr = (channel << 8) + id;
4098 cfg.cfghdr.hdr = &hdr;
4099 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4100
4101 if (mpt_config(ioc, &cfg) != 0)
4102 goto out;
4103
4104 if (!hdr.PageLength)
4105 goto out;
4106
4107 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4108 &dma_handle);
4109
4110 if (!buffer)
4111 goto out;
4112
4113 cfg.physAddr = dma_handle;
4114 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4115
4116 if (mpt_config(ioc, &cfg) != 0)
4117 goto out;
4118
4119 if (!(buffer->VolumeStatus.Flags &
4120 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4121 goto out;
4122
4123 if (!buffer->NumPhysDisks)
4124 goto out;
4125
4126 for (i = 0; i < buffer->NumPhysDisks; i++) {
4127
4128 if (mpt_raid_phys_disk_pg0(ioc,
4129 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4130 continue;
4131
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304132 if (mptsas_sas_device_pg0(ioc, &sas_device,
4133 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4134 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4135 (phys_disk.PhysDiskBus << 8) +
4136 phys_disk.PhysDiskID))
4137 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004138
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304139 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4140 sas_device.sas_address);
4141 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004142 }
4143
4144 out:
4145 if (buffer)
4146 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4147 dma_handle);
4148}
Moore, Erice6b2d762006-03-14 09:14:24 -07004149/*
4150 * Work queue thread to handle SAS hotplug events
4151 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004152static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304153mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4154 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004155{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004156 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004157 struct scsi_target * starget;
Moore, Ericc73787e2006-01-26 16:20:06 -07004158 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004159 VirtTarget *vtarget;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304160 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06004161
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304162 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004163
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304164 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004165
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304166 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004167 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004168
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304169 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4170 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4171 hot_plug_info->id) {
4172 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4173 "to add hidden disk - target_id matchs "
4174 "volume_id\n", ioc->name);
4175 mptsas_free_fw_event(ioc, fw_event);
4176 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004177 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004178 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304179 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004180
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004181 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304182 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4183 mptsas_sas_device_pg0(ioc, &sas_device,
4184 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4185 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4186 (hot_plug_info->channel << 8) +
4187 hot_plug_info->id);
Moore, Ericc73787e2006-01-26 16:20:06 -07004188
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304189 if (!sas_device.handle)
4190 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004191
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304192 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4193 if (!phy_info)
4194 break;
4195
4196 if (mptsas_get_rphy(phy_info))
4197 break;
4198
4199 mptsas_add_end_device(ioc, phy_info);
4200 break;
4201
4202 case MPTSAS_DEL_DEVICE:
4203 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4204 hot_plug_info->sas_address);
4205 mptsas_del_end_device(ioc, phy_info);
4206 break;
4207
4208 case MPTSAS_DEL_PHYSDISK:
4209
4210 mpt_findImVolumes(ioc);
4211
4212 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304213 ioc, hot_plug_info->phys_disk_num,
4214 hot_plug_info->channel,
4215 hot_plug_info->id);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304216 mptsas_del_end_device(ioc, phy_info);
4217 break;
4218
4219 case MPTSAS_ADD_PHYSDISK_REPROBE:
4220
Christoph Hellwige3094442006-02-16 13:25:36 +01004221 if (mptsas_sas_device_pg0(ioc, &sas_device,
4222 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004223 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304224 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4225 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4226 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4227 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004228 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004229 }
4230
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304231 phy_info = mptsas_find_phyinfo_by_sas_address(
4232 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004233
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304234 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304235 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304236 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4237 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004238 break;
4239 }
4240
4241 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304242 if (!starget) {
4243 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4244 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4245 __func__, hot_plug_info->id, __LINE__));
4246 break;
4247 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004248
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304249 vtarget = starget->hostdata;
4250 if (!vtarget) {
4251 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4252 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4253 __func__, hot_plug_info->id, __LINE__));
4254 break;
4255 }
Eric Moore547f9a22006-06-27 14:42:12 -06004256
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304257 mpt_findImVolumes(ioc);
4258
4259 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4260 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4261 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4262 hot_plug_info->phys_disk_num, (unsigned long long)
4263 sas_device.sas_address);
4264
4265 vtarget->id = hot_plug_info->phys_disk_num;
4266 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4267 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4268 mptsas_reprobe_target(starget, 1);
4269 break;
4270
4271 case MPTSAS_DEL_PHYSDISK_REPROBE:
4272
4273 if (mptsas_sas_device_pg0(ioc, &sas_device,
4274 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4275 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4276 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304277 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304278 "%s: fw_id=%d exit at line=%d\n",
4279 ioc->name, __func__,
4280 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004281 break;
4282 }
4283
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304284 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4285 sas_device.sas_address);
4286 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304287 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304288 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4289 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004290 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004291 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004292
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304293 starget = mptsas_get_starget(phy_info);
4294 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304295 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304296 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4297 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004298 break;
4299 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004300
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304301 vtarget = starget->hostdata;
4302 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304303 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304304 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4305 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004306 break;
4307 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304308
4309 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4310 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4311 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4312 __func__, hot_plug_info->id, __LINE__));
4313 break;
4314 }
4315
4316 mpt_findImVolumes(ioc);
4317
4318 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4319 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4320 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4321 hot_plug_info->phys_disk_num, (unsigned long long)
4322 sas_device.sas_address);
4323
4324 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4325 vtarget->id = hot_plug_info->id;
4326 phy_info->attached.phys_disk_num = ~0;
4327 mptsas_reprobe_target(starget, 0);
4328 mptsas_add_device_component_by_fw(ioc,
4329 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004330 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304331
Moore, Ericc73787e2006-01-26 16:20:06 -07004332 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304333
Moore, Ericc73787e2006-01-26 16:20:06 -07004334 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304335 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4336 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4337 hot_plug_info->id);
4338 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4339 hot_plug_info->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07004340 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304341
Moore, Ericc73787e2006-01-26 16:20:06 -07004342 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304343
Moore, Ericc73787e2006-01-26 16:20:06 -07004344 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304345 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4346 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4347 hot_plug_info->id);
4348 scsi_remove_device(hot_plug_info->sdev);
4349 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787e2006-01-26 16:20:06 -07004350 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304351
Eric Mooreb506ade2007-01-29 09:45:37 -07004352 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304353
4354 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004355 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304356 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004357 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304358
Moore, Ericbd23e942006-04-17 12:43:04 -06004359 default:
4360 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004361 }
4362
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304363 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004364}
4365
4366static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304367mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004368{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304369 MPT_ADAPTER *ioc;
4370 struct mptsas_hotplug_event hot_plug_info;
4371 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4372 u32 device_info;
4373 u64 sas_address;
4374
4375 ioc = fw_event->ioc;
4376 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4377 fw_event->event_data;
4378 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004379
4380 if ((device_info &
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304381 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4382 MPI_SAS_DEVICE_INFO_STP_TARGET |
4383 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4384 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004385 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304386 }
4387
4388 if (sas_event_data->ReasonCode ==
4389 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4390 mptbase_sas_persist_operation(ioc,
4391 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4392 mptsas_free_fw_event(ioc, fw_event);
4393 return;
4394 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004395
Moore, Eric4b766472006-03-14 09:14:12 -07004396 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004397 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004398 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304399 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4400 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4401 hot_plug_info.channel = sas_event_data->Bus;
4402 hot_plug_info.id = sas_event_data->TargetID;
4403 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004404 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304405 sizeof(u64));
4406 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4407 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004408 if (sas_event_data->ReasonCode &
4409 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304410 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004411 else
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304412 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4413 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004414 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304415
Moore, Eric4b766472006-03-14 09:14:12 -07004416 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304417 mptbase_sas_persist_operation(ioc,
4418 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4419 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004420 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304421
Moore, Eric4b766472006-03-14 09:14:12 -07004422 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304423 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004424 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304425 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004426 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304427 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004428 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004429 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004430}
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304431
Moore, Ericc73787e2006-01-26 16:20:06 -07004432static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304433mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787e2006-01-26 16:20:06 -07004434{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304435 MPT_ADAPTER *ioc;
4436 EVENT_DATA_RAID *raid_event_data;
4437 struct mptsas_hotplug_event hot_plug_info;
4438 int status;
4439 int state;
4440 struct scsi_device *sdev = NULL;
4441 VirtDevice *vdevice = NULL;
4442 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787e2006-01-26 16:20:06 -07004443
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304444 ioc = fw_event->ioc;
4445 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4446 status = le32_to_cpu(raid_event_data->SettingsStatus);
4447 state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07004448
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304449 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4450 hot_plug_info.id = raid_event_data->VolumeID;
4451 hot_plug_info.channel = raid_event_data->VolumeBus;
4452 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4453
4454 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4455 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4456 raid_event_data->ReasonCode ==
4457 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4458 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4459 hot_plug_info.id, 0);
4460 hot_plug_info.sdev = sdev;
4461 if (sdev)
4462 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07004463 }
4464
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304465 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4466 "ReasonCode=%02x\n", ioc->name, __func__,
4467 raid_event_data->ReasonCode));
Moore, Ericc73787e2006-01-26 16:20:06 -07004468
4469 switch (raid_event_data->ReasonCode) {
4470 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304471 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004472 break;
4473 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304474 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004475 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004476 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4477 switch (state) {
4478 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004479 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304480 mpt_raid_phys_disk_pg0(ioc,
4481 raid_event_data->PhysDiskNum, &phys_disk);
4482 hot_plug_info.id = phys_disk.PhysDiskID;
4483 hot_plug_info.channel = phys_disk.PhysDiskBus;
4484 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004485 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304486 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004487 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004488 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4489 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4490 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304491 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004492 break;
4493 default:
4494 break;
4495 }
4496 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07004497 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304498 if (!sdev)
4499 break;
4500 vdevice->vtarget->deleted = 1; /* block IO */
4501 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004502 break;
4503 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304504 if (sdev) {
4505 scsi_device_put(sdev);
4506 break;
4507 }
4508 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004509 break;
4510 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304511 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4512 if (!sdev)
4513 break;
4514 vdevice->vtarget->deleted = 1; /* block IO */
4515 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4516 break;
4517 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004518 switch (state) {
4519 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4520 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304521 if (!sdev)
4522 break;
4523 vdevice->vtarget->deleted = 1; /* block IO */
4524 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004525 break;
4526 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4527 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304528 if (sdev) {
4529 scsi_device_put(sdev);
4530 break;
4531 }
4532 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004533 break;
4534 default:
4535 break;
4536 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004537 break;
4538 default:
4539 break;
4540 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304541
4542 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4543 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4544 else
4545 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787e2006-01-26 16:20:06 -07004546}
4547
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304548/**
4549 * mptsas_issue_tm - send mptsas internal tm request
4550 * @ioc: Pointer to MPT_ADAPTER structure
4551 * @type: Task Management type
4552 * @channel: channel number for task management
4553 * @id: Logical Target ID for reset (if appropriate)
4554 * @lun: Logical unit for reset (if appropriate)
4555 * @task_context: Context for the task to be aborted
4556 * @timeout: timeout for task management control
4557 *
4558 * return 0 on success and -1 on failure:
4559 *
4560 */
4561static int
4562mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4563 int task_context, ulong timeout, u8 *issue_reset)
4564{
4565 MPT_FRAME_HDR *mf;
4566 SCSITaskMgmt_t *pScsiTm;
4567 int retval;
4568 unsigned long timeleft;
4569
4570 *issue_reset = 0;
4571 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4572 if (mf == NULL) {
4573 retval = -1; /* return failure */
4574 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4575 "msg frames!!\n", ioc->name));
4576 goto out;
4577 }
4578
4579 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4580 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4581 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4582 type, timeout, channel, id, (unsigned long long)lun,
4583 task_context));
4584
4585 pScsiTm = (SCSITaskMgmt_t *) mf;
4586 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4587 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4588 pScsiTm->TaskType = type;
4589 pScsiTm->MsgFlags = 0;
4590 pScsiTm->TargetID = id;
4591 pScsiTm->Bus = channel;
4592 pScsiTm->ChainOffset = 0;
4593 pScsiTm->Reserved = 0;
4594 pScsiTm->Reserved1 = 0;
4595 pScsiTm->TaskMsgContext = task_context;
4596 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4597
4598 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4599 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4600 retval = 0;
4601 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4602
4603 /* Now wait for the command to complete */
4604 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4605 timeout*HZ);
4606 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4607 retval = -1; /* return failure */
4608 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4609 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4610 mpt_free_msg_frame(ioc, mf);
4611 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4612 goto out;
4613 *issue_reset = 1;
4614 goto out;
4615 }
4616
4617 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4618 retval = -1; /* return failure */
4619 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4620 "TaskMgmt request: failed with no reply\n", ioc->name));
4621 goto out;
4622 }
4623
4624 out:
4625 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4626 return retval;
4627}
4628
4629/**
4630 * mptsas_broadcast_primative_work - Handle broadcast primitives
4631 * @work: work queue payload containing info describing the event
4632 *
4633 * this will be handled in workqueue context.
4634 */
4635static void
4636mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4637{
4638 MPT_ADAPTER *ioc = fw_event->ioc;
4639 MPT_FRAME_HDR *mf;
4640 VirtDevice *vdevice;
4641 int ii;
4642 struct scsi_cmnd *sc;
4643 SCSITaskMgmtReply_t *pScsiTmReply;
4644 u8 issue_reset;
4645 int task_context;
4646 u8 channel, id;
4647 int lun;
4648 u32 termination_count;
4649 u32 query_count;
4650
4651 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4652 "%s - enter\n", ioc->name, __func__));
4653
4654 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4655 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4656 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4657 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4658 return;
4659 }
4660
4661 issue_reset = 0;
4662 termination_count = 0;
4663 query_count = 0;
4664 mpt_findImVolumes(ioc);
4665 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4666
4667 for (ii = 0; ii < ioc->req_depth; ii++) {
4668 if (ioc->fw_events_off)
4669 goto out;
4670 sc = mptscsih_get_scsi_lookup(ioc, ii);
4671 if (!sc)
4672 continue;
4673 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4674 if (!mf)
4675 continue;
4676 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4677 vdevice = sc->device->hostdata;
4678 if (!vdevice || !vdevice->vtarget)
4679 continue;
4680 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4681 continue; /* skip hidden raid components */
4682 if (vdevice->vtarget->raidVolume)
4683 continue; /* skip hidden raid components */
4684 channel = vdevice->vtarget->channel;
4685 id = vdevice->vtarget->id;
4686 lun = vdevice->lun;
4687 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4688 channel, id, (u64)lun, task_context, 30, &issue_reset))
4689 goto out;
4690 query_count++;
4691 termination_count +=
4692 le32_to_cpu(pScsiTmReply->TerminationCount);
4693 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4694 (pScsiTmReply->ResponseCode ==
4695 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4696 pScsiTmReply->ResponseCode ==
4697 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4698 continue;
4699 if (mptsas_issue_tm(ioc,
4700 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4701 channel, id, (u64)lun, 0, 30, &issue_reset))
4702 goto out;
4703 termination_count +=
4704 le32_to_cpu(pScsiTmReply->TerminationCount);
4705 }
4706
4707 out:
4708 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4709 "%s - exit, query_count = %d termination_count = %d\n",
4710 ioc->name, __func__, query_count, termination_count));
4711
4712 ioc->broadcast_aen_busy = 0;
4713 mpt_clear_taskmgmt_in_progress_flag(ioc);
4714 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4715
4716 if (issue_reset) {
4717 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4718 ioc->name, __func__);
4719 mpt_HardResetHandler(ioc, CAN_SLEEP);
4720 }
4721 mptsas_free_fw_event(ioc, fw_event);
4722}
4723
Eric Mooreb506ade2007-01-29 09:45:37 -07004724/*
4725 * mptsas_send_ir2_event - handle exposing hidden disk when
4726 * an inactive raid volume is added
4727 *
4728 * @ioc: Pointer to MPT_ADAPTER structure
4729 * @ir2_data
4730 *
4731 */
4732static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304733mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004734{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304735 MPT_ADAPTER *ioc;
4736 struct mptsas_hotplug_event hot_plug_info;
4737 MPI_EVENT_DATA_IR2 *ir2_data;
4738 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304739 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004740
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304741 ioc = fw_event->ioc;
4742 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4743 reasonCode = ir2_data->ReasonCode;
4744
4745 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4746 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4747
4748 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4749 hot_plug_info.id = ir2_data->TargetID;
4750 hot_plug_info.channel = ir2_data->Bus;
4751 switch (reasonCode) {
4752 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4753 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4754 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304755 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4756 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4757 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4758 break;
4759 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4760 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4761 mpt_raid_phys_disk_pg0(ioc,
4762 ir2_data->PhysDiskNum, &phys_disk);
4763 hot_plug_info.id = phys_disk.PhysDiskID;
4764 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4765 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304766 default:
4767 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004768 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304769 }
4770 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4771}
Moore, Erice6b2d762006-03-14 09:14:24 -07004772
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004773static int
4774mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4775{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304776 u32 event = le32_to_cpu(reply->Event);
4777 int sz, event_data_sz;
4778 struct fw_event_work *fw_event;
4779 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004780
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304781 /* events turned off due to host reset or driver unloading */
4782 if (ioc->fw_events_off)
4783 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004784
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304785 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004786 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304787 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4788 {
4789 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4790 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4791 if (broadcast_event_data->Primitive !=
4792 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4793 return 0;
4794 if (ioc->broadcast_aen_busy)
4795 return 0;
4796 ioc->broadcast_aen_busy = 1;
4797 break;
4798 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004799 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304800 {
4801 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4802 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4803
4804 if (sas_event_data->ReasonCode ==
4805 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4806 mptsas_target_reset_queue(ioc, sas_event_data);
4807 return 0;
4808 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004809 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304810 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304811 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4812 {
4813 MpiEventDataSasExpanderStatusChange_t *expander_data =
4814 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4815
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304816 if (ioc->old_sas_discovery_protocal)
4817 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304818
4819 if (expander_data->ReasonCode ==
4820 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4821 ioc->device_missing_delay)
4822 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004823 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304824 }
4825 case MPI_EVENT_SAS_DISCOVERY:
4826 {
4827 u32 discovery_status;
4828 EventDataSasDiscovery_t *discovery_data =
4829 (EventDataSasDiscovery_t *)reply->Data;
4830
4831 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4832 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304833 if (ioc->old_sas_discovery_protocal && !discovery_status)
4834 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304835 return 0;
4836 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304837 case MPI_EVENT_INTEGRATED_RAID:
4838 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004839 case MPI_EVENT_IR2:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304840 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4841 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004842 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004843 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304844 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004845 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004846
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304847 event_data_sz = ((reply->MsgLength * 4) -
4848 offsetof(EventNotificationReply_t, Data));
4849 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4850 fw_event = kzalloc(sz, GFP_ATOMIC);
4851 if (!fw_event) {
4852 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4853 __func__, __LINE__);
4854 return 0;
4855 }
4856 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4857 fw_event->event = event;
4858 fw_event->ioc = ioc;
4859 mptsas_add_fw_event(ioc, fw_event, delay);
4860 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004861}
4862
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304863/* Delete a volume when no longer listed in ioc pg2
4864 */
4865static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4866{
4867 struct scsi_device *sdev;
4868 int i;
4869
4870 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4871 if (!sdev)
4872 return;
4873 if (!ioc->raid_data.pIocPg2)
4874 goto out;
4875 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4876 goto out;
4877 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4878 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4879 goto release_sdev;
4880 out:
4881 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4882 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4883 scsi_remove_device(sdev);
4884 release_sdev:
4885 scsi_device_put(sdev);
4886}
4887
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004888static int
4889mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4890{
4891 struct Scsi_Host *sh;
4892 MPT_SCSI_HOST *hd;
4893 MPT_ADAPTER *ioc;
4894 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004895 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004896 int numSGE = 0;
4897 int scale;
4898 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004899 int error=0;
4900 int r;
4901
4902 r = mpt_attach(pdev,id);
4903 if (r)
4904 return r;
4905
4906 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304907 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004908 ioc->DoneCtx = mptsasDoneCtx;
4909 ioc->TaskCtx = mptsasTaskCtx;
4910 ioc->InternalCtx = mptsasInternalCtx;
4911
4912 /* Added sanity check on readiness of the MPT adapter.
4913 */
4914 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4915 printk(MYIOC_s_WARN_FMT
4916 "Skipping because it's not operational!\n",
4917 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004918 error = -ENODEV;
4919 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004920 }
4921
4922 if (!ioc->active) {
4923 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4924 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004925 error = -ENODEV;
4926 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004927 }
4928
4929 /* Sanity check - ensure at least 1 port is INITIATOR capable
4930 */
4931 ioc_cap = 0;
4932 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4933 if (ioc->pfacts[ii].ProtocolFlags &
4934 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4935 ioc_cap++;
4936 }
4937
4938 if (!ioc_cap) {
4939 printk(MYIOC_s_WARN_FMT
4940 "Skipping ioc=%p because SCSI Initiator mode "
4941 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004942 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004943 }
4944
4945 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4946 if (!sh) {
4947 printk(MYIOC_s_WARN_FMT
4948 "Unable to register controller with SCSI subsystem\n",
4949 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004950 error = -1;
4951 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004952 }
4953
4954 spin_lock_irqsave(&ioc->FreeQlock, flags);
4955
4956 /* Attach the SCSI Host to the IOC structure
4957 */
4958 ioc->sh = sh;
4959
4960 sh->io_port = 0;
4961 sh->n_io_port = 0;
4962 sh->irq = 0;
4963
4964 /* set 16 byte cdb's */
4965 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05304966 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
4967 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07004968 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004969 sh->transportt = mptsas_transport_template;
4970
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004971 /* Required entry.
4972 */
4973 sh->unique_id = ioc->id;
4974
4975 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004976 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004977 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004978 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004979 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004980
4981 /* Verify that we won't exceed the maximum
4982 * number of chain buffers
4983 * We can optimize: ZZ = req_sz/sizeof(SGE)
4984 * For 32bit SGE's:
4985 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4986 * + (req_sz - 64)/sizeof(SGE)
4987 * A slightly different algorithm is required for
4988 * 64bit SGEs.
4989 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304990 scale = ioc->req_sz/ioc->SGE_size;
4991 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004992 numSGE = (scale - 1) *
4993 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304994 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004995 } else {
4996 numSGE = 1 + (scale - 1) *
4997 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304998 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004999 }
5000
5001 if (numSGE < sh->sg_tablesize) {
5002 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305003 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005004 "Resetting sg_tablesize to %d from %d\n",
5005 ioc->name, numSGE, sh->sg_tablesize));
5006 sh->sg_tablesize = numSGE;
5007 }
5008
Eric Mooree7eae9f2007-09-29 10:15:59 -06005009 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005010 hd->ioc = ioc;
5011
5012 /* SCSI needs scsi_cmnd lookup table!
5013 * (with size equal to req_depth*PtrSz!)
5014 */
Eric Mooree8206382007-09-29 10:16:53 -06005015 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5016 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005017 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005018 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005019 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005020 }
Eric Mooree8206382007-09-29 10:16:53 -06005021 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005022
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305023 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005024 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005025
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005026 ioc->sas_data.ptClear = mpt_pt_clear;
5027
Eric Mooredf9e0622007-01-29 09:46:21 -07005028 hd->last_queue_full = 0;
5029 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305030 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5031 mutex_init(&ioc->sas_device_info_mutex);
5032
Eric Mooredf9e0622007-01-29 09:46:21 -07005033 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5034
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005035 if (ioc->sas_data.ptClear==1) {
5036 mptbase_sas_persist_operation(
5037 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5038 }
5039
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005040 error = scsi_add_host(sh, &ioc->pcidev->dev);
5041 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005042 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5043 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005044 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005045 }
5046
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305047 /* older firmware doesn't support expander events */
5048 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5049 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005050 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305051 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005052 return 0;
5053
Eric Moore547f9a22006-06-27 14:42:12 -06005054 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005055
5056 mptscsih_remove(pdev);
5057 return error;
5058}
5059
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305060void
5061mptsas_shutdown(struct pci_dev *pdev)
5062{
5063 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5064
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305065 mptsas_fw_event_off(ioc);
5066 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305067}
5068
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005069static void __devexit mptsas_remove(struct pci_dev *pdev)
5070{
5071 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5072 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005073 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005074
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305075 mptsas_shutdown(pdev);
5076
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305077 mptsas_del_device_components(ioc);
5078
Eric Mooreb506ade2007-01-29 09:45:37 -07005079 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005080 sas_remove_host(ioc->sh);
5081
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005082 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005083 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5084 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005085 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305086 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305087
Eric Moore547f9a22006-06-27 14:42:12 -06005088 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005089 kfree(p);
5090 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005091 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305092 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005093 mptscsih_remove(pdev);
5094}
5095
5096static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005097 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005098 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005099 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005100 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005101 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005102 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005103 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005104 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005105 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005106 PCI_ANY_ID, PCI_ANY_ID },
5107 {0} /* Terminating entry */
5108};
5109MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5110
5111
5112static struct pci_driver mptsas_driver = {
5113 .name = "mptsas",
5114 .id_table = mptsas_pci_table,
5115 .probe = mptsas_probe,
5116 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305117 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005118#ifdef CONFIG_PM
5119 .suspend = mptscsih_suspend,
5120 .resume = mptscsih_resume,
5121#endif
5122};
5123
5124static int __init
5125mptsas_init(void)
5126{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305127 int error;
5128
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005129 show_mptmod_ver(my_NAME, my_VERSION);
5130
5131 mptsas_transport_template =
5132 sas_attach_transport(&mptsas_transport_functions);
5133 if (!mptsas_transport_template)
5134 return -ENODEV;
5135
5136 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305137 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005138 mptsasInternalCtx =
5139 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005140 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305141 mptsasDeviceResetCtx =
5142 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005143
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305144 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5145 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005146
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305147 error = pci_register_driver(&mptsas_driver);
5148 if (error)
5149 sas_release_transport(mptsas_transport_template);
5150
5151 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005152}
5153
5154static void __exit
5155mptsas_exit(void)
5156{
5157 pci_unregister_driver(&mptsas_driver);
5158 sas_release_transport(mptsas_transport_template);
5159
5160 mpt_reset_deregister(mptsasDoneCtx);
5161 mpt_event_deregister(mptsasDoneCtx);
5162
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005163 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005164 mpt_deregister(mptsasInternalCtx);
5165 mpt_deregister(mptsasTaskCtx);
5166 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305167 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005168}
5169
5170module_init(mptsas_init);
5171module_exit(mptsas_exit);