blob: 1b7f550daebcbadf5c5e4bc2238deeaad4cfb7a7 [file] [log] [blame]
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001/*
2 * linux/drivers/message/fusion/mptsas.c
Prakash, Sathyaf36789e2007-08-14 16:22:54 +05303 * For use with LSI PCI chip/adapter(s)
4 * running LSI Fusion MPT (Message Passing Technology) firmware.
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005 *
Prakash, Sathyacddc0ab2008-05-21 00:56:41 +05306 * Copyright (c) 1999-2008 LSI Corporation
Eric Moore16d20102007-06-13 16:31:07 -06007 * (mailto:DL-MPTFusionLinux@lsi.com)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02008 */
9/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
10/*
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; version 2 of the License.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License for more details.
19
20 NO WARRANTY
21 THE PROGRAM IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OR
22 CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED INCLUDING, WITHOUT
23 LIMITATION, ANY WARRANTIES OR CONDITIONS OF TITLE, NON-INFRINGEMENT,
24 MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Each Recipient is
25 solely responsible for determining the appropriateness of using and
26 distributing the Program and assumes all risks associated with its
27 exercise of rights under this Agreement, including but not limited to
28 the risks and costs of program errors, damage to or loss of data,
29 programs or equipment, and unavailability or interruption of operations.
30
31 DISCLAIMER OF LIABILITY
32 NEITHER RECIPIENT NOR ANY CONTRIBUTORS SHALL HAVE ANY LIABILITY FOR ANY
33 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
34 DAMAGES (INCLUDING WITHOUT LIMITATION LOST PROFITS), HOWEVER CAUSED AND
35 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
36 TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
37 USE OR DISTRIBUTION OF THE PROGRAM OR THE EXERCISE OF ANY RIGHTS GRANTED
38 HEREUNDER, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGES
39
40 You should have received a copy of the GNU General Public License
41 along with this program; if not, write to the Free Software
42 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
43*/
44/*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=*/
45
46#include <linux/module.h>
47#include <linux/kernel.h>
48#include <linux/init.h>
49#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080050#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020051#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060052#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020053
Eric Moore547f9a22006-06-27 14:42:12 -060054#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020055#include <scsi/scsi_cmnd.h>
56#include <scsi/scsi_device.h>
57#include <scsi/scsi_host.h>
58#include <scsi/scsi_transport_sas.h>
Eric Moore547f9a22006-06-27 14:42:12 -060059#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020060
61#include "mptbase.h"
62#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053063#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020064
65
66#define my_NAME "Fusion MPT SAS Host driver"
67#define my_VERSION MPT_LINUX_VERSION_COMMON
68#define MYNAM "mptsas"
69
James Bottomleye8bf3942006-07-11 17:49:34 -040070/*
71 * Reserved channel for integrated raid
72 */
73#define MPTSAS_RAID_CHANNEL 1
74
Kashyap, Desai4b976502009-08-05 12:52:03 +053075#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020076MODULE_AUTHOR(MODULEAUTHOR);
77MODULE_DESCRIPTION(my_NAME);
78MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070079MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020080
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081static int mpt_pt_clear;
82module_param(mpt_pt_clear, int, 0);
83MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060084 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020085 "(default=MPTSCSIH_PT_CLEAR=0)");
86
Eric Moore793955f2007-01-29 09:42:20 -070087/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
88#define MPTSAS_MAX_LUN (16895)
89static int max_lun = MPTSAS_MAX_LUN;
90module_param(max_lun, int, 0);
91MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
92
Prakash, Sathyaf606f572007-08-14 16:12:53 +053093static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
94static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
96static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053097static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020098
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +053099static void mptsas_firmware_event_work(struct work_struct *work);
100static void mptsas_send_sas_event(struct fw_event_work *fw_event);
101static void mptsas_send_raid_event(struct fw_event_work *fw_event);
102static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
103static void mptsas_parse_device_info(struct sas_identify *identify,
104 struct mptsas_devinfo *device_info);
105static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
106 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
107static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
108 (MPT_ADAPTER *ioc, u64 sas_address);
109static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
110 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
111static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
112 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
113static int mptsas_add_end_device(MPT_ADAPTER *ioc,
114 struct mptsas_phyinfo *phy_info);
115static void mptsas_del_end_device(MPT_ADAPTER *ioc,
116 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530117static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
118static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
119 (MPT_ADAPTER *ioc, u64 sas_address);
120static void mptsas_expander_delete(MPT_ADAPTER *ioc,
121 struct mptsas_portinfo *port_info, u8 force);
122static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530123static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
124static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530125static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530126static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530127static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200128
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530129static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
130 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200131{
Eric Moore29dd3602007-09-14 18:46:51 -0600132 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
133 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
135 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
137 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
139 ioc->name, phy_data->Port));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
141 ioc->name, phy_data->PortFlags));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
143 ioc->name, phy_data->PhyFlags));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
145 ioc->name, phy_data->NegotiatedLinkRate));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
147 "Controller PHY Device Info=0x%X\n", ioc->name,
148 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
149 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
150 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200151}
152
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530153static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200154{
155 __le64 sas_address;
156
157 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
158
Eric Moore29dd3602007-09-14 18:46:51 -0600159 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
160 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
162 "Attached Device Handle=0x%X\n", ioc->name,
163 le16_to_cpu(pg0->AttachedDevHandle)));
164 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
165 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
166 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
167 "Attached PHY Identifier=0x%X\n", ioc->name,
168 pg0->AttachedPhyIdentifier));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
170 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
172 ioc->name, pg0->ProgrammedLinkRate));
173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
174 ioc->name, pg0->ChangeCount));
175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
176 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200177}
178
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530179static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200180{
Eric Moore29dd3602007-09-14 18:46:51 -0600181 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
182 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
184 ioc->name, pg1->InvalidDwordCount));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
186 "Running Disparity Error Count=0x%x\n", ioc->name,
187 pg1->RunningDisparityErrorCount));
188 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
189 "Loss Dword Synch Count=0x%x\n", ioc->name,
190 pg1->LossDwordSynchCount));
191 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
192 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
193 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200194}
195
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530196static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200197{
198 __le64 sas_address;
199
200 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
201
Eric Moore29dd3602007-09-14 18:46:51 -0600202 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
203 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
205 ioc->name, le16_to_cpu(pg0->DevHandle)));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
207 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
209 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
211 ioc->name, le16_to_cpu(pg0->Slot)));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
213 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
215 ioc->name, pg0->TargetID));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
217 ioc->name, pg0->Bus));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
219 ioc->name, pg0->PhyNum));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
221 ioc->name, le16_to_cpu(pg0->AccessStatus)));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
223 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
224 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
225 ioc->name, le16_to_cpu(pg0->Flags)));
226 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
227 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200228}
229
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530230static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200231{
Eric Moore29dd3602007-09-14 18:46:51 -0600232 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
233 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
235 ioc->name, pg1->PhysicalPort));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
237 ioc->name, pg1->PhyIdentifier));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
239 ioc->name, pg1->NegotiatedLinkRate));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
241 ioc->name, pg1->ProgrammedLinkRate));
242 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
243 ioc->name, pg1->HwLinkRate));
244 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
245 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
246 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
247 "Attached Device Handle=0x%X\n\n", ioc->name,
248 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200249}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200250
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530251/* inhibit sas firmware event handling */
252static void
253mptsas_fw_event_off(MPT_ADAPTER *ioc)
254{
255 unsigned long flags;
256
257 spin_lock_irqsave(&ioc->fw_event_lock, flags);
258 ioc->fw_events_off = 1;
259 ioc->sas_discovery_quiesce_io = 0;
260 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
261
262}
263
264/* enable sas firmware event handling */
265static void
266mptsas_fw_event_on(MPT_ADAPTER *ioc)
267{
268 unsigned long flags;
269
270 spin_lock_irqsave(&ioc->fw_event_lock, flags);
271 ioc->fw_events_off = 0;
272 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
273}
274
275/* queue a sas firmware event */
276static void
277mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
278 unsigned long delay)
279{
280 unsigned long flags;
281
282 spin_lock_irqsave(&ioc->fw_event_lock, flags);
283 list_add_tail(&fw_event->list, &ioc->fw_event_list);
284 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
285 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
286 ioc->name, __func__, fw_event));
287 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
288 delay);
289 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
290}
291
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530292/* requeue a sas firmware event */
293static void
294mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
295 unsigned long delay)
296{
297 unsigned long flags;
298 spin_lock_irqsave(&ioc->fw_event_lock, flags);
299 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
300 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
301 fw_event->retries++;
302 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
303 msecs_to_jiffies(delay));
304 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
305}
306
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530307/* free memory assoicated to a sas firmware event */
308static void
309mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
310{
311 unsigned long flags;
312
313 spin_lock_irqsave(&ioc->fw_event_lock, flags);
314 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
315 ioc->name, __func__, fw_event));
316 list_del(&fw_event->list);
317 kfree(fw_event);
318 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
319}
320
321/* walk the firmware event queue, and either stop or wait for
322 * outstanding events to complete */
323static void
324mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
325{
326 struct fw_event_work *fw_event, *next;
327 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-05-29 16:47:26 +0530350 }
Kashyap, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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, Desai3eb0822c2009-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
1078/**
1079 * mptsas_target_reset_queue
1080 *
1081 * Receive request for TARGET_RESET after recieving an firmware
1082 * event NOT_RESPONDING_EVENT, then put command in link list
1083 * and queue if task_queue already in use.
1084 *
1085 * @ioc
1086 * @sas_event_data
1087 *
1088 **/
1089static void
1090mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1091 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1092{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001093 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001094 VirtTarget *vtarget = NULL;
1095 struct mptsas_target_reset_event *target_reset_list;
1096 u8 id, channel;
1097
1098 id = sas_event_data->TargetID;
1099 channel = sas_event_data->Bus;
1100
1101 if (!(vtarget = mptsas_find_vtarget(ioc, channel, id)))
1102 return;
1103
1104 vtarget->deleted = 1; /* block IO */
1105
Kashyap, Desai2f187862009-05-29 16:52:37 +05301106 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001107 GFP_ATOMIC);
1108 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301109 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1110 "%s, failed to allocate mem @%d..!!\n",
1111 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001112 return;
1113 }
1114
1115 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1116 sizeof(*sas_event_data));
1117 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1118
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301119 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001120
1121 if (mptsas_target_reset(ioc, channel, id)) {
1122 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001123 }
1124}
1125
1126/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001127 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301128 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001129 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001130 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1131 * queue to finish off removing device from upper layers. then send next
1132 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001133 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301134static int
1135mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001136{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001137 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001138 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001139 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301140 struct mptsas_target_reset_event *target_reset_list;
1141 SCSITaskMgmtReply_t *pScsiTmReply;
1142
1143 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1144 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1145
1146 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1147 if (pScsiTmReply) {
1148 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1149 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1150 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1151 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1152 "term_cmnds = %d\n", ioc->name,
1153 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1154 pScsiTmReply->TaskType,
1155 le16_to_cpu(pScsiTmReply->IOCStatus),
1156 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1157 pScsiTmReply->ResponseCode,
1158 le32_to_cpu(pScsiTmReply->TerminationCount)));
1159
1160 if (pScsiTmReply->ResponseCode)
1161 mptscsih_taskmgmt_response_code(ioc,
1162 pScsiTmReply->ResponseCode);
1163 }
1164
1165 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1166 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1167 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1168 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1169 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1170 memcpy(ioc->taskmgmt_cmds.reply, mr,
1171 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1172 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1173 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1174 complete(&ioc->taskmgmt_cmds.done);
1175 return 1;
1176 }
1177 return 0;
1178 }
1179
1180 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001181
1182 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301183 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001184
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301185 target_reset_list = list_entry(head->next,
1186 struct mptsas_target_reset_event, list);
1187
1188 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1189 "TaskMgmt: completed (%d seconds)\n",
1190 ioc->name, jiffies_to_msecs(jiffies -
1191 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001192
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301193 id = pScsiTmReply->TargetID;
1194 channel = pScsiTmReply->Bus;
1195 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001196
1197 /*
1198 * retry target reset
1199 */
1200 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301201 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001202 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301203 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001204 }
1205
1206 /*
1207 * enable work queue to remove device from upper layers
1208 */
1209 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301210 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1211 mptsas_queue_device_delete(ioc,
1212 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301213
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301214
Eric Mooredf9e0622007-01-29 09:46:21 -07001215 /*
1216 * issue target reset to next device in the queue
1217 */
1218
1219 head = &hd->target_reset_list;
1220 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301221 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001222
1223 target_reset_list = list_entry(head->next, struct mptsas_target_reset_event,
1224 list);
1225
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301226 id = target_reset_list->sas_event_data.TargetID;
1227 channel = target_reset_list->sas_event_data.Bus;
1228 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001229
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301230 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001231 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001232
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301233 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001234}
1235
1236/**
1237 * mptscsih_ioc_reset
1238 *
1239 * @ioc
1240 * @reset_phase
1241 *
1242 **/
1243static int
1244mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1245{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001246 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001247 int rc;
1248
1249 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301250 if ((ioc->bus_type != SAS) || (!rc))
1251 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001252
Eric Mooree7eae9f2007-09-29 10:15:59 -06001253 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001254 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001255 goto out;
1256
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301257 switch (reset_phase) {
1258 case MPT_IOC_SETUP_RESET:
1259 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1260 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1261 mptsas_fw_event_off(ioc);
1262 break;
1263 case MPT_IOC_PRE_RESET:
1264 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1265 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1266 break;
1267 case MPT_IOC_POST_RESET:
1268 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1269 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1270 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1271 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1272 complete(&ioc->sas_mgmt.done);
1273 }
1274 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301275 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301276 break;
1277 default:
1278 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001279 }
1280
1281 out:
1282 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001283}
1284
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301285
1286/**
1287 * enum device_state -
1288 * @DEVICE_RETRY: need to retry the TUR
1289 * @DEVICE_ERROR: TUR return error, don't add device
1290 * @DEVICE_READY: device can be added
1291 *
1292 */
1293enum device_state{
1294 DEVICE_RETRY,
1295 DEVICE_ERROR,
1296 DEVICE_READY,
1297};
1298
Christoph Hellwige3094442006-02-16 13:25:36 +01001299static int
Moore, Eric52435432006-03-14 09:14:15 -07001300mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001301 u32 form, u32 form_specific)
1302{
1303 ConfigExtendedPageHeader_t hdr;
1304 CONFIGPARMS cfg;
1305 SasEnclosurePage0_t *buffer;
1306 dma_addr_t dma_handle;
1307 int error;
1308 __le64 le_identifier;
1309
1310 memset(&hdr, 0, sizeof(hdr));
1311 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1312 hdr.PageNumber = 0;
1313 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1314 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1315
1316 cfg.cfghdr.ehdr = &hdr;
1317 cfg.physAddr = -1;
1318 cfg.pageAddr = form + form_specific;
1319 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1320 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301321 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001322
1323 error = mpt_config(ioc, &cfg);
1324 if (error)
1325 goto out;
1326 if (!hdr.ExtPageLength) {
1327 error = -ENXIO;
1328 goto out;
1329 }
1330
1331 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1332 &dma_handle);
1333 if (!buffer) {
1334 error = -ENOMEM;
1335 goto out;
1336 }
1337
1338 cfg.physAddr = dma_handle;
1339 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1340
1341 error = mpt_config(ioc, &cfg);
1342 if (error)
1343 goto out_free_consistent;
1344
1345 /* save config data */
1346 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1347 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1348 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1349 enclosure->flags = le16_to_cpu(buffer->Flags);
1350 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1351 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1352 enclosure->start_id = buffer->StartTargetID;
1353 enclosure->start_channel = buffer->StartBus;
1354 enclosure->sep_id = buffer->SEPTargetID;
1355 enclosure->sep_channel = buffer->SEPBus;
1356
1357 out_free_consistent:
1358 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1359 buffer, dma_handle);
1360 out:
1361 return error;
1362}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001363
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301364/**
1365 * mptsas_add_end_device - report a new end device to sas transport layer
1366 * @ioc: Pointer to MPT_ADAPTER structure
1367 * @phy_info: decribes attached device
1368 *
1369 * return (0) success (1) failure
1370 *
1371 **/
1372static int
1373mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1374{
1375 struct sas_rphy *rphy;
1376 struct sas_port *port;
1377 struct sas_identify identify;
1378 char *ds = NULL;
1379 u8 fw_id;
1380
1381 if (!phy_info) {
1382 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1383 "%s: exit at line=%d\n", ioc->name,
1384 __func__, __LINE__));
1385 return 1;
1386 }
1387
1388 fw_id = phy_info->attached.id;
1389
1390 if (mptsas_get_rphy(phy_info)) {
1391 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1392 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1393 __func__, fw_id, __LINE__));
1394 return 2;
1395 }
1396
1397 port = mptsas_get_port(phy_info);
1398 if (!port) {
1399 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1400 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1401 __func__, fw_id, __LINE__));
1402 return 3;
1403 }
1404
1405 if (phy_info->attached.device_info &
1406 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1407 ds = "ssp";
1408 if (phy_info->attached.device_info &
1409 MPI_SAS_DEVICE_INFO_STP_TARGET)
1410 ds = "stp";
1411 if (phy_info->attached.device_info &
1412 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1413 ds = "sata";
1414
1415 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1416 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1417 phy_info->attached.channel, phy_info->attached.id,
1418 phy_info->attached.phy_id, (unsigned long long)
1419 phy_info->attached.sas_address);
1420
1421 mptsas_parse_device_info(&identify, &phy_info->attached);
1422 rphy = sas_end_device_alloc(port);
1423 if (!rphy) {
1424 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1425 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1426 __func__, fw_id, __LINE__));
1427 return 5; /* non-fatal: an rphy can be added later */
1428 }
1429
1430 rphy->identify = identify;
1431 if (sas_rphy_add(rphy)) {
1432 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1433 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1434 __func__, fw_id, __LINE__));
1435 sas_rphy_free(rphy);
1436 return 6;
1437 }
1438 mptsas_set_rphy(ioc, phy_info, rphy);
1439 return 0;
1440}
1441
1442/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001443 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301444 * @ioc: Pointer to MPT_ADAPTER structure
1445 * @phy_info: decribes attached device
1446 *
1447 **/
1448static void
1449mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1450{
1451 struct sas_rphy *rphy;
1452 struct sas_port *port;
1453 struct mptsas_portinfo *port_info;
1454 struct mptsas_phyinfo *phy_info_parent;
1455 int i;
1456 char *ds = NULL;
1457 u8 fw_id;
1458 u64 sas_address;
1459
1460 if (!phy_info)
1461 return;
1462
1463 fw_id = phy_info->attached.id;
1464 sas_address = phy_info->attached.sas_address;
1465
1466 if (!phy_info->port_details) {
1467 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1468 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1469 __func__, fw_id, __LINE__));
1470 return;
1471 }
1472 rphy = mptsas_get_rphy(phy_info);
1473 if (!rphy) {
1474 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1475 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1476 __func__, fw_id, __LINE__));
1477 return;
1478 }
1479
1480 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1481 || phy_info->attached.device_info
1482 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1483 || phy_info->attached.device_info
1484 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1485 ds = "initiator";
1486 if (phy_info->attached.device_info &
1487 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1488 ds = "ssp";
1489 if (phy_info->attached.device_info &
1490 MPI_SAS_DEVICE_INFO_STP_TARGET)
1491 ds = "stp";
1492 if (phy_info->attached.device_info &
1493 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1494 ds = "sata";
1495
1496 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1497 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1498 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1499 phy_info->attached.id, phy_info->attached.phy_id,
1500 (unsigned long long) sas_address);
1501
1502 port = mptsas_get_port(phy_info);
1503 if (!port) {
1504 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1505 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1506 __func__, fw_id, __LINE__));
1507 return;
1508 }
1509 port_info = phy_info->portinfo;
1510 phy_info_parent = port_info->phy_info;
1511 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1512 if (!phy_info_parent->phy)
1513 continue;
1514 if (phy_info_parent->attached.sas_address !=
1515 sas_address)
1516 continue;
1517 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1518 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1519 ioc->name, phy_info_parent->phy_id,
1520 phy_info_parent->phy);
1521 sas_port_delete_phy(port, phy_info_parent->phy);
1522 }
1523
1524 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1525 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1526 port->port_identifier, (unsigned long long)sas_address);
1527 sas_port_delete(port);
1528 mptsas_set_port(ioc, phy_info, NULL);
1529 mptsas_port_delete(ioc, phy_info->port_details);
1530}
1531
1532struct mptsas_phyinfo *
1533mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1534 struct mptsas_devinfo *sas_device)
1535{
1536 struct mptsas_phyinfo *phy_info;
1537 struct mptsas_portinfo *port_info;
1538 int i;
1539
1540 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1541 sas_device->sas_address);
1542 if (!phy_info)
1543 goto out;
1544 port_info = phy_info->portinfo;
1545 if (!port_info)
1546 goto out;
1547 mutex_lock(&ioc->sas_topology_mutex);
1548 for (i = 0; i < port_info->num_phys; i++) {
1549 if (port_info->phy_info[i].attached.sas_address !=
1550 sas_device->sas_address)
1551 continue;
1552 port_info->phy_info[i].attached.channel = sas_device->channel;
1553 port_info->phy_info[i].attached.id = sas_device->id;
1554 port_info->phy_info[i].attached.sas_address =
1555 sas_device->sas_address;
1556 port_info->phy_info[i].attached.handle = sas_device->handle;
1557 port_info->phy_info[i].attached.handle_parent =
1558 sas_device->handle_parent;
1559 port_info->phy_info[i].attached.handle_enclosure =
1560 sas_device->handle_enclosure;
1561 }
1562 mutex_unlock(&ioc->sas_topology_mutex);
1563 out:
1564 return phy_info;
1565}
1566
1567/**
1568 * mptsas_firmware_event_work - work thread for processing fw events
1569 * @work: work queue payload containing info describing the event
1570 * Context: user
1571 *
1572 */
1573static void
1574mptsas_firmware_event_work(struct work_struct *work)
1575{
1576 struct fw_event_work *fw_event =
1577 container_of(work, struct fw_event_work, work.work);
1578 MPT_ADAPTER *ioc = fw_event->ioc;
1579
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301580 /* special rescan topology handling */
1581 if (fw_event->event == -1) {
1582 if (ioc->in_rescan) {
1583 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1584 "%s: rescan ignored as it is in progress\n",
1585 ioc->name, __func__));
1586 return;
1587 }
1588 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1589 "reset\n", ioc->name, __func__));
1590 ioc->in_rescan = 1;
1591 mptsas_not_responding_devices(ioc);
1592 mptsas_scan_sas_topology(ioc);
1593 ioc->in_rescan = 0;
1594 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301595 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301596 return;
1597 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301598
1599 /* events handling turned off during host reset */
1600 if (ioc->fw_events_off) {
1601 mptsas_free_fw_event(ioc, fw_event);
1602 return;
1603 }
1604
1605 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1606 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1607 (fw_event->event & 0xFF)));
1608
1609 switch (fw_event->event) {
1610 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1611 mptsas_send_sas_event(fw_event);
1612 break;
1613 case MPI_EVENT_INTEGRATED_RAID:
1614 mptsas_send_raid_event(fw_event);
1615 break;
1616 case MPI_EVENT_IR2:
1617 mptsas_send_ir2_event(fw_event);
1618 break;
1619 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1620 mptbase_sas_persist_operation(ioc,
1621 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1622 mptsas_free_fw_event(ioc, fw_event);
1623 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301624 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1625 mptsas_broadcast_primative_work(fw_event);
1626 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301627 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1628 mptsas_send_expander_event(fw_event);
1629 break;
1630 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1631 mptsas_send_link_status_event(fw_event);
1632 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301633 case MPI_EVENT_QUEUE_FULL:
1634 mptsas_handle_queue_full_event(fw_event);
1635 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301636 }
1637}
1638
1639
1640
James Bottomleyf013db32006-03-18 14:54:36 -06001641static int
1642mptsas_slave_configure(struct scsi_device *sdev)
1643{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301644 struct Scsi_Host *host = sdev->host;
1645 MPT_SCSI_HOST *hd = shost_priv(host);
1646 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301647 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001648
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301649 if (vdevice->vtarget->deleted) {
1650 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1651 vdevice->vtarget->deleted = 0;
1652 }
1653
1654 /*
1655 * RAID volumes placed beyond the last expected port.
1656 * Ignore sending sas mode pages in that case..
1657 */
1658 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1659 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001660 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301661 }
James Bottomleyf013db32006-03-18 14:54:36 -06001662
James Bottomleye8bf3942006-07-11 17:49:34 -04001663 sas_read_port_mode_page(sdev);
1664
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301665 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1666
James Bottomleye8bf3942006-07-11 17:49:34 -04001667 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001668 return mptscsih_slave_configure(sdev);
1669}
1670
Eric Moore547f9a22006-06-27 14:42:12 -06001671static int
1672mptsas_target_alloc(struct scsi_target *starget)
1673{
1674 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001675 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001676 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001677 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001678 struct sas_rphy *rphy;
1679 struct mptsas_portinfo *p;
1680 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001681 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001682
1683 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1684 if (!vtarget)
1685 return -ENOMEM;
1686
1687 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001688 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001689 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1690 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001691 channel = 0;
1692
Eric Moore793955f2007-01-29 09:42:20 -07001693 /*
1694 * RAID volumes placed beyond the last expected port.
1695 */
1696 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301697 if (!ioc->raid_data.pIocPg2) {
1698 kfree(vtarget);
1699 return -ENXIO;
1700 }
1701 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1702 if (id == ioc->raid_data.pIocPg2->
1703 RaidVolume[i].VolumeID) {
1704 channel = ioc->raid_data.pIocPg2->
1705 RaidVolume[i].VolumeBus;
1706 }
1707 }
1708 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001709 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001710 }
Eric Moore547f9a22006-06-27 14:42:12 -06001711
1712 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001713 mutex_lock(&ioc->sas_topology_mutex);
1714 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001715 for (i = 0; i < p->num_phys; i++) {
1716 if (p->phy_info[i].attached.sas_address !=
1717 rphy->identify.sas_address)
1718 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001719 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001720 channel = p->phy_info[i].attached.channel;
1721 mptsas_set_starget(&p->phy_info[i], starget);
1722
1723 /*
1724 * Exposing hidden raid components
1725 */
Eric Mooree80b0022007-09-14 18:49:03 -06001726 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1727 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001728 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001729 vtarget->tflags |=
1730 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001731 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001732 }
Eric Mooree80b0022007-09-14 18:49:03 -06001733 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001734 goto out;
1735 }
1736 }
Eric Mooree80b0022007-09-14 18:49:03 -06001737 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001738
1739 kfree(vtarget);
1740 return -ENXIO;
1741
1742 out:
Eric Moore793955f2007-01-29 09:42:20 -07001743 vtarget->id = id;
1744 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001745 starget->hostdata = vtarget;
1746 return 0;
1747}
1748
1749static void
1750mptsas_target_destroy(struct scsi_target *starget)
1751{
1752 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001753 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001754 struct sas_rphy *rphy;
1755 struct mptsas_portinfo *p;
1756 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301757 MPT_ADAPTER *ioc = hd->ioc;
1758 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001759
1760 if (!starget->hostdata)
1761 return;
1762
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301763 vtarget = starget->hostdata;
1764
Kashyap, Desai57e98512009-05-29 16:55:09 +05301765 mptsas_del_device_component_by_os(ioc, starget->channel,
1766 starget->id);
1767
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301768
James Bottomleye8bf3942006-07-11 17:49:34 -04001769 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001770 goto out;
1771
1772 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001773 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001774 for (i = 0; i < p->num_phys; i++) {
1775 if (p->phy_info[i].attached.sas_address !=
1776 rphy->identify.sas_address)
1777 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301778
1779 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1780 "delete device: fw_channel %d, fw_id %d, phy %d, "
1781 "sas_addr 0x%llx\n", ioc->name,
1782 p->phy_info[i].attached.channel,
1783 p->phy_info[i].attached.id,
1784 p->phy_info[i].attached.phy_id, (unsigned long long)
1785 p->phy_info[i].attached.sas_address);
1786
Eric Moore547f9a22006-06-27 14:42:12 -06001787 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001788 }
1789 }
1790
1791 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301792 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001793 kfree(starget->hostdata);
1794 starget->hostdata = NULL;
1795}
1796
1797
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001798static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001799mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001800{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001801 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001802 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001803 struct sas_rphy *rphy;
1804 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001805 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001806 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001807 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001808 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001809
Eric Moorea69de502007-09-14 18:48:19 -06001810 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1811 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001812 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001813 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001814 return -ENOMEM;
1815 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001816 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001817 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001818
James Bottomleye8bf3942006-07-11 17:49:34 -04001819 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001820 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001821
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001822 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001823 mutex_lock(&ioc->sas_topology_mutex);
1824 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001825 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001826 if (p->phy_info[i].attached.sas_address !=
1827 rphy->identify.sas_address)
1828 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001829 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001830 /*
1831 * Exposing hidden raid components
1832 */
Eric Mooree80b0022007-09-14 18:49:03 -06001833 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001834 p->phy_info[i].attached.channel,
1835 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001836 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001837 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001838 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001839 }
1840 }
Eric Mooree80b0022007-09-14 18:49:03 -06001841 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001842
Eric Moorea69de502007-09-14 18:48:19 -06001843 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001844 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001845
1846 out:
Eric Moorea69de502007-09-14 18:48:19 -06001847 vdevice->vtarget->num_luns++;
1848 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001849 return 0;
1850}
1851
Eric Moore547f9a22006-06-27 14:42:12 -06001852static int
1853mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001854{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301855 MPT_SCSI_HOST *hd;
1856 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001857 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001858
Eric Moorea69de502007-09-14 18:48:19 -06001859 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001860 SCpnt->result = DID_NO_CONNECT << 16;
1861 done(SCpnt);
1862 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001863 }
Eric Moore547f9a22006-06-27 14:42:12 -06001864
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301865 hd = shost_priv(SCpnt->device->host);
1866 ioc = hd->ioc;
1867
1868 if (ioc->sas_discovery_quiesce_io)
1869 return SCSI_MLQUEUE_HOST_BUSY;
1870
Eric Moore793955f2007-01-29 09:42:20 -07001871// scsi_print_command(SCpnt);
1872
Eric Moore547f9a22006-06-27 14:42:12 -06001873 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001874}
1875
Eric Moore547f9a22006-06-27 14:42:12 -06001876
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001877static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001878 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001879 .proc_name = "mptsas",
1880 .proc_info = mptscsih_proc_info,
1881 .name = "MPT SPI Host",
1882 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001883 .queuecommand = mptsas_qcmd,
1884 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001885 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001886 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001887 .target_destroy = mptsas_target_destroy,
1888 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001889 .change_queue_depth = mptscsih_change_queue_depth,
1890 .eh_abort_handler = mptscsih_abort,
1891 .eh_device_reset_handler = mptscsih_dev_reset,
1892 .eh_bus_reset_handler = mptscsih_bus_reset,
1893 .eh_host_reset_handler = mptscsih_host_reset,
1894 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301895 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001896 .this_id = -1,
1897 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1898 .max_sectors = 8192,
1899 .cmd_per_lun = 7,
1900 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301901 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001902};
1903
Christoph Hellwigb5141122005-10-28 22:07:41 +02001904static int mptsas_get_linkerrors(struct sas_phy *phy)
1905{
1906 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1907 ConfigExtendedPageHeader_t hdr;
1908 CONFIGPARMS cfg;
1909 SasPhyPage1_t *buffer;
1910 dma_addr_t dma_handle;
1911 int error;
1912
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001913 /* FIXME: only have link errors on local phys */
1914 if (!scsi_is_sas_phy_local(phy))
1915 return -EINVAL;
1916
Christoph Hellwigb5141122005-10-28 22:07:41 +02001917 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1918 hdr.ExtPageLength = 0;
1919 hdr.PageNumber = 1 /* page number 1*/;
1920 hdr.Reserved1 = 0;
1921 hdr.Reserved2 = 0;
1922 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1923 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1924
1925 cfg.cfghdr.ehdr = &hdr;
1926 cfg.physAddr = -1;
1927 cfg.pageAddr = phy->identify.phy_identifier;
1928 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1929 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301930 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02001931
1932 error = mpt_config(ioc, &cfg);
1933 if (error)
1934 return error;
1935 if (!hdr.ExtPageLength)
1936 return -ENXIO;
1937
1938 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1939 &dma_handle);
1940 if (!buffer)
1941 return -ENOMEM;
1942
1943 cfg.physAddr = dma_handle;
1944 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1945
1946 error = mpt_config(ioc, &cfg);
1947 if (error)
1948 goto out_free_consistent;
1949
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301950 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001951
1952 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1953 phy->running_disparity_error_count =
1954 le32_to_cpu(buffer->RunningDisparityErrorCount);
1955 phy->loss_of_dword_sync_count =
1956 le32_to_cpu(buffer->LossDwordSynchCount);
1957 phy->phy_reset_problem_count =
1958 le32_to_cpu(buffer->PhyResetProblemCount);
1959
1960 out_free_consistent:
1961 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1962 buffer, dma_handle);
1963 return error;
1964}
1965
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001966static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
1967 MPT_FRAME_HDR *reply)
1968{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301969 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001970 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05301971 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001972 memcpy(ioc->sas_mgmt.reply, reply,
1973 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
1974 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05301975
1976 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1977 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
1978 complete(&ioc->sas_mgmt.done);
1979 return 1;
1980 }
1981 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001982}
1983
1984static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
1985{
1986 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1987 SasIoUnitControlRequest_t *req;
1988 SasIoUnitControlReply_t *reply;
1989 MPT_FRAME_HDR *mf;
1990 MPIHeader_t *hdr;
1991 unsigned long timeleft;
1992 int error = -ERESTARTSYS;
1993
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001994 /* FIXME: fusion doesn't allow non-local phy reset */
1995 if (!scsi_is_sas_phy_local(phy))
1996 return -EINVAL;
1997
Christoph Hellwigda4fa652005-10-19 20:01:42 +02001998 /* not implemented for expanders */
1999 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2000 return -ENXIO;
2001
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002002 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002003 goto out;
2004
2005 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2006 if (!mf) {
2007 error = -ENOMEM;
2008 goto out_unlock;
2009 }
2010
2011 hdr = (MPIHeader_t *) mf;
2012 req = (SasIoUnitControlRequest_t *)mf;
2013 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2014 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2015 req->MsgContext = hdr->MsgContext;
2016 req->Operation = hard_reset ?
2017 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2018 req->PhyNum = phy->identify.phy_identifier;
2019
Kashyap, Desai2f187862009-05-29 16:52:37 +05302020 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002021 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2022
2023 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2024 10 * HZ);
2025 if (!timeleft) {
2026 /* On timeout reset the board */
2027 mpt_free_msg_frame(ioc, mf);
2028 mpt_HardResetHandler(ioc, CAN_SLEEP);
2029 error = -ETIMEDOUT;
2030 goto out_unlock;
2031 }
2032
2033 /* a reply frame is expected */
2034 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302035 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002036 error = -ENXIO;
2037 goto out_unlock;
2038 }
2039
2040 /* process the completed Reply Message Frame */
2041 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2042 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002043 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002044 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002045 error = -ENXIO;
2046 goto out_unlock;
2047 }
2048
2049 error = 0;
2050
2051 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302052 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002053 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002054 out:
2055 return error;
2056}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002057
Christoph Hellwige3094442006-02-16 13:25:36 +01002058static int
2059mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2060{
2061 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2062 int i, error;
2063 struct mptsas_portinfo *p;
2064 struct mptsas_enclosure enclosure_info;
2065 u64 enclosure_handle;
2066
2067 mutex_lock(&ioc->sas_topology_mutex);
2068 list_for_each_entry(p, &ioc->sas_topology, list) {
2069 for (i = 0; i < p->num_phys; i++) {
2070 if (p->phy_info[i].attached.sas_address ==
2071 rphy->identify.sas_address) {
2072 enclosure_handle = p->phy_info[i].
2073 attached.handle_enclosure;
2074 goto found_info;
2075 }
2076 }
2077 }
2078 mutex_unlock(&ioc->sas_topology_mutex);
2079 return -ENXIO;
2080
2081 found_info:
2082 mutex_unlock(&ioc->sas_topology_mutex);
2083 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002084 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002085 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2086 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2087 if (!error)
2088 *identifier = enclosure_info.enclosure_logical_id;
2089 return error;
2090}
2091
2092static int
2093mptsas_get_bay_identifier(struct sas_rphy *rphy)
2094{
2095 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2096 struct mptsas_portinfo *p;
2097 int i, rc;
2098
2099 mutex_lock(&ioc->sas_topology_mutex);
2100 list_for_each_entry(p, &ioc->sas_topology, list) {
2101 for (i = 0; i < p->num_phys; i++) {
2102 if (p->phy_info[i].attached.sas_address ==
2103 rphy->identify.sas_address) {
2104 rc = p->phy_info[i].attached.slot;
2105 goto out;
2106 }
2107 }
2108 }
2109 rc = -ENXIO;
2110 out:
2111 mutex_unlock(&ioc->sas_topology_mutex);
2112 return rc;
2113}
2114
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002115static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2116 struct request *req)
2117{
2118 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2119 MPT_FRAME_HDR *mf;
2120 SmpPassthroughRequest_t *smpreq;
2121 struct request *rsp = req->next_rq;
2122 int ret;
2123 int flagsLength;
2124 unsigned long timeleft;
2125 char *psge;
2126 dma_addr_t dma_addr_in = 0;
2127 dma_addr_t dma_addr_out = 0;
2128 u64 sas_address = 0;
2129
2130 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002131 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002132 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002133 return -EINVAL;
2134 }
2135
2136 /* do we need to support multiple segments? */
2137 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002138 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002139 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2140 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002141 return -EINVAL;
2142 }
2143
2144 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2145 if (ret)
2146 goto out;
2147
2148 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2149 if (!mf) {
2150 ret = -ENOMEM;
2151 goto out_unlock;
2152 }
2153
2154 smpreq = (SmpPassthroughRequest_t *)mf;
2155 memset(smpreq, 0, sizeof(*smpreq));
2156
Tejun Heob0790412009-05-07 22:24:42 +09002157 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002158 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2159
2160 if (rphy)
2161 sas_address = rphy->identify.sas_address;
2162 else {
2163 struct mptsas_portinfo *port_info;
2164
2165 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302166 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002167 if (port_info && port_info->phy_info)
2168 sas_address =
2169 port_info->phy_info[0].phy->identify.sas_address;
2170 mutex_unlock(&ioc->sas_topology_mutex);
2171 }
2172
2173 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2174
2175 psge = (char *)
2176 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2177
2178 /* request */
2179 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2180 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302181 MPI_SGE_FLAGS_DIRECTION)
2182 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002183 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002184
2185 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002186 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002187 if (!dma_addr_out)
2188 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302189 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302190 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002191
2192 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302193 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2194 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2195 MPI_SGE_FLAGS_IOC_TO_HOST |
2196 MPI_SGE_FLAGS_END_OF_BUFFER;
2197
2198 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002199 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002200 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002201 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002202 if (!dma_addr_in)
2203 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302204 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002205
Kashyap, Desai2f187862009-05-29 16:52:37 +05302206 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002207 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2208
2209 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2210 if (!timeleft) {
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002211 printk(MYIOC_s_ERR_FMT "%s: smp timeout!\n", ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002212 /* On timeout reset the board */
2213 mpt_HardResetHandler(ioc, CAN_SLEEP);
2214 ret = -ETIMEDOUT;
2215 goto unmap;
2216 }
2217 mf = NULL;
2218
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302219 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002220 SmpPassthroughReply_t *smprep;
2221
2222 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2223 memcpy(req->sense, smprep, sizeof(*smprep));
2224 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002225 req->resid_len = 0;
2226 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002227 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302228 printk(MYIOC_s_ERR_FMT
2229 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002230 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002231 ret = -ENXIO;
2232 }
2233unmap:
2234 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002235 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002236 PCI_DMA_BIDIRECTIONAL);
2237 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002238 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002239 PCI_DMA_BIDIRECTIONAL);
2240put_mf:
2241 if (mf)
2242 mpt_free_msg_frame(ioc, mf);
2243out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302244 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002245 mutex_unlock(&ioc->sas_mgmt.mutex);
2246out:
2247 return ret;
2248}
2249
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002250static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002251 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002252 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2253 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002254 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002255 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002256};
2257
2258static struct scsi_transport_template *mptsas_transport_template;
2259
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002260static int
2261mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2262{
2263 ConfigExtendedPageHeader_t hdr;
2264 CONFIGPARMS cfg;
2265 SasIOUnitPage0_t *buffer;
2266 dma_addr_t dma_handle;
2267 int error, i;
2268
2269 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2270 hdr.ExtPageLength = 0;
2271 hdr.PageNumber = 0;
2272 hdr.Reserved1 = 0;
2273 hdr.Reserved2 = 0;
2274 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2275 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2276
2277 cfg.cfghdr.ehdr = &hdr;
2278 cfg.physAddr = -1;
2279 cfg.pageAddr = 0;
2280 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2281 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302282 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002283
2284 error = mpt_config(ioc, &cfg);
2285 if (error)
2286 goto out;
2287 if (!hdr.ExtPageLength) {
2288 error = -ENXIO;
2289 goto out;
2290 }
2291
2292 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2293 &dma_handle);
2294 if (!buffer) {
2295 error = -ENOMEM;
2296 goto out;
2297 }
2298
2299 cfg.physAddr = dma_handle;
2300 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2301
2302 error = mpt_config(ioc, &cfg);
2303 if (error)
2304 goto out_free_consistent;
2305
2306 port_info->num_phys = buffer->NumPhys;
2307 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302308 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002309 if (!port_info->phy_info) {
2310 error = -ENOMEM;
2311 goto out_free_consistent;
2312 }
2313
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302314 ioc->nvdata_version_persistent =
2315 le16_to_cpu(buffer->NvdataVersionPersistent);
2316 ioc->nvdata_version_default =
2317 le16_to_cpu(buffer->NvdataVersionDefault);
2318
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002319 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302320 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002321 port_info->phy_info[i].phy_id = i;
2322 port_info->phy_info[i].port_id =
2323 buffer->PhyData[i].Port;
2324 port_info->phy_info[i].negotiated_link_rate =
2325 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002326 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002327 port_info->phy_info[i].handle =
2328 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002329 }
2330
2331 out_free_consistent:
2332 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2333 buffer, dma_handle);
2334 out:
2335 return error;
2336}
2337
2338static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302339mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2340{
2341 ConfigExtendedPageHeader_t hdr;
2342 CONFIGPARMS cfg;
2343 SasIOUnitPage1_t *buffer;
2344 dma_addr_t dma_handle;
2345 int error;
2346 u16 device_missing_delay;
2347
2348 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2349 memset(&cfg, 0, sizeof(CONFIGPARMS));
2350
2351 cfg.cfghdr.ehdr = &hdr;
2352 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302353 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302354 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2355 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2356 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2357 cfg.cfghdr.ehdr->PageNumber = 1;
2358
2359 error = mpt_config(ioc, &cfg);
2360 if (error)
2361 goto out;
2362 if (!hdr.ExtPageLength) {
2363 error = -ENXIO;
2364 goto out;
2365 }
2366
2367 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2368 &dma_handle);
2369 if (!buffer) {
2370 error = -ENOMEM;
2371 goto out;
2372 }
2373
2374 cfg.physAddr = dma_handle;
2375 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2376
2377 error = mpt_config(ioc, &cfg);
2378 if (error)
2379 goto out_free_consistent;
2380
2381 ioc->io_missing_delay =
2382 le16_to_cpu(buffer->IODeviceMissingDelay);
2383 device_missing_delay = le16_to_cpu(buffer->ReportDeviceMissingDelay);
2384 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2385 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2386 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2387
2388 out_free_consistent:
2389 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2390 buffer, dma_handle);
2391 out:
2392 return error;
2393}
2394
2395static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002396mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2397 u32 form, u32 form_specific)
2398{
2399 ConfigExtendedPageHeader_t hdr;
2400 CONFIGPARMS cfg;
2401 SasPhyPage0_t *buffer;
2402 dma_addr_t dma_handle;
2403 int error;
2404
2405 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2406 hdr.ExtPageLength = 0;
2407 hdr.PageNumber = 0;
2408 hdr.Reserved1 = 0;
2409 hdr.Reserved2 = 0;
2410 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2411 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2412
2413 cfg.cfghdr.ehdr = &hdr;
2414 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302415 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002416
2417 /* Get Phy Pg 0 for each Phy. */
2418 cfg.physAddr = -1;
2419 cfg.pageAddr = form + form_specific;
2420 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2421
2422 error = mpt_config(ioc, &cfg);
2423 if (error)
2424 goto out;
2425
2426 if (!hdr.ExtPageLength) {
2427 error = -ENXIO;
2428 goto out;
2429 }
2430
2431 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2432 &dma_handle);
2433 if (!buffer) {
2434 error = -ENOMEM;
2435 goto out;
2436 }
2437
2438 cfg.physAddr = dma_handle;
2439 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2440
2441 error = mpt_config(ioc, &cfg);
2442 if (error)
2443 goto out_free_consistent;
2444
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302445 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002446
2447 phy_info->hw_link_rate = buffer->HwLinkRate;
2448 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2449 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2450 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2451
2452 out_free_consistent:
2453 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2454 buffer, dma_handle);
2455 out:
2456 return error;
2457}
2458
2459static int
2460mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2461 u32 form, u32 form_specific)
2462{
2463 ConfigExtendedPageHeader_t hdr;
2464 CONFIGPARMS cfg;
2465 SasDevicePage0_t *buffer;
2466 dma_addr_t dma_handle;
2467 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002468 int error=0;
2469
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002470 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2471 hdr.ExtPageLength = 0;
2472 hdr.PageNumber = 0;
2473 hdr.Reserved1 = 0;
2474 hdr.Reserved2 = 0;
2475 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2476 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2477
2478 cfg.cfghdr.ehdr = &hdr;
2479 cfg.pageAddr = form + form_specific;
2480 cfg.physAddr = -1;
2481 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2482 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302483 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002484
Moore, Ericdb9c9172006-03-14 09:14:18 -07002485 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002486 error = mpt_config(ioc, &cfg);
2487 if (error)
2488 goto out;
2489 if (!hdr.ExtPageLength) {
2490 error = -ENXIO;
2491 goto out;
2492 }
2493
2494 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2495 &dma_handle);
2496 if (!buffer) {
2497 error = -ENOMEM;
2498 goto out;
2499 }
2500
2501 cfg.physAddr = dma_handle;
2502 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2503
2504 error = mpt_config(ioc, &cfg);
2505 if (error)
2506 goto out_free_consistent;
2507
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302508 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002509
Kashyap, Desai2f187862009-05-29 16:52:37 +05302510 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002511 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002512 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002513 device_info->handle_enclosure =
2514 le16_to_cpu(buffer->EnclosureHandle);
2515 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002516 device_info->phy_id = buffer->PhyNum;
2517 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002518 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002519 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002520 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002521 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2522 device_info->sas_address = le64_to_cpu(sas_address);
2523 device_info->device_info =
2524 le32_to_cpu(buffer->DeviceInfo);
2525
2526 out_free_consistent:
2527 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2528 buffer, dma_handle);
2529 out:
2530 return error;
2531}
2532
2533static int
2534mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2535 u32 form, u32 form_specific)
2536{
2537 ConfigExtendedPageHeader_t hdr;
2538 CONFIGPARMS cfg;
2539 SasExpanderPage0_t *buffer;
2540 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002541 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302542 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002543
Kashyap, Desai2f187862009-05-29 16:52:37 +05302544 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002545 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2546 hdr.ExtPageLength = 0;
2547 hdr.PageNumber = 0;
2548 hdr.Reserved1 = 0;
2549 hdr.Reserved2 = 0;
2550 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2551 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2552
2553 cfg.cfghdr.ehdr = &hdr;
2554 cfg.physAddr = -1;
2555 cfg.pageAddr = form + form_specific;
2556 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2557 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302558 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002559
Moore, Ericdb9c9172006-03-14 09:14:18 -07002560 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002561 error = mpt_config(ioc, &cfg);
2562 if (error)
2563 goto out;
2564
2565 if (!hdr.ExtPageLength) {
2566 error = -ENXIO;
2567 goto out;
2568 }
2569
2570 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2571 &dma_handle);
2572 if (!buffer) {
2573 error = -ENOMEM;
2574 goto out;
2575 }
2576
2577 cfg.physAddr = dma_handle;
2578 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2579
2580 error = mpt_config(ioc, &cfg);
2581 if (error)
2582 goto out_free_consistent;
2583
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002584 if (!buffer->NumPhys) {
2585 error = -ENODEV;
2586 goto out_free_consistent;
2587 }
2588
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002589 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302590 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002591 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302592 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002593 if (!port_info->phy_info) {
2594 error = -ENOMEM;
2595 goto out_free_consistent;
2596 }
2597
Kashyap, Desai2f187862009-05-29 16:52:37 +05302598 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002599 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002600 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002601 port_info->phy_info[i].handle =
2602 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302603 port_info->phy_info[i].identify.sas_address =
2604 le64_to_cpu(sas_address);
2605 port_info->phy_info[i].identify.handle_parent =
2606 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002607 }
Eric Moore547f9a22006-06-27 14:42:12 -06002608
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002609 out_free_consistent:
2610 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2611 buffer, dma_handle);
2612 out:
2613 return error;
2614}
2615
2616static int
2617mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2618 u32 form, u32 form_specific)
2619{
2620 ConfigExtendedPageHeader_t hdr;
2621 CONFIGPARMS cfg;
2622 SasExpanderPage1_t *buffer;
2623 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002624 int error=0;
2625
Kashyap, Desai2f187862009-05-29 16:52:37 +05302626 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002627 hdr.ExtPageLength = 0;
2628 hdr.PageNumber = 1;
2629 hdr.Reserved1 = 0;
2630 hdr.Reserved2 = 0;
2631 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2632 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2633
2634 cfg.cfghdr.ehdr = &hdr;
2635 cfg.physAddr = -1;
2636 cfg.pageAddr = form + form_specific;
2637 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2638 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302639 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002640
2641 error = mpt_config(ioc, &cfg);
2642 if (error)
2643 goto out;
2644
2645 if (!hdr.ExtPageLength) {
2646 error = -ENXIO;
2647 goto out;
2648 }
2649
2650 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2651 &dma_handle);
2652 if (!buffer) {
2653 error = -ENOMEM;
2654 goto out;
2655 }
2656
2657 cfg.physAddr = dma_handle;
2658 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2659
2660 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302661
2662 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2663 error = -ENODEV;
2664 goto out;
2665 }
2666
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002667 if (error)
2668 goto out_free_consistent;
2669
2670
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302671 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002672
2673 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002674 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002675 phy_info->port_id = buffer->PhysicalPort;
2676 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2677 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2678 phy_info->hw_link_rate = buffer->HwLinkRate;
2679 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2680 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2681
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002682 out_free_consistent:
2683 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2684 buffer, dma_handle);
2685 out:
2686 return error;
2687}
2688
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302689struct rep_manu_request{
2690 u8 smp_frame_type;
2691 u8 function;
2692 u8 reserved;
2693 u8 request_length;
2694};
2695
2696struct rep_manu_reply{
2697 u8 smp_frame_type; /* 0x41 */
2698 u8 function; /* 0x01 */
2699 u8 function_result;
2700 u8 response_length;
2701 u16 expander_change_count;
2702 u8 reserved0[2];
2703 u8 sas_format:1;
2704 u8 reserved1:7;
2705 u8 reserved2[3];
2706 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2707 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2708 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2709 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2710 u16 component_id;
2711 u8 component_revision_id;
2712 u8 reserved3;
2713 u8 vendor_specific[8];
2714};
2715
2716/**
2717 * mptsas_exp_repmanufacture_info -
2718 * @ioc: per adapter object
2719 * @sas_address: expander sas address
2720 * @edev: the sas_expander_device object
2721 *
2722 * Fills in the sas_expander_device object when SMP port is created.
2723 *
2724 * Returns 0 for success, non-zero for failure.
2725 */
2726static int
2727mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2728 u64 sas_address, struct sas_expander_device *edev)
2729{
2730 MPT_FRAME_HDR *mf;
2731 SmpPassthroughRequest_t *smpreq;
2732 SmpPassthroughReply_t *smprep;
2733 struct rep_manu_reply *manufacture_reply;
2734 struct rep_manu_request *manufacture_request;
2735 int ret;
2736 int flagsLength;
2737 unsigned long timeleft;
2738 char *psge;
2739 unsigned long flags;
2740 void *data_out = NULL;
2741 dma_addr_t data_out_dma = 0;
2742 u32 sz;
2743
2744 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2745 if (ioc->ioc_reset_in_progress) {
2746 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2747 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2748 __func__, ioc->name);
2749 return -EFAULT;
2750 }
2751 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2752
2753 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2754 if (ret)
2755 goto out;
2756
2757 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2758 if (!mf) {
2759 ret = -ENOMEM;
2760 goto out_unlock;
2761 }
2762
2763 smpreq = (SmpPassthroughRequest_t *)mf;
2764 memset(smpreq, 0, sizeof(*smpreq));
2765
2766 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2767
2768 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2769 if (!data_out) {
2770 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2771 __FILE__, __LINE__, __func__);
2772 ret = -ENOMEM;
2773 goto put_mf;
2774 }
2775
2776 manufacture_request = data_out;
2777 manufacture_request->smp_frame_type = 0x40;
2778 manufacture_request->function = 1;
2779 manufacture_request->reserved = 0;
2780 manufacture_request->request_length = 0;
2781
2782 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2783 smpreq->PhysicalPort = 0xFF;
2784 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2785 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2786
2787 psge = (char *)
2788 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2789
2790 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2791 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2792 MPI_SGE_FLAGS_HOST_TO_IOC |
2793 MPI_SGE_FLAGS_END_OF_BUFFER;
2794 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2795 flagsLength |= sizeof(struct rep_manu_request);
2796
2797 ioc->add_sge(psge, flagsLength, data_out_dma);
2798 psge += ioc->SGE_size;
2799
2800 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2801 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2802 MPI_SGE_FLAGS_IOC_TO_HOST |
2803 MPI_SGE_FLAGS_END_OF_BUFFER;
2804 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2805 flagsLength |= sizeof(struct rep_manu_reply);
2806 ioc->add_sge(psge, flagsLength, data_out_dma +
2807 sizeof(struct rep_manu_request));
2808
2809 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2810 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2811
2812 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2813 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2814 ret = -ETIME;
2815 mpt_free_msg_frame(ioc, mf);
2816 mf = NULL;
2817 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2818 goto out_free;
2819 if (!timeleft)
2820 mpt_HardResetHandler(ioc, CAN_SLEEP);
2821 goto out_free;
2822 }
2823
2824 mf = NULL;
2825
2826 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2827 u8 *tmp;
2828
2829 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2830 if (le16_to_cpu(smprep->ResponseDataLength) !=
2831 sizeof(struct rep_manu_reply))
2832 goto out_free;
2833
2834 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2835 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2836 SAS_EXPANDER_VENDOR_ID_LEN);
2837 strncpy(edev->product_id, manufacture_reply->product_id,
2838 SAS_EXPANDER_PRODUCT_ID_LEN);
2839 strncpy(edev->product_rev, manufacture_reply->product_rev,
2840 SAS_EXPANDER_PRODUCT_REV_LEN);
2841 edev->level = manufacture_reply->sas_format;
2842 if (manufacture_reply->sas_format) {
2843 strncpy(edev->component_vendor_id,
2844 manufacture_reply->component_vendor_id,
2845 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2846 tmp = (u8 *)&manufacture_reply->component_id;
2847 edev->component_id = tmp[0] << 8 | tmp[1];
2848 edev->component_revision_id =
2849 manufacture_reply->component_revision_id;
2850 }
2851 } else {
2852 printk(MYIOC_s_ERR_FMT
2853 "%s: smp passthru reply failed to be returned\n",
2854 ioc->name, __func__);
2855 ret = -ENXIO;
2856 }
2857out_free:
2858 if (data_out_dma)
2859 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2860put_mf:
2861 if (mf)
2862 mpt_free_msg_frame(ioc, mf);
2863out_unlock:
2864 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2865 mutex_unlock(&ioc->sas_mgmt.mutex);
2866out:
2867 return ret;
2868 }
2869
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002870static void
2871mptsas_parse_device_info(struct sas_identify *identify,
2872 struct mptsas_devinfo *device_info)
2873{
2874 u16 protocols;
2875
2876 identify->sas_address = device_info->sas_address;
2877 identify->phy_identifier = device_info->phy_id;
2878
2879 /*
2880 * Fill in Phy Initiator Port Protocol.
2881 * Bits 6:3, more than one bit can be set, fall through cases.
2882 */
2883 protocols = device_info->device_info & 0x78;
2884 identify->initiator_port_protocols = 0;
2885 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2886 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2887 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2888 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2889 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2890 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2891 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2892 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2893
2894 /*
2895 * Fill in Phy Target Port Protocol.
2896 * Bits 10:7, more than one bit can be set, fall through cases.
2897 */
2898 protocols = device_info->device_info & 0x780;
2899 identify->target_port_protocols = 0;
2900 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2901 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2902 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2903 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2904 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2905 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2906 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2907 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2908
2909 /*
2910 * Fill in Attached device type.
2911 */
2912 switch (device_info->device_info &
2913 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2914 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2915 identify->device_type = SAS_PHY_UNUSED;
2916 break;
2917 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2918 identify->device_type = SAS_END_DEVICE;
2919 break;
2920 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2921 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2922 break;
2923 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2924 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2925 break;
2926 }
2927}
2928
2929static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002930 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002931{
Moore, Erice6b2d762006-03-14 09:14:24 -07002932 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002933 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002934 struct sas_port *port;
2935 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002936
Eric Moore547f9a22006-06-27 14:42:12 -06002937 if (!dev) {
2938 error = -ENODEV;
2939 goto out;
2940 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002941
2942 if (!phy_info->phy) {
2943 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002944 if (!phy) {
2945 error = -ENOMEM;
2946 goto out;
2947 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002948 } else
2949 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002950
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002951 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002952
2953 /*
2954 * Set Negotiated link rate.
2955 */
2956 switch (phy_info->negotiated_link_rate) {
2957 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002958 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002959 break;
2960 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002961 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002962 break;
2963 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002964 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002965 break;
2966 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002967 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002968 break;
2969 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
2970 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
2971 default:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002972 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002973 break;
2974 }
2975
2976 /*
2977 * Set Max hardware link rate.
2978 */
2979 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2980 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002981 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002982 break;
2983 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002984 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002985 break;
2986 default:
2987 break;
2988 }
2989
2990 /*
2991 * Set Max programmed link rate.
2992 */
2993 switch (phy_info->programmed_link_rate &
2994 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
2995 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002996 phy->maximum_linkrate = 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 Hellwig9a28f49a2006-01-13 18:04:41 +01002999 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003000 break;
3001 default:
3002 break;
3003 }
3004
3005 /*
3006 * Set Min hardware link rate.
3007 */
3008 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3009 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003010 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003011 break;
3012 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003013 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003014 break;
3015 default:
3016 break;
3017 }
3018
3019 /*
3020 * Set Min programmed link rate.
3021 */
3022 switch (phy_info->programmed_link_rate &
3023 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3024 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003025 phy->minimum_linkrate = 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 Hellwig9a28f49a2006-01-13 18:04:41 +01003028 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003029 break;
3030 default:
3031 break;
3032 }
3033
Moore, Erice6b2d762006-03-14 09:14:24 -07003034 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003035
Moore, Erice6b2d762006-03-14 09:14:24 -07003036 error = sas_phy_add(phy);
3037 if (error) {
3038 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003039 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003040 }
3041 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003042 }
3043
Eric Moore547f9a22006-06-27 14:42:12 -06003044 if (!phy_info->attached.handle ||
3045 !phy_info->port_details)
3046 goto out;
3047
3048 port = mptsas_get_port(phy_info);
3049 ioc = phy_to_ioc(phy_info->phy);
3050
3051 if (phy_info->sas_port_add_phy) {
3052
3053 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003054 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003055 if (!port) {
3056 error = -ENOMEM;
3057 goto out;
3058 }
3059 error = sas_port_add(port);
3060 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303061 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003062 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003063 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003064 goto out;
3065 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303066 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303067 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3068 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3069 ioc->name, port->port_identifier,
3070 (unsigned long long)phy_info->
3071 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003072 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303073 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3074 "sas_port_add_phy: phy_id=%d\n",
3075 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003076 sas_port_add_phy(port, phy_info->phy);
3077 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303078 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3079 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3080 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003081 }
Eric Moore547f9a22006-06-27 14:42:12 -06003082 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003083
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003084 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003085 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003086 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003087
James Bottomley2686de22006-06-30 12:54:02 -05003088 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003089 /*
3090 * Let the hotplug_work thread handle processing
3091 * the adding/removing of devices that occur
3092 * after start of day.
3093 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303094 if (mptsas_is_end_device(&phy_info->attached) &&
3095 phy_info->attached.handle_parent) {
3096 goto out;
3097 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003098
James Bottomleyf013db32006-03-18 14:54:36 -06003099 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003100 if (scsi_is_host_device(parent)) {
3101 struct mptsas_portinfo *port_info;
3102 int i;
3103
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303104 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003105
3106 for (i = 0; i < port_info->num_phys; i++)
3107 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003108 identify.sas_address) {
3109 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003110 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003111 }
James Bottomley2686de22006-06-30 12:54:02 -05003112
3113 } else if (scsi_is_sas_rphy(parent)) {
3114 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3115 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003116 parent_rphy->identify.sas_address) {
3117 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003118 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003119 }
James Bottomley2686de22006-06-30 12:54:02 -05003120 }
3121
James Bottomleyf013db32006-03-18 14:54:36 -06003122 switch (identify.device_type) {
3123 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003124 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003125 break;
3126 case SAS_EDGE_EXPANDER_DEVICE:
3127 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003128 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003129 break;
3130 default:
3131 rphy = NULL;
3132 break;
3133 }
Eric Moore547f9a22006-06-27 14:42:12 -06003134 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303135 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003136 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003137 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003138 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003139 }
3140
Eric Moore547f9a22006-06-27 14:42:12 -06003141 rphy->identify = identify;
3142 error = sas_rphy_add(rphy);
3143 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303144 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003145 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003146 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003147 sas_rphy_free(rphy);
3148 goto out;
3149 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303150 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303151 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3152 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3153 mptsas_exp_repmanufacture_info(ioc,
3154 identify.sas_address,
3155 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003156 }
3157
Eric Moore547f9a22006-06-27 14:42:12 -06003158 out:
3159 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003160}
3161
3162static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003163mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003164{
Moore, Erice6b2d762006-03-14 09:14:24 -07003165 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003166 int error = -ENOMEM, i;
3167
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303168 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003169 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003170 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003171
Moore, Erice6b2d762006-03-14 09:14:24 -07003172 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003173 if (error)
3174 goto out_free_port_info;
3175
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303176 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003177 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303178 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003179 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303180 ioc->hba_port_info = port_info = hba;
3181 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003182 list_add_tail(&port_info->list, &ioc->sas_topology);
3183 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003184 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003185 port_info->phy_info[i].negotiated_link_rate =
3186 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003187 port_info->phy_info[i].handle =
3188 hba->phy_info[i].handle;
3189 port_info->phy_info[i].port_id =
3190 hba->phy_info[i].port_id;
3191 }
Eric Moore547f9a22006-06-27 14:42:12 -06003192 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003193 kfree(hba);
3194 hba = NULL;
3195 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003196 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303197#if defined(CPQ_CIM)
3198 ioc->num_ports = port_info->num_phys;
3199#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003200 for (i = 0; i < port_info->num_phys; i++) {
3201 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3202 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3203 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303204 port_info->phy_info[i].identify.handle =
3205 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003206 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003207 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3208 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303209 port_info->phy_info[i].identify.handle);
3210 if (!ioc->hba_port_sas_addr)
3211 ioc->hba_port_sas_addr =
3212 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003213 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003214 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003215 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003216 mptsas_sas_device_pg0(ioc,
3217 &port_info->phy_info[i].attached,
3218 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3219 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3220 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003221 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003222
Eric Moore547f9a22006-06-27 14:42:12 -06003223 mptsas_setup_wide_ports(ioc, port_info);
3224
3225 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003226 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003227 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003228
3229 return 0;
3230
3231 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003232 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003233 out:
3234 return error;
3235}
3236
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303237static void
3238mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003239{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303240 struct mptsas_portinfo *parent;
3241 struct device *parent_dev;
3242 struct sas_rphy *rphy;
3243 int i;
3244 u64 sas_address; /* expander sas address */
3245 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003246
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303247 handle = port_info->phy_info[0].handle;
3248 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003249 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003250 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303251 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3252 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003253
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303254 mptsas_sas_device_pg0(ioc,
3255 &port_info->phy_info[i].identify,
3256 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3257 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3258 port_info->phy_info[i].identify.handle);
3259 port_info->phy_info[i].identify.phy_id =
3260 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003261
3262 if (port_info->phy_info[i].attached.handle) {
3263 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303264 &port_info->phy_info[i].attached,
3265 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3266 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3267 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003268 port_info->phy_info[i].attached.phy_id =
3269 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003270 }
Eric Moore547f9a22006-06-27 14:42:12 -06003271 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003272
Moore, Erice6b2d762006-03-14 09:14:24 -07003273 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303274 parent = mptsas_find_portinfo_by_handle(ioc,
3275 port_info->phy_info[0].identify.handle_parent);
3276 if (!parent) {
3277 mutex_unlock(&ioc->sas_topology_mutex);
3278 return;
3279 }
3280 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3281 i++) {
3282 if (parent->phy_info[i].attached.sas_address == sas_address) {
3283 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3284 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003285 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003286 }
3287 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303288
3289 mptsas_setup_wide_ports(ioc, port_info);
3290 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3291 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3292 ioc->sas_index, 0);
3293}
3294
3295static void
3296mptsas_expander_event_add(MPT_ADAPTER *ioc,
3297 MpiEventDataSasExpanderStatusChange_t *expander_data)
3298{
3299 struct mptsas_portinfo *port_info;
3300 int i;
3301 __le64 sas_address;
3302
3303 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3304 if (!port_info)
3305 BUG();
3306 port_info->num_phys = (expander_data->NumPhys) ?
3307 expander_data->NumPhys : 1;
3308 port_info->phy_info = kcalloc(port_info->num_phys,
3309 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3310 if (!port_info->phy_info)
3311 BUG();
3312 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3313 for (i = 0; i < port_info->num_phys; i++) {
3314 port_info->phy_info[i].portinfo = port_info;
3315 port_info->phy_info[i].handle =
3316 le16_to_cpu(expander_data->DevHandle);
3317 port_info->phy_info[i].identify.sas_address =
3318 le64_to_cpu(sas_address);
3319 port_info->phy_info[i].identify.handle_parent =
3320 le16_to_cpu(expander_data->ParentDevHandle);
3321 }
3322
3323 mutex_lock(&ioc->sas_topology_mutex);
3324 list_add_tail(&port_info->list, &ioc->sas_topology);
3325 mutex_unlock(&ioc->sas_topology_mutex);
3326
3327 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3328 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3329 (unsigned long long)sas_address);
3330
3331 mptsas_expander_refresh(ioc, port_info);
3332}
3333
3334/**
3335 * mptsas_delete_expander_siblings - remove siblings attached to expander
3336 * @ioc: Pointer to MPT_ADAPTER structure
3337 * @parent: the parent port_info object
3338 * @expander: the expander port_info object
3339 **/
3340static void
3341mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3342 *parent, struct mptsas_portinfo *expander)
3343{
3344 struct mptsas_phyinfo *phy_info;
3345 struct mptsas_portinfo *port_info;
3346 struct sas_rphy *rphy;
3347 int i;
3348
3349 phy_info = expander->phy_info;
3350 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3351 rphy = mptsas_get_rphy(phy_info);
3352 if (!rphy)
3353 continue;
3354 if (rphy->identify.device_type == SAS_END_DEVICE)
3355 mptsas_del_end_device(ioc, phy_info);
3356 }
3357
3358 phy_info = expander->phy_info;
3359 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3360 rphy = mptsas_get_rphy(phy_info);
3361 if (!rphy)
3362 continue;
3363 if (rphy->identify.device_type ==
3364 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3365 rphy->identify.device_type ==
3366 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3367 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3368 rphy->identify.sas_address);
3369 if (!port_info)
3370 continue;
3371 if (port_info == parent) /* backlink rphy */
3372 continue;
3373 /*
3374 Delete this expander even if the expdevpage is exists
3375 because the parent expander is already deleted
3376 */
3377 mptsas_expander_delete(ioc, port_info, 1);
3378 }
3379 }
3380}
3381
3382
3383/**
3384 * mptsas_expander_delete - remove this expander
3385 * @ioc: Pointer to MPT_ADAPTER structure
3386 * @port_info: expander port_info struct
3387 * @force: Flag to forcefully delete the expander
3388 *
3389 **/
3390
3391static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3392 struct mptsas_portinfo *port_info, u8 force)
3393{
3394
3395 struct mptsas_portinfo *parent;
3396 int i;
3397 u64 expander_sas_address;
3398 struct mptsas_phyinfo *phy_info;
3399 struct mptsas_portinfo buffer;
3400 struct mptsas_portinfo_details *port_details;
3401 struct sas_port *port;
3402
3403 if (!port_info)
3404 return;
3405
3406 /* see if expander is still there before deleting */
3407 mptsas_sas_expander_pg0(ioc, &buffer,
3408 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3409 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3410 port_info->phy_info[0].identify.handle);
3411
3412 if (buffer.num_phys) {
3413 kfree(buffer.phy_info);
3414 if (!force)
3415 return;
3416 }
3417
3418
3419 /*
3420 * Obtain the port_info instance to the parent port
3421 */
3422 port_details = NULL;
3423 expander_sas_address =
3424 port_info->phy_info[0].identify.sas_address;
3425 parent = mptsas_find_portinfo_by_handle(ioc,
3426 port_info->phy_info[0].identify.handle_parent);
3427 mptsas_delete_expander_siblings(ioc, parent, port_info);
3428 if (!parent)
3429 goto out;
3430
3431 /*
3432 * Delete rphys in the parent that point
3433 * to this expander.
3434 */
3435 phy_info = parent->phy_info;
3436 port = NULL;
3437 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3438 if (!phy_info->phy)
3439 continue;
3440 if (phy_info->attached.sas_address !=
3441 expander_sas_address)
3442 continue;
3443 if (!port) {
3444 port = mptsas_get_port(phy_info);
3445 port_details = phy_info->port_details;
3446 }
3447 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3448 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3449 phy_info->phy_id, phy_info->phy);
3450 sas_port_delete_phy(port, phy_info->phy);
3451 }
3452 if (port) {
3453 dev_printk(KERN_DEBUG, &port->dev,
3454 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3455 ioc->name, port->port_identifier,
3456 (unsigned long long)expander_sas_address);
3457 sas_port_delete(port);
3458 mptsas_port_delete(ioc, port_details);
3459 }
3460 out:
3461
3462 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3463 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3464 (unsigned long long)expander_sas_address);
3465
3466 /*
3467 * free link
3468 */
3469 list_del(&port_info->list);
3470 kfree(port_info->phy_info);
3471 kfree(port_info);
3472}
3473
3474
3475/**
3476 * mptsas_send_expander_event - expanders events
3477 * @ioc: Pointer to MPT_ADAPTER structure
3478 * @expander_data: event data
3479 *
3480 *
3481 * This function handles adding, removing, and refreshing
3482 * device handles within the expander objects.
3483 */
3484static void
3485mptsas_send_expander_event(struct fw_event_work *fw_event)
3486{
3487 MPT_ADAPTER *ioc;
3488 MpiEventDataSasExpanderStatusChange_t *expander_data;
3489 struct mptsas_portinfo *port_info;
3490 __le64 sas_address;
3491 int i;
3492
3493 ioc = fw_event->ioc;
3494 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3495 fw_event->event_data;
3496 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303497 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303498 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3499
3500 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3501 if (port_info) {
3502 for (i = 0; i < port_info->num_phys; i++) {
3503 port_info->phy_info[i].portinfo = port_info;
3504 port_info->phy_info[i].handle =
3505 le16_to_cpu(expander_data->DevHandle);
3506 port_info->phy_info[i].identify.sas_address =
3507 le64_to_cpu(sas_address);
3508 port_info->phy_info[i].identify.handle_parent =
3509 le16_to_cpu(expander_data->ParentDevHandle);
3510 }
3511 mptsas_expander_refresh(ioc, port_info);
3512 } else if (!port_info && expander_data->NumPhys)
3513 mptsas_expander_event_add(ioc, expander_data);
3514 } else if (expander_data->ReasonCode ==
3515 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3516 mptsas_expander_delete(ioc, port_info, 0);
3517
3518 mptsas_free_fw_event(ioc, fw_event);
3519}
3520
3521
3522/**
3523 * mptsas_expander_add -
3524 * @ioc: Pointer to MPT_ADAPTER structure
3525 * @handle:
3526 *
3527 */
3528struct mptsas_portinfo *
3529mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3530{
3531 struct mptsas_portinfo buffer, *port_info;
3532 int i;
3533
3534 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3535 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3536 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3537 return NULL;
3538
3539 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3540 if (!port_info) {
3541 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3542 "%s: exit at line=%d\n", ioc->name,
3543 __func__, __LINE__));
3544 return NULL;
3545 }
3546 port_info->num_phys = buffer.num_phys;
3547 port_info->phy_info = buffer.phy_info;
3548 for (i = 0; i < port_info->num_phys; i++)
3549 port_info->phy_info[i].portinfo = port_info;
3550 mutex_lock(&ioc->sas_topology_mutex);
3551 list_add_tail(&port_info->list, &ioc->sas_topology);
3552 mutex_unlock(&ioc->sas_topology_mutex);
3553 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3554 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3555 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3556 mptsas_expander_refresh(ioc, port_info);
3557 return port_info;
3558}
3559
3560static void
3561mptsas_send_link_status_event(struct fw_event_work *fw_event)
3562{
3563 MPT_ADAPTER *ioc;
3564 MpiEventDataSasPhyLinkStatus_t *link_data;
3565 struct mptsas_portinfo *port_info;
3566 struct mptsas_phyinfo *phy_info = NULL;
3567 __le64 sas_address;
3568 u8 phy_num;
3569 u8 link_rate;
3570
3571 ioc = fw_event->ioc;
3572 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3573
3574 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3575 sas_address = le64_to_cpu(sas_address);
3576 link_rate = link_data->LinkRates >> 4;
3577 phy_num = link_data->PhyNum;
3578
3579 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3580 if (port_info) {
3581 phy_info = &port_info->phy_info[phy_num];
3582 if (phy_info)
3583 phy_info->negotiated_link_rate = link_rate;
3584 }
3585
3586 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3587 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3588
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303589 if (!port_info) {
3590 if (ioc->old_sas_discovery_protocal) {
3591 port_info = mptsas_expander_add(ioc,
3592 le16_to_cpu(link_data->DevHandle));
3593 if (port_info)
3594 goto out;
3595 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303596 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303597 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303598
3599 if (port_info == ioc->hba_port_info)
3600 mptsas_probe_hba_phys(ioc);
3601 else
3602 mptsas_expander_refresh(ioc, port_info);
3603 } else if (phy_info && phy_info->phy) {
3604 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3605 phy_info->phy->negotiated_linkrate =
3606 SAS_PHY_DISABLED;
3607 else if (link_rate ==
3608 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3609 phy_info->phy->negotiated_linkrate =
3610 SAS_LINK_RATE_FAILED;
3611 else
3612 phy_info->phy->negotiated_linkrate =
3613 SAS_LINK_RATE_UNKNOWN;
3614 }
3615 out:
3616 mptsas_free_fw_event(ioc, fw_event);
3617}
3618
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303619static void
3620mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3621{
3622 struct mptsas_portinfo buffer, *port_info;
3623 struct mptsas_device_info *sas_info;
3624 struct mptsas_devinfo sas_device;
3625 u32 handle;
3626 VirtTarget *vtarget = NULL;
3627 struct mptsas_phyinfo *phy_info;
3628 u8 found_expander;
3629 int retval, retry_count;
3630 unsigned long flags;
3631
3632 mpt_findImVolumes(ioc);
3633
3634 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3635 if (ioc->ioc_reset_in_progress) {
3636 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3637 "%s: exiting due to a parallel reset \n", ioc->name,
3638 __func__));
3639 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3640 return;
3641 }
3642 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3643
3644 /* devices, logical volumes */
3645 mutex_lock(&ioc->sas_device_info_mutex);
3646 redo_device_scan:
3647 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303648 if (sas_info->is_cached)
3649 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303650 if (!sas_info->is_logical_volume) {
3651 sas_device.handle = 0;
3652 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303653retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303654 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303655 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3656 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3657 (sas_info->fw.channel << 8) +
3658 sas_info->fw.id);
3659
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303660 if (sas_device.handle)
3661 continue;
3662 if (retval == -EBUSY) {
3663 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3664 if (ioc->ioc_reset_in_progress) {
3665 dfailprintk(ioc,
3666 printk(MYIOC_s_DEBUG_FMT
3667 "%s: exiting due to reset\n",
3668 ioc->name, __func__));
3669 spin_unlock_irqrestore
3670 (&ioc->taskmgmt_lock, flags);
3671 mutex_unlock(&ioc->
3672 sas_device_info_mutex);
3673 return;
3674 }
3675 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3676 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303677 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303678
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303679 if (retval && (retval != -ENODEV)) {
3680 if (retry_count < 10) {
3681 retry_count++;
3682 goto retry_page;
3683 } else {
3684 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3685 "%s: Config page retry exceeded retry "
3686 "count deleting device 0x%llx\n",
3687 ioc->name, __func__,
3688 sas_info->sas_address));
3689 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303690 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303691
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303692 /* delete device */
3693 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303694 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303695
3696 if (vtarget)
3697 vtarget->deleted = 1;
3698
3699 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3700 sas_info->sas_address);
3701
3702 if (phy_info) {
3703 mptsas_del_end_device(ioc, phy_info);
3704 goto redo_device_scan;
3705 }
3706 } else
3707 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303708 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003709 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303710
3711 /* expanders */
3712 mutex_lock(&ioc->sas_topology_mutex);
3713 redo_expander_scan:
3714 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3715
3716 if (port_info->phy_info &&
3717 (!(port_info->phy_info[0].identify.device_info &
3718 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3719 continue;
3720 found_expander = 0;
3721 handle = 0xFFFF;
3722 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3723 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3724 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3725 !found_expander) {
3726
3727 handle = buffer.phy_info[0].handle;
3728 if (buffer.phy_info[0].identify.sas_address ==
3729 port_info->phy_info[0].identify.sas_address) {
3730 found_expander = 1;
3731 }
3732 kfree(buffer.phy_info);
3733 }
3734
3735 if (!found_expander) {
3736 mptsas_expander_delete(ioc, port_info, 0);
3737 goto redo_expander_scan;
3738 }
3739 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003740 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303741}
3742
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303743/**
3744 * mptsas_probe_expanders - adding expanders
3745 * @ioc: Pointer to MPT_ADAPTER structure
3746 *
3747 **/
3748static void
3749mptsas_probe_expanders(MPT_ADAPTER *ioc)
3750{
3751 struct mptsas_portinfo buffer, *port_info;
3752 u32 handle;
3753 int i;
3754
3755 handle = 0xFFFF;
3756 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3757 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3758 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3759
3760 handle = buffer.phy_info[0].handle;
3761 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3762 buffer.phy_info[0].identify.sas_address);
3763
3764 if (port_info) {
3765 /* refreshing handles */
3766 for (i = 0; i < buffer.num_phys; i++) {
3767 port_info->phy_info[i].handle = handle;
3768 port_info->phy_info[i].identify.handle_parent =
3769 buffer.phy_info[0].identify.handle_parent;
3770 }
3771 mptsas_expander_refresh(ioc, port_info);
3772 kfree(buffer.phy_info);
3773 continue;
3774 }
3775
3776 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3777 if (!port_info) {
3778 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3779 "%s: exit at line=%d\n", ioc->name,
3780 __func__, __LINE__));
3781 return;
3782 }
3783 port_info->num_phys = buffer.num_phys;
3784 port_info->phy_info = buffer.phy_info;
3785 for (i = 0; i < port_info->num_phys; i++)
3786 port_info->phy_info[i].portinfo = port_info;
3787 mutex_lock(&ioc->sas_topology_mutex);
3788 list_add_tail(&port_info->list, &ioc->sas_topology);
3789 mutex_unlock(&ioc->sas_topology_mutex);
3790 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3791 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3792 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3793 mptsas_expander_refresh(ioc, port_info);
3794 }
3795}
3796
3797static void
3798mptsas_probe_devices(MPT_ADAPTER *ioc)
3799{
3800 u16 handle;
3801 struct mptsas_devinfo sas_device;
3802 struct mptsas_phyinfo *phy_info;
3803
3804 handle = 0xFFFF;
3805 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3806 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3807
3808 handle = sas_device.handle;
3809
3810 if ((sas_device.device_info &
3811 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3812 MPI_SAS_DEVICE_INFO_STP_TARGET |
3813 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3814 continue;
3815
3816 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3817 if (!phy_info)
3818 continue;
3819
3820 if (mptsas_get_rphy(phy_info))
3821 continue;
3822
3823 mptsas_add_end_device(ioc, phy_info);
3824 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003825}
3826
Kashyap, Desai2f187862009-05-29 16:52:37 +05303827/**
3828 * mptsas_scan_sas_topology -
3829 * @ioc: Pointer to MPT_ADAPTER structure
3830 * @sas_address:
3831 *
3832 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003833static void
3834mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3835{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303836 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003837 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003838
Moore, Erice6b2d762006-03-14 09:14:24 -07003839 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303840 mptsas_probe_expanders(ioc);
3841 mptsas_probe_devices(ioc);
3842
Moore, Ericf44e5462006-03-14 09:14:21 -07003843 /*
3844 Reporting RAID volumes.
3845 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303846 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3847 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3848 return;
Eric Moore793955f2007-01-29 09:42:20 -07003849 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303850 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3851 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3852 if (sdev) {
3853 scsi_device_put(sdev);
3854 continue;
3855 }
3856 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3857 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3858 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003859 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003860 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3861 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003862}
3863
Kashyap, Desai57e98512009-05-29 16:55:09 +05303864
3865static void
3866mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3867{
3868 MPT_ADAPTER *ioc;
3869 EventDataQueueFull_t *qfull_data;
3870 struct mptsas_device_info *sas_info;
3871 struct scsi_device *sdev;
3872 int depth;
3873 int id = -1;
3874 int channel = -1;
3875 int fw_id, fw_channel;
3876 u16 current_depth;
3877
3878
3879 ioc = fw_event->ioc;
3880 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3881 fw_id = qfull_data->TargetID;
3882 fw_channel = qfull_data->Bus;
3883 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3884
3885 /* if hidden raid component, look for the volume id */
3886 mutex_lock(&ioc->sas_device_info_mutex);
3887 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3888 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3889 list) {
3890 if (sas_info->is_cached ||
3891 sas_info->is_logical_volume)
3892 continue;
3893 if (sas_info->is_hidden_raid_component &&
3894 (sas_info->fw.channel == fw_channel &&
3895 sas_info->fw.id == fw_id)) {
3896 id = sas_info->volume_id;
3897 channel = MPTSAS_RAID_CHANNEL;
3898 goto out;
3899 }
3900 }
3901 } else {
3902 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3903 list) {
3904 if (sas_info->is_cached ||
3905 sas_info->is_hidden_raid_component ||
3906 sas_info->is_logical_volume)
3907 continue;
3908 if (sas_info->fw.channel == fw_channel &&
3909 sas_info->fw.id == fw_id) {
3910 id = sas_info->os.id;
3911 channel = sas_info->os.channel;
3912 goto out;
3913 }
3914 }
3915
3916 }
3917
3918 out:
3919 mutex_unlock(&ioc->sas_device_info_mutex);
3920
3921 if (id != -1) {
3922 shost_for_each_device(sdev, ioc->sh) {
3923 if (sdev->id == id && sdev->channel == channel) {
3924 if (current_depth > sdev->queue_depth) {
3925 sdev_printk(KERN_INFO, sdev,
3926 "strange observation, the queue "
3927 "depth is (%d) meanwhile fw queue "
3928 "depth (%d)\n", sdev->queue_depth,
3929 current_depth);
3930 continue;
3931 }
3932 depth = scsi_track_queue_full(sdev,
3933 current_depth - 1);
3934 if (depth > 0)
3935 sdev_printk(KERN_INFO, sdev,
3936 "Queue depth reduced to (%d)\n",
3937 depth);
3938 else if (depth < 0)
3939 sdev_printk(KERN_INFO, sdev,
3940 "Tagged Command Queueing is being "
3941 "disabled\n");
3942 else if (depth == 0)
3943 sdev_printk(KERN_INFO, sdev,
3944 "Queue depth not changed yet\n");
3945 }
3946 }
3947 }
3948
3949 mptsas_free_fw_event(ioc, fw_event);
3950}
3951
3952
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003953static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06003954mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003955{
3956 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003957 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06003958 int i;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003959
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003960 mutex_lock(&ioc->sas_topology_mutex);
3961 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3962 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06003963 if (!mptsas_is_end_device(
3964 &port_info->phy_info[i].attached))
3965 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07003966 if (port_info->phy_info[i].attached.sas_address
3967 != sas_address)
3968 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06003969 phy_info = &port_info->phy_info[i];
3970 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003971 }
3972 }
3973 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003974 return phy_info;
3975}
3976
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303977/**
3978 * mptsas_find_phyinfo_by_phys_disk_num -
3979 * @ioc: Pointer to MPT_ADAPTER structure
3980 * @phys_disk_num:
3981 * @channel:
3982 * @id:
3983 *
3984 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07003985static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303986mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
3987 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07003988{
Eric Mooreb506ade2007-01-29 09:45:37 -07003989 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303990 struct mptsas_portinfo *port_info;
3991 RaidPhysDiskPage1_t *phys_disk = NULL;
3992 int num_paths;
3993 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07003994 int i;
3995
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303996 phy_info = NULL;
3997 if (!ioc->raid_data.pIocPg3)
3998 return NULL;
3999 /* dual port support */
4000 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4001 if (!num_paths)
4002 goto out;
4003 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4004 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4005 if (!phys_disk)
4006 goto out;
4007 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4008 for (i = 0; i < num_paths; i++) {
4009 if ((phys_disk->Path[i].Flags & 1) != 0)
4010 /* entry no longer valid */
4011 continue;
4012 if ((id == phys_disk->Path[i].PhysDiskID) &&
4013 (channel == phys_disk->Path[i].PhysDiskBus)) {
4014 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4015 sizeof(u64));
4016 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4017 sas_address);
4018 goto out;
4019 }
4020 }
4021
4022 out:
4023 kfree(phys_disk);
4024 if (phy_info)
4025 return phy_info;
4026
4027 /*
4028 * Extra code to handle RAID0 case, where the sas_address is not updated
4029 * in phys_disk_page_1 when hotswapped
4030 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004031 mutex_lock(&ioc->sas_topology_mutex);
4032 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304033 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004034 if (!mptsas_is_end_device(
4035 &port_info->phy_info[i].attached))
4036 continue;
4037 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4038 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304039 if ((port_info->phy_info[i].attached.phys_disk_num ==
4040 phys_disk_num) &&
4041 (port_info->phy_info[i].attached.id == id) &&
4042 (port_info->phy_info[i].attached.channel ==
4043 channel))
4044 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004045 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004046 }
4047 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004048 return phy_info;
4049}
4050
4051static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004052mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4053{
Eric Mooref99be432007-01-04 20:46:54 -07004054 int rc;
4055
Moore, Ericf44e5462006-03-14 09:14:21 -07004056 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004057 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004058}
4059
4060static void
4061mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4062{
4063 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4064 mptsas_reprobe_lun);
4065}
4066
Eric Mooreb506ade2007-01-29 09:45:37 -07004067static void
4068mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4069{
4070 CONFIGPARMS cfg;
4071 ConfigPageHeader_t hdr;
4072 dma_addr_t dma_handle;
4073 pRaidVolumePage0_t buffer = NULL;
4074 RaidPhysDiskPage0_t phys_disk;
4075 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304076 struct mptsas_phyinfo *phy_info;
4077 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004078
4079 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4080 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4081 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4082 cfg.pageAddr = (channel << 8) + id;
4083 cfg.cfghdr.hdr = &hdr;
4084 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
4085
4086 if (mpt_config(ioc, &cfg) != 0)
4087 goto out;
4088
4089 if (!hdr.PageLength)
4090 goto out;
4091
4092 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4093 &dma_handle);
4094
4095 if (!buffer)
4096 goto out;
4097
4098 cfg.physAddr = dma_handle;
4099 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4100
4101 if (mpt_config(ioc, &cfg) != 0)
4102 goto out;
4103
4104 if (!(buffer->VolumeStatus.Flags &
4105 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4106 goto out;
4107
4108 if (!buffer->NumPhysDisks)
4109 goto out;
4110
4111 for (i = 0; i < buffer->NumPhysDisks; i++) {
4112
4113 if (mpt_raid_phys_disk_pg0(ioc,
4114 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4115 continue;
4116
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304117 if (mptsas_sas_device_pg0(ioc, &sas_device,
4118 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4119 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4120 (phys_disk.PhysDiskBus << 8) +
4121 phys_disk.PhysDiskID))
4122 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004123
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304124 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4125 sas_device.sas_address);
4126 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004127 }
4128
4129 out:
4130 if (buffer)
4131 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4132 dma_handle);
4133}
Moore, Erice6b2d762006-03-14 09:14:24 -07004134/*
4135 * Work queue thread to handle SAS hotplug events
4136 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004137static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304138mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4139 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004140{
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004141 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004142 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004143 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004144 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304145 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06004146
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304147 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004148
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304149 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004150
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304151 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004152 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004153
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304154 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4155 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4156 hot_plug_info->id) {
4157 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4158 "to add hidden disk - target_id matchs "
4159 "volume_id\n", ioc->name);
4160 mptsas_free_fw_event(ioc, fw_event);
4161 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004162 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004163 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304164 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004165
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004166 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304167 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4168 mptsas_sas_device_pg0(ioc, &sas_device,
4169 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4170 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4171 (hot_plug_info->channel << 8) +
4172 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004173
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304174 if (!sas_device.handle)
4175 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004176
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304177 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4178 if (!phy_info)
4179 break;
4180
4181 if (mptsas_get_rphy(phy_info))
4182 break;
4183
4184 mptsas_add_end_device(ioc, phy_info);
4185 break;
4186
4187 case MPTSAS_DEL_DEVICE:
4188 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4189 hot_plug_info->sas_address);
4190 mptsas_del_end_device(ioc, phy_info);
4191 break;
4192
4193 case MPTSAS_DEL_PHYSDISK:
4194
4195 mpt_findImVolumes(ioc);
4196
4197 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304198 ioc, hot_plug_info->phys_disk_num,
4199 hot_plug_info->channel,
4200 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304201 mptsas_del_end_device(ioc, phy_info);
4202 break;
4203
4204 case MPTSAS_ADD_PHYSDISK_REPROBE:
4205
Christoph Hellwige3094442006-02-16 13:25:36 +01004206 if (mptsas_sas_device_pg0(ioc, &sas_device,
4207 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004208 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304209 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4210 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4211 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4212 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004213 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004214 }
4215
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304216 phy_info = mptsas_find_phyinfo_by_sas_address(
4217 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004218
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304219 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304220 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304221 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4222 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004223 break;
4224 }
4225
4226 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304227 if (!starget) {
4228 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4229 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4230 __func__, hot_plug_info->id, __LINE__));
4231 break;
4232 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004233
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304234 vtarget = starget->hostdata;
4235 if (!vtarget) {
4236 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4237 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4238 __func__, hot_plug_info->id, __LINE__));
4239 break;
4240 }
Eric Moore547f9a22006-06-27 14:42:12 -06004241
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304242 mpt_findImVolumes(ioc);
4243
4244 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4245 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4246 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4247 hot_plug_info->phys_disk_num, (unsigned long long)
4248 sas_device.sas_address);
4249
4250 vtarget->id = hot_plug_info->phys_disk_num;
4251 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4252 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4253 mptsas_reprobe_target(starget, 1);
4254 break;
4255
4256 case MPTSAS_DEL_PHYSDISK_REPROBE:
4257
4258 if (mptsas_sas_device_pg0(ioc, &sas_device,
4259 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4260 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4261 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304262 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304263 "%s: fw_id=%d exit at line=%d\n",
4264 ioc->name, __func__,
4265 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004266 break;
4267 }
4268
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304269 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4270 sas_device.sas_address);
4271 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304272 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304273 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4274 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004275 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004276 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004277
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304278 starget = mptsas_get_starget(phy_info);
4279 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304280 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304281 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4282 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004283 break;
4284 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004285
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304286 vtarget = starget->hostdata;
4287 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304288 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304289 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4290 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004291 break;
4292 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304293
4294 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4295 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4296 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4297 __func__, hot_plug_info->id, __LINE__));
4298 break;
4299 }
4300
4301 mpt_findImVolumes(ioc);
4302
4303 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4304 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4305 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4306 hot_plug_info->phys_disk_num, (unsigned long long)
4307 sas_device.sas_address);
4308
4309 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4310 vtarget->id = hot_plug_info->id;
4311 phy_info->attached.phys_disk_num = ~0;
4312 mptsas_reprobe_target(starget, 0);
4313 mptsas_add_device_component_by_fw(ioc,
4314 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004315 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304316
Moore, Ericc73787ee2006-01-26 16:20:06 -07004317 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304318
Moore, Ericc73787ee2006-01-26 16:20:06 -07004319 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304320 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4321 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4322 hot_plug_info->id);
4323 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4324 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004325 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304326
Moore, Ericc73787ee2006-01-26 16:20:06 -07004327 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304328
Moore, Ericc73787ee2006-01-26 16:20:06 -07004329 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304330 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4331 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4332 hot_plug_info->id);
4333 scsi_remove_device(hot_plug_info->sdev);
4334 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004335 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304336
Eric Mooreb506ade2007-01-29 09:45:37 -07004337 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304338
4339 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004340 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304341 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004342 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304343
Moore, Ericbd23e942006-04-17 12:43:04 -06004344 default:
4345 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004346 }
4347
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304348 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004349}
4350
4351static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304352mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004353{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304354 MPT_ADAPTER *ioc;
4355 struct mptsas_hotplug_event hot_plug_info;
4356 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4357 u32 device_info;
4358 u64 sas_address;
4359
4360 ioc = fw_event->ioc;
4361 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4362 fw_event->event_data;
4363 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004364
4365 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304366 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4367 MPI_SAS_DEVICE_INFO_STP_TARGET |
4368 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4369 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004370 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304371 }
4372
4373 if (sas_event_data->ReasonCode ==
4374 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4375 mptbase_sas_persist_operation(ioc,
4376 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4377 mptsas_free_fw_event(ioc, fw_event);
4378 return;
4379 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004380
Moore, Eric4b766472006-03-14 09:14:12 -07004381 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004382 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004383 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304384 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4385 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4386 hot_plug_info.channel = sas_event_data->Bus;
4387 hot_plug_info.id = sas_event_data->TargetID;
4388 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004389 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304390 sizeof(u64));
4391 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4392 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004393 if (sas_event_data->ReasonCode &
4394 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304395 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004396 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304397 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4398 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004399 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304400
Moore, Eric4b766472006-03-14 09:14:12 -07004401 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304402 mptbase_sas_persist_operation(ioc,
4403 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4404 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004405 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304406
Moore, Eric4b766472006-03-14 09:14:12 -07004407 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304408 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004409 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304410 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004411 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304412 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004413 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004414 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004415}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304416
Moore, Ericc73787ee2006-01-26 16:20:06 -07004417static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304418mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004419{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304420 MPT_ADAPTER *ioc;
4421 EVENT_DATA_RAID *raid_event_data;
4422 struct mptsas_hotplug_event hot_plug_info;
4423 int status;
4424 int state;
4425 struct scsi_device *sdev = NULL;
4426 VirtDevice *vdevice = NULL;
4427 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004428
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304429 ioc = fw_event->ioc;
4430 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4431 status = le32_to_cpu(raid_event_data->SettingsStatus);
4432 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004433
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304434 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4435 hot_plug_info.id = raid_event_data->VolumeID;
4436 hot_plug_info.channel = raid_event_data->VolumeBus;
4437 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4438
4439 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4440 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4441 raid_event_data->ReasonCode ==
4442 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4443 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4444 hot_plug_info.id, 0);
4445 hot_plug_info.sdev = sdev;
4446 if (sdev)
4447 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004448 }
4449
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304450 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4451 "ReasonCode=%02x\n", ioc->name, __func__,
4452 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004453
4454 switch (raid_event_data->ReasonCode) {
4455 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304456 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004457 break;
4458 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304459 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004460 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004461 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4462 switch (state) {
4463 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004464 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304465 mpt_raid_phys_disk_pg0(ioc,
4466 raid_event_data->PhysDiskNum, &phys_disk);
4467 hot_plug_info.id = phys_disk.PhysDiskID;
4468 hot_plug_info.channel = phys_disk.PhysDiskBus;
4469 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004470 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304471 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004472 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004473 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4474 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4475 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304476 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004477 break;
4478 default:
4479 break;
4480 }
4481 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004482 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304483 if (!sdev)
4484 break;
4485 vdevice->vtarget->deleted = 1; /* block IO */
4486 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004487 break;
4488 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304489 if (sdev) {
4490 scsi_device_put(sdev);
4491 break;
4492 }
4493 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004494 break;
4495 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304496 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4497 if (!sdev)
4498 break;
4499 vdevice->vtarget->deleted = 1; /* block IO */
4500 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4501 break;
4502 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004503 switch (state) {
4504 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4505 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304506 if (!sdev)
4507 break;
4508 vdevice->vtarget->deleted = 1; /* block IO */
4509 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004510 break;
4511 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4512 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304513 if (sdev) {
4514 scsi_device_put(sdev);
4515 break;
4516 }
4517 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004518 break;
4519 default:
4520 break;
4521 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004522 break;
4523 default:
4524 break;
4525 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304526
4527 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4528 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4529 else
4530 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004531}
4532
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304533/**
4534 * mptsas_issue_tm - send mptsas internal tm request
4535 * @ioc: Pointer to MPT_ADAPTER structure
4536 * @type: Task Management type
4537 * @channel: channel number for task management
4538 * @id: Logical Target ID for reset (if appropriate)
4539 * @lun: Logical unit for reset (if appropriate)
4540 * @task_context: Context for the task to be aborted
4541 * @timeout: timeout for task management control
4542 *
4543 * return 0 on success and -1 on failure:
4544 *
4545 */
4546static int
4547mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4548 int task_context, ulong timeout, u8 *issue_reset)
4549{
4550 MPT_FRAME_HDR *mf;
4551 SCSITaskMgmt_t *pScsiTm;
4552 int retval;
4553 unsigned long timeleft;
4554
4555 *issue_reset = 0;
4556 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4557 if (mf == NULL) {
4558 retval = -1; /* return failure */
4559 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4560 "msg frames!!\n", ioc->name));
4561 goto out;
4562 }
4563
4564 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4565 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4566 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4567 type, timeout, channel, id, (unsigned long long)lun,
4568 task_context));
4569
4570 pScsiTm = (SCSITaskMgmt_t *) mf;
4571 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4572 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4573 pScsiTm->TaskType = type;
4574 pScsiTm->MsgFlags = 0;
4575 pScsiTm->TargetID = id;
4576 pScsiTm->Bus = channel;
4577 pScsiTm->ChainOffset = 0;
4578 pScsiTm->Reserved = 0;
4579 pScsiTm->Reserved1 = 0;
4580 pScsiTm->TaskMsgContext = task_context;
4581 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4582
4583 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4584 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4585 retval = 0;
4586 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4587
4588 /* Now wait for the command to complete */
4589 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4590 timeout*HZ);
4591 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4592 retval = -1; /* return failure */
4593 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4594 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4595 mpt_free_msg_frame(ioc, mf);
4596 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4597 goto out;
4598 *issue_reset = 1;
4599 goto out;
4600 }
4601
4602 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4603 retval = -1; /* return failure */
4604 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4605 "TaskMgmt request: failed with no reply\n", ioc->name));
4606 goto out;
4607 }
4608
4609 out:
4610 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4611 return retval;
4612}
4613
4614/**
4615 * mptsas_broadcast_primative_work - Handle broadcast primitives
4616 * @work: work queue payload containing info describing the event
4617 *
4618 * this will be handled in workqueue context.
4619 */
4620static void
4621mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4622{
4623 MPT_ADAPTER *ioc = fw_event->ioc;
4624 MPT_FRAME_HDR *mf;
4625 VirtDevice *vdevice;
4626 int ii;
4627 struct scsi_cmnd *sc;
4628 SCSITaskMgmtReply_t *pScsiTmReply;
4629 u8 issue_reset;
4630 int task_context;
4631 u8 channel, id;
4632 int lun;
4633 u32 termination_count;
4634 u32 query_count;
4635
4636 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4637 "%s - enter\n", ioc->name, __func__));
4638
4639 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4640 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4641 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4642 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4643 return;
4644 }
4645
4646 issue_reset = 0;
4647 termination_count = 0;
4648 query_count = 0;
4649 mpt_findImVolumes(ioc);
4650 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4651
4652 for (ii = 0; ii < ioc->req_depth; ii++) {
4653 if (ioc->fw_events_off)
4654 goto out;
4655 sc = mptscsih_get_scsi_lookup(ioc, ii);
4656 if (!sc)
4657 continue;
4658 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4659 if (!mf)
4660 continue;
4661 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4662 vdevice = sc->device->hostdata;
4663 if (!vdevice || !vdevice->vtarget)
4664 continue;
4665 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4666 continue; /* skip hidden raid components */
4667 if (vdevice->vtarget->raidVolume)
4668 continue; /* skip hidden raid components */
4669 channel = vdevice->vtarget->channel;
4670 id = vdevice->vtarget->id;
4671 lun = vdevice->lun;
4672 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4673 channel, id, (u64)lun, task_context, 30, &issue_reset))
4674 goto out;
4675 query_count++;
4676 termination_count +=
4677 le32_to_cpu(pScsiTmReply->TerminationCount);
4678 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4679 (pScsiTmReply->ResponseCode ==
4680 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4681 pScsiTmReply->ResponseCode ==
4682 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4683 continue;
4684 if (mptsas_issue_tm(ioc,
4685 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4686 channel, id, (u64)lun, 0, 30, &issue_reset))
4687 goto out;
4688 termination_count +=
4689 le32_to_cpu(pScsiTmReply->TerminationCount);
4690 }
4691
4692 out:
4693 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4694 "%s - exit, query_count = %d termination_count = %d\n",
4695 ioc->name, __func__, query_count, termination_count));
4696
4697 ioc->broadcast_aen_busy = 0;
4698 mpt_clear_taskmgmt_in_progress_flag(ioc);
4699 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4700
4701 if (issue_reset) {
4702 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4703 ioc->name, __func__);
4704 mpt_HardResetHandler(ioc, CAN_SLEEP);
4705 }
4706 mptsas_free_fw_event(ioc, fw_event);
4707}
4708
Eric Mooreb506ade2007-01-29 09:45:37 -07004709/*
4710 * mptsas_send_ir2_event - handle exposing hidden disk when
4711 * an inactive raid volume is added
4712 *
4713 * @ioc: Pointer to MPT_ADAPTER structure
4714 * @ir2_data
4715 *
4716 */
4717static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304718mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004719{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304720 MPT_ADAPTER *ioc;
4721 struct mptsas_hotplug_event hot_plug_info;
4722 MPI_EVENT_DATA_IR2 *ir2_data;
4723 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304724 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004725
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304726 ioc = fw_event->ioc;
4727 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4728 reasonCode = ir2_data->ReasonCode;
4729
4730 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4731 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4732
4733 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4734 hot_plug_info.id = ir2_data->TargetID;
4735 hot_plug_info.channel = ir2_data->Bus;
4736 switch (reasonCode) {
4737 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4738 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4739 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304740 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4741 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4742 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4743 break;
4744 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4745 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4746 mpt_raid_phys_disk_pg0(ioc,
4747 ir2_data->PhysDiskNum, &phys_disk);
4748 hot_plug_info.id = phys_disk.PhysDiskID;
4749 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4750 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304751 default:
4752 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004753 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304754 }
4755 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4756}
Moore, Erice6b2d762006-03-14 09:14:24 -07004757
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004758static int
4759mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4760{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304761 u32 event = le32_to_cpu(reply->Event);
4762 int sz, event_data_sz;
4763 struct fw_event_work *fw_event;
4764 unsigned long delay;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004765
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304766 /* events turned off due to host reset or driver unloading */
4767 if (ioc->fw_events_off)
4768 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004769
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304770 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004771 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304772 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4773 {
4774 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4775 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4776 if (broadcast_event_data->Primitive !=
4777 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4778 return 0;
4779 if (ioc->broadcast_aen_busy)
4780 return 0;
4781 ioc->broadcast_aen_busy = 1;
4782 break;
4783 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004784 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304785 {
4786 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4787 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4788
4789 if (sas_event_data->ReasonCode ==
4790 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4791 mptsas_target_reset_queue(ioc, sas_event_data);
4792 return 0;
4793 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004794 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304795 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304796 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4797 {
4798 MpiEventDataSasExpanderStatusChange_t *expander_data =
4799 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4800
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304801 if (ioc->old_sas_discovery_protocal)
4802 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304803
4804 if (expander_data->ReasonCode ==
4805 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4806 ioc->device_missing_delay)
4807 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004808 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304809 }
4810 case MPI_EVENT_SAS_DISCOVERY:
4811 {
4812 u32 discovery_status;
4813 EventDataSasDiscovery_t *discovery_data =
4814 (EventDataSasDiscovery_t *)reply->Data;
4815
4816 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4817 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304818 if (ioc->old_sas_discovery_protocal && !discovery_status)
4819 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304820 return 0;
4821 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304822 case MPI_EVENT_INTEGRATED_RAID:
4823 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004824 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304825 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4826 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004827 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004828 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304829 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004830 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004831
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304832 event_data_sz = ((reply->MsgLength * 4) -
4833 offsetof(EventNotificationReply_t, Data));
4834 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4835 fw_event = kzalloc(sz, GFP_ATOMIC);
4836 if (!fw_event) {
4837 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4838 __func__, __LINE__);
4839 return 0;
4840 }
4841 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4842 fw_event->event = event;
4843 fw_event->ioc = ioc;
4844 mptsas_add_fw_event(ioc, fw_event, delay);
4845 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004846}
4847
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304848/* Delete a volume when no longer listed in ioc pg2
4849 */
4850static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4851{
4852 struct scsi_device *sdev;
4853 int i;
4854
4855 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4856 if (!sdev)
4857 return;
4858 if (!ioc->raid_data.pIocPg2)
4859 goto out;
4860 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4861 goto out;
4862 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4863 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4864 goto release_sdev;
4865 out:
4866 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4867 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4868 scsi_remove_device(sdev);
4869 release_sdev:
4870 scsi_device_put(sdev);
4871}
4872
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004873static int
4874mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4875{
4876 struct Scsi_Host *sh;
4877 MPT_SCSI_HOST *hd;
4878 MPT_ADAPTER *ioc;
4879 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004880 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004881 int numSGE = 0;
4882 int scale;
4883 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004884 int error=0;
4885 int r;
4886
4887 r = mpt_attach(pdev,id);
4888 if (r)
4889 return r;
4890
4891 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304892 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004893 ioc->DoneCtx = mptsasDoneCtx;
4894 ioc->TaskCtx = mptsasTaskCtx;
4895 ioc->InternalCtx = mptsasInternalCtx;
4896
4897 /* Added sanity check on readiness of the MPT adapter.
4898 */
4899 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4900 printk(MYIOC_s_WARN_FMT
4901 "Skipping because it's not operational!\n",
4902 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004903 error = -ENODEV;
4904 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004905 }
4906
4907 if (!ioc->active) {
4908 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
4909 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004910 error = -ENODEV;
4911 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004912 }
4913
4914 /* Sanity check - ensure at least 1 port is INITIATOR capable
4915 */
4916 ioc_cap = 0;
4917 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
4918 if (ioc->pfacts[ii].ProtocolFlags &
4919 MPI_PORTFACTS_PROTOCOL_INITIATOR)
4920 ioc_cap++;
4921 }
4922
4923 if (!ioc_cap) {
4924 printk(MYIOC_s_WARN_FMT
4925 "Skipping ioc=%p because SCSI Initiator mode "
4926 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06004927 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004928 }
4929
4930 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
4931 if (!sh) {
4932 printk(MYIOC_s_WARN_FMT
4933 "Unable to register controller with SCSI subsystem\n",
4934 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004935 error = -1;
4936 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004937 }
4938
4939 spin_lock_irqsave(&ioc->FreeQlock, flags);
4940
4941 /* Attach the SCSI Host to the IOC structure
4942 */
4943 ioc->sh = sh;
4944
4945 sh->io_port = 0;
4946 sh->n_io_port = 0;
4947 sh->irq = 0;
4948
4949 /* set 16 byte cdb's */
4950 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05304951 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
4952 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07004953 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004954 sh->transportt = mptsas_transport_template;
4955
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004956 /* Required entry.
4957 */
4958 sh->unique_id = ioc->id;
4959
4960 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004961 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07004962 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01004963 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02004964 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004965
4966 /* Verify that we won't exceed the maximum
4967 * number of chain buffers
4968 * We can optimize: ZZ = req_sz/sizeof(SGE)
4969 * For 32bit SGE's:
4970 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
4971 * + (req_sz - 64)/sizeof(SGE)
4972 * A slightly different algorithm is required for
4973 * 64bit SGEs.
4974 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304975 scale = ioc->req_sz/ioc->SGE_size;
4976 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004977 numSGE = (scale - 1) *
4978 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304979 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004980 } else {
4981 numSGE = 1 + (scale - 1) *
4982 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05304983 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004984 }
4985
4986 if (numSGE < sh->sg_tablesize) {
4987 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304988 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004989 "Resetting sg_tablesize to %d from %d\n",
4990 ioc->name, numSGE, sh->sg_tablesize));
4991 sh->sg_tablesize = numSGE;
4992 }
4993
Eric Mooree7eae9f2007-09-29 10:15:59 -06004994 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004995 hd->ioc = ioc;
4996
4997 /* SCSI needs scsi_cmnd lookup table!
4998 * (with size equal to req_depth*PtrSz!)
4999 */
Eric Mooree8206382007-09-29 10:16:53 -06005000 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5001 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005002 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005003 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005004 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005005 }
Eric Mooree8206382007-09-29 10:16:53 -06005006 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005007
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305008 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005009 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005010
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005011 ioc->sas_data.ptClear = mpt_pt_clear;
5012
Eric Mooredf9e0622007-01-29 09:46:21 -07005013 hd->last_queue_full = 0;
5014 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305015 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5016 mutex_init(&ioc->sas_device_info_mutex);
5017
Eric Mooredf9e0622007-01-29 09:46:21 -07005018 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5019
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005020 if (ioc->sas_data.ptClear==1) {
5021 mptbase_sas_persist_operation(
5022 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5023 }
5024
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005025 error = scsi_add_host(sh, &ioc->pcidev->dev);
5026 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005027 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5028 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005029 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005030 }
5031
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305032 /* older firmware doesn't support expander events */
5033 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5034 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005035 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305036 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005037 return 0;
5038
Eric Moore547f9a22006-06-27 14:42:12 -06005039 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005040
5041 mptscsih_remove(pdev);
5042 return error;
5043}
5044
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305045void
5046mptsas_shutdown(struct pci_dev *pdev)
5047{
5048 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5049
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305050 mptsas_fw_event_off(ioc);
5051 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305052}
5053
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005054static void __devexit mptsas_remove(struct pci_dev *pdev)
5055{
5056 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5057 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005058 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005059
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305060 mptsas_shutdown(pdev);
5061
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305062 mptsas_del_device_components(ioc);
5063
Eric Mooreb506ade2007-01-29 09:45:37 -07005064 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005065 sas_remove_host(ioc->sh);
5066
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005067 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005068 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5069 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005070 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305071 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305072
Eric Moore547f9a22006-06-27 14:42:12 -06005073 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005074 kfree(p);
5075 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005076 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305077 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005078 mptscsih_remove(pdev);
5079}
5080
5081static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005082 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005083 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005084 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005085 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005086 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005087 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005088 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005089 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005090 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005091 PCI_ANY_ID, PCI_ANY_ID },
5092 {0} /* Terminating entry */
5093};
5094MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5095
5096
5097static struct pci_driver mptsas_driver = {
5098 .name = "mptsas",
5099 .id_table = mptsas_pci_table,
5100 .probe = mptsas_probe,
5101 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305102 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005103#ifdef CONFIG_PM
5104 .suspend = mptscsih_suspend,
5105 .resume = mptscsih_resume,
5106#endif
5107};
5108
5109static int __init
5110mptsas_init(void)
5111{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305112 int error;
5113
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005114 show_mptmod_ver(my_NAME, my_VERSION);
5115
5116 mptsas_transport_template =
5117 sas_attach_transport(&mptsas_transport_functions);
5118 if (!mptsas_transport_template)
5119 return -ENODEV;
5120
5121 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305122 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005123 mptsasInternalCtx =
5124 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005125 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305126 mptsasDeviceResetCtx =
5127 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005128
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305129 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5130 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005131
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305132 error = pci_register_driver(&mptsas_driver);
5133 if (error)
5134 sas_release_transport(mptsas_transport_template);
5135
5136 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005137}
5138
5139static void __exit
5140mptsas_exit(void)
5141{
5142 pci_unregister_driver(&mptsas_driver);
5143 sas_release_transport(mptsas_transport_template);
5144
5145 mpt_reset_deregister(mptsasDoneCtx);
5146 mpt_event_deregister(mptsasDoneCtx);
5147
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005148 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005149 mpt_deregister(mptsasInternalCtx);
5150 mpt_deregister(mptsasTaskCtx);
5151 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305152 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005153}
5154
5155module_init(mptsas_init);
5156module_exit(mptsas_exit);