blob: 83a5115f025113d89eb2c793901b443691d5f397 [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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090048#include <linux/slab.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020049#include <linux/init.h>
50#include <linux/errno.h>
Tim Schmielaucd354f12007-02-14 00:33:14 -080051#include <linux/jiffies.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020052#include <linux/workqueue.h>
Eric Moore547f9a22006-06-27 14:42:12 -060053#include <linux/delay.h> /* for mdelay */
Christoph Hellwig0c33b272005-09-09 16:27:19 +020054
Eric Moore547f9a22006-06-27 14:42:12 -060055#include <scsi/scsi.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020056#include <scsi/scsi_cmnd.h>
57#include <scsi/scsi_device.h>
58#include <scsi/scsi_host.h>
59#include <scsi/scsi_transport_sas.h>
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +053060#include <scsi/scsi_transport.h>
Eric Moore547f9a22006-06-27 14:42:12 -060061#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020062
63#include "mptbase.h"
64#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053065#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020066
67
68#define my_NAME "Fusion MPT SAS Host driver"
69#define my_VERSION MPT_LINUX_VERSION_COMMON
70#define MYNAM "mptsas"
71
James Bottomleye8bf3942006-07-11 17:49:34 -040072/*
73 * Reserved channel for integrated raid
74 */
75#define MPTSAS_RAID_CHANNEL 1
76
Kashyap, Desai4b976502009-08-05 12:52:03 +053077#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020078MODULE_AUTHOR(MODULEAUTHOR);
79MODULE_DESCRIPTION(my_NAME);
80MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070081MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020082
Christoph Hellwig0c33b272005-09-09 16:27:19 +020083static int mpt_pt_clear;
84module_param(mpt_pt_clear, int, 0);
85MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060086 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020087 "(default=MPTSCSIH_PT_CLEAR=0)");
88
Eric Moore793955f2007-01-29 09:42:20 -070089/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
90#define MPTSAS_MAX_LUN (16895)
91static int max_lun = MPTSAS_MAX_LUN;
92module_param(max_lun, int, 0);
93MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
94
Prakash, Sathyaf606f572007-08-14 16:12:53 +053095static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
96static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
97static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
98static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053099static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200100
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530101static void mptsas_firmware_event_work(struct work_struct *work);
102static void mptsas_send_sas_event(struct fw_event_work *fw_event);
103static void mptsas_send_raid_event(struct fw_event_work *fw_event);
104static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
105static void mptsas_parse_device_info(struct sas_identify *identify,
106 struct mptsas_devinfo *device_info);
107static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
108 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
109static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
110 (MPT_ADAPTER *ioc, u64 sas_address);
111static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
112 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
113static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
114 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
115static int mptsas_add_end_device(MPT_ADAPTER *ioc,
116 struct mptsas_phyinfo *phy_info);
117static void mptsas_del_end_device(MPT_ADAPTER *ioc,
118 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530119static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
120static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
121 (MPT_ADAPTER *ioc, u64 sas_address);
122static void mptsas_expander_delete(MPT_ADAPTER *ioc,
123 struct mptsas_portinfo *port_info, u8 force);
124static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530125static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
126static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530127static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530128static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530129static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Kashyap, Desaib68bf092010-06-17 14:40:56 +0530130void mptsas_schedule_target_reset(void *ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200131
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530132static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
133 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200134{
Eric Moore29dd3602007-09-14 18:46:51 -0600135 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
136 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
137 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
138 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
139 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
140 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
141 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
142 ioc->name, phy_data->Port));
143 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
144 ioc->name, phy_data->PortFlags));
145 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
146 ioc->name, phy_data->PhyFlags));
147 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
148 ioc->name, phy_data->NegotiatedLinkRate));
149 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
150 "Controller PHY Device Info=0x%X\n", ioc->name,
151 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
152 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
153 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200154}
155
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530156static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200157{
158 __le64 sas_address;
159
160 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
161
Eric Moore29dd3602007-09-14 18:46:51 -0600162 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
163 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
164 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
165 "Attached Device Handle=0x%X\n", ioc->name,
166 le16_to_cpu(pg0->AttachedDevHandle)));
167 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
168 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
169 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
170 "Attached PHY Identifier=0x%X\n", ioc->name,
171 pg0->AttachedPhyIdentifier));
172 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
173 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
174 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
175 ioc->name, pg0->ProgrammedLinkRate));
176 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
177 ioc->name, pg0->ChangeCount));
178 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
179 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200180}
181
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530182static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200183{
Eric Moore29dd3602007-09-14 18:46:51 -0600184 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
185 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
186 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
187 ioc->name, pg1->InvalidDwordCount));
188 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
189 "Running Disparity Error Count=0x%x\n", ioc->name,
190 pg1->RunningDisparityErrorCount));
191 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
192 "Loss Dword Synch Count=0x%x\n", ioc->name,
193 pg1->LossDwordSynchCount));
194 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
195 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
196 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200197}
198
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530199static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200200{
201 __le64 sas_address;
202
203 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
204
Eric Moore29dd3602007-09-14 18:46:51 -0600205 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
206 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
207 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
208 ioc->name, le16_to_cpu(pg0->DevHandle)));
209 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
210 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
211 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
212 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
213 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
214 ioc->name, le16_to_cpu(pg0->Slot)));
215 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
216 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
217 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
218 ioc->name, pg0->TargetID));
219 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
220 ioc->name, pg0->Bus));
221 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
222 ioc->name, pg0->PhyNum));
223 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
224 ioc->name, le16_to_cpu(pg0->AccessStatus)));
225 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
226 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
227 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
228 ioc->name, le16_to_cpu(pg0->Flags)));
229 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
230 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200231}
232
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530233static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200234{
Eric Moore29dd3602007-09-14 18:46:51 -0600235 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
236 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
237 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
238 ioc->name, pg1->PhysicalPort));
239 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
240 ioc->name, pg1->PhyIdentifier));
241 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
242 ioc->name, pg1->NegotiatedLinkRate));
243 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
244 ioc->name, pg1->ProgrammedLinkRate));
245 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
246 ioc->name, pg1->HwLinkRate));
247 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
248 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
249 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
250 "Attached Device Handle=0x%X\n\n", ioc->name,
251 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200253
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530254/* inhibit sas firmware event handling */
255static void
256mptsas_fw_event_off(MPT_ADAPTER *ioc)
257{
258 unsigned long flags;
259
260 spin_lock_irqsave(&ioc->fw_event_lock, flags);
261 ioc->fw_events_off = 1;
262 ioc->sas_discovery_quiesce_io = 0;
263 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
264
265}
266
267/* enable sas firmware event handling */
268static void
269mptsas_fw_event_on(MPT_ADAPTER *ioc)
270{
271 unsigned long flags;
272
273 spin_lock_irqsave(&ioc->fw_event_lock, flags);
274 ioc->fw_events_off = 0;
275 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
276}
277
278/* queue a sas firmware event */
279static void
280mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
281 unsigned long delay)
282{
283 unsigned long flags;
284
285 spin_lock_irqsave(&ioc->fw_event_lock, flags);
286 list_add_tail(&fw_event->list, &ioc->fw_event_list);
287 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
288 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
289 ioc->name, __func__, fw_event));
290 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
291 delay);
292 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
293}
294
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530295/* requeue a sas firmware event */
296static void
297mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
298 unsigned long delay)
299{
300 unsigned long flags;
301 spin_lock_irqsave(&ioc->fw_event_lock, flags);
302 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
303 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
304 fw_event->retries++;
305 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
306 msecs_to_jiffies(delay));
307 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
308}
309
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530310/* free memory assoicated to a sas firmware event */
311static void
312mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
313{
314 unsigned long flags;
315
316 spin_lock_irqsave(&ioc->fw_event_lock, flags);
317 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
318 ioc->name, __func__, fw_event));
319 list_del(&fw_event->list);
320 kfree(fw_event);
321 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
322}
323
324/* walk the firmware event queue, and either stop or wait for
325 * outstanding events to complete */
326static void
327mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
328{
329 struct fw_event_work *fw_event, *next;
330 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530331 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
332
333 /* flush the target_reset_list */
334 if (!list_empty(&hd->target_reset_list)) {
335 list_for_each_entry_safe(target_reset_list, n,
336 &hd->target_reset_list, list) {
337 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
338 "%s: removing target reset for id=%d\n",
339 ioc->name, __func__,
340 target_reset_list->sas_event_data.TargetID));
341 list_del(&target_reset_list->list);
342 kfree(target_reset_list);
343 }
344 }
345
346 if (list_empty(&ioc->fw_event_list) ||
347 !ioc->fw_event_q || in_interrupt())
348 return;
349
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530350 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
351 if (cancel_delayed_work(&fw_event->work))
352 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530353 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530354}
355
356
Christoph Hellwige3094442006-02-16 13:25:36 +0100357static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
358{
359 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
360 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
361}
362
363static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
364{
365 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
366 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
367}
368
Moore, Erice6b2d762006-03-14 09:14:24 -0700369/*
370 * mptsas_find_portinfo_by_handle
371 *
372 * This function should be called with the sas_topology_mutex already held
373 */
374static struct mptsas_portinfo *
375mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
376{
377 struct mptsas_portinfo *port_info, *rc=NULL;
378 int i;
379
380 list_for_each_entry(port_info, &ioc->sas_topology, list)
381 for (i = 0; i < port_info->num_phys; i++)
382 if (port_info->phy_info[i].identify.handle == handle) {
383 rc = port_info;
384 goto out;
385 }
386 out:
387 return rc;
388}
389
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530390/**
391 * mptsas_find_portinfo_by_sas_address -
392 * @ioc: Pointer to MPT_ADAPTER structure
393 * @handle:
394 *
395 * This function should be called with the sas_topology_mutex already held
396 *
397 **/
398static struct mptsas_portinfo *
399mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
400{
401 struct mptsas_portinfo *port_info, *rc = NULL;
402 int i;
403
404 if (sas_address >= ioc->hba_port_sas_addr &&
405 sas_address < (ioc->hba_port_sas_addr +
406 ioc->hba_port_num_phy))
407 return ioc->hba_port_info;
408
409 mutex_lock(&ioc->sas_topology_mutex);
410 list_for_each_entry(port_info, &ioc->sas_topology, list)
411 for (i = 0; i < port_info->num_phys; i++)
412 if (port_info->phy_info[i].identify.sas_address ==
413 sas_address) {
414 rc = port_info;
415 goto out;
416 }
417 out:
418 mutex_unlock(&ioc->sas_topology_mutex);
419 return rc;
420}
421
Moore, Ericbd23e942006-04-17 12:43:04 -0600422/*
423 * Returns true if there is a scsi end device
424 */
425static inline int
426mptsas_is_end_device(struct mptsas_devinfo * attached)
427{
Eric Moore547f9a22006-06-27 14:42:12 -0600428 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600429 (attached->device_info &
430 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
431 ((attached->device_info &
432 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
433 (attached->device_info &
434 MPI_SAS_DEVICE_INFO_STP_TARGET) |
435 (attached->device_info &
436 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
437 return 1;
438 else
439 return 0;
440}
441
Eric Moore547f9a22006-06-27 14:42:12 -0600442/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600443static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530444mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600445{
446 struct mptsas_portinfo *port_info;
447 struct mptsas_phyinfo *phy_info;
448 u8 i;
449
450 if (!port_details)
451 return;
452
453 port_info = port_details->port_info;
454 phy_info = port_info->phy_info;
455
Eric Moore29dd3602007-09-14 18:46:51 -0600456 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700457 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700458 port_details->num_phys, (unsigned long long)
459 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600460
461 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
462 if(phy_info->port_details != port_details)
463 continue;
464 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530465 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600466 phy_info->port_details = NULL;
467 }
468 kfree(port_details);
469}
470
471static inline struct sas_rphy *
472mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
473{
474 if (phy_info->port_details)
475 return phy_info->port_details->rphy;
476 else
477 return NULL;
478}
479
480static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530481mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600482{
483 if (phy_info->port_details) {
484 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600485 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
486 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600487 }
488
Eric Moore547f9a22006-06-27 14:42:12 -0600489 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600490 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
491 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600492 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
493 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600494 }
Eric Moore547f9a22006-06-27 14:42:12 -0600495}
496
497static inline struct sas_port *
498mptsas_get_port(struct mptsas_phyinfo *phy_info)
499{
500 if (phy_info->port_details)
501 return phy_info->port_details->port;
502 else
503 return NULL;
504}
505
506static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530507mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600508{
509 if (phy_info->port_details)
510 phy_info->port_details->port = port;
511
Eric Moore547f9a22006-06-27 14:42:12 -0600512 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600513 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
514 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600515 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
516 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600517 }
Eric Moore547f9a22006-06-27 14:42:12 -0600518}
519
520static inline struct scsi_target *
521mptsas_get_starget(struct mptsas_phyinfo *phy_info)
522{
523 if (phy_info->port_details)
524 return phy_info->port_details->starget;
525 else
526 return NULL;
527}
528
529static inline void
530mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
531starget)
532{
533 if (phy_info->port_details)
534 phy_info->port_details->starget = starget;
535}
536
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530537/**
538 * mptsas_add_device_component -
539 * @ioc: Pointer to MPT_ADAPTER structure
540 * @channel: fw mapped id's
541 * @id:
542 * @sas_address:
543 * @device_info:
544 *
545 **/
546static void
547mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
548 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
549{
550 struct mptsas_device_info *sas_info, *next;
551 struct scsi_device *sdev;
552 struct scsi_target *starget;
553 struct sas_rphy *rphy;
554
555 /*
556 * Delete all matching devices out of the list
557 */
558 mutex_lock(&ioc->sas_device_info_mutex);
559 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
560 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530561 if (!sas_info->is_logical_volume &&
562 (sas_info->sas_address == sas_address ||
563 (sas_info->fw.channel == channel &&
564 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530565 list_del(&sas_info->list);
566 kfree(sas_info);
567 }
568 }
569
570 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
571 if (!sas_info)
572 goto out;
573
574 /*
575 * Set Firmware mapping
576 */
577 sas_info->fw.id = id;
578 sas_info->fw.channel = channel;
579
580 sas_info->sas_address = sas_address;
581 sas_info->device_info = device_info;
582 sas_info->slot = slot;
583 sas_info->enclosure_logical_id = enclosure_logical_id;
584 INIT_LIST_HEAD(&sas_info->list);
585 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
586
587 /*
588 * Set OS mapping
589 */
590 shost_for_each_device(sdev, ioc->sh) {
591 starget = scsi_target(sdev);
592 rphy = dev_to_rphy(starget->dev.parent);
593 if (rphy->identify.sas_address == sas_address) {
594 sas_info->os.id = starget->id;
595 sas_info->os.channel = starget->channel;
596 }
597 }
598
599 out:
600 mutex_unlock(&ioc->sas_device_info_mutex);
601 return;
602}
603
604/**
605 * mptsas_add_device_component_by_fw -
606 * @ioc: Pointer to MPT_ADAPTER structure
607 * @channel: fw mapped id's
608 * @id:
609 *
610 **/
611static void
612mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
613{
614 struct mptsas_devinfo sas_device;
615 struct mptsas_enclosure enclosure_info;
616 int rc;
617
618 rc = mptsas_sas_device_pg0(ioc, &sas_device,
619 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
620 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
621 (channel << 8) + id);
622 if (rc)
623 return;
624
625 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
626 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
627 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
628 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
629 sas_device.handle_enclosure);
630
631 mptsas_add_device_component(ioc, sas_device.channel,
632 sas_device.id, sas_device.sas_address, sas_device.device_info,
633 sas_device.slot, enclosure_info.enclosure_logical_id);
634}
635
636/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000637 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530638 * @ioc: Pointer to MPT_ADAPTER structure
639 * @channel: fw mapped id's
640 * @id:
641 *
642 **/
643static void
644mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
645 struct scsi_target *starget)
646{
647 CONFIGPARMS cfg;
648 ConfigPageHeader_t hdr;
649 dma_addr_t dma_handle;
650 pRaidVolumePage0_t buffer = NULL;
651 int i;
652 RaidPhysDiskPage0_t phys_disk;
653 struct mptsas_device_info *sas_info, *next;
654
655 memset(&cfg, 0 , sizeof(CONFIGPARMS));
656 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
657 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
658 /* assumption that all volumes on channel = 0 */
659 cfg.pageAddr = starget->id;
660 cfg.cfghdr.hdr = &hdr;
661 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530662 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530663
664 if (mpt_config(ioc, &cfg) != 0)
665 goto out;
666
667 if (!hdr.PageLength)
668 goto out;
669
670 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
671 &dma_handle);
672
673 if (!buffer)
674 goto out;
675
676 cfg.physAddr = dma_handle;
677 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
678
679 if (mpt_config(ioc, &cfg) != 0)
680 goto out;
681
682 if (!buffer->NumPhysDisks)
683 goto out;
684
685 /*
686 * Adding entry for hidden components
687 */
688 for (i = 0; i < buffer->NumPhysDisks; i++) {
689
690 if (mpt_raid_phys_disk_pg0(ioc,
691 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
692 continue;
693
694 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
695 phys_disk.PhysDiskID);
696
Kashyap, Desai57e98512009-05-29 16:55:09 +0530697 mutex_lock(&ioc->sas_device_info_mutex);
698 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
699 list) {
700 if (!sas_info->is_logical_volume &&
701 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
702 sas_info->fw.id == phys_disk.PhysDiskID)) {
703 sas_info->is_hidden_raid_component = 1;
704 sas_info->volume_id = starget->id;
705 }
706 }
707 mutex_unlock(&ioc->sas_device_info_mutex);
708
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530709 }
710
711 /*
712 * Delete all matching devices out of the list
713 */
714 mutex_lock(&ioc->sas_device_info_mutex);
715 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
716 list) {
717 if (sas_info->is_logical_volume && sas_info->fw.id ==
718 starget->id) {
719 list_del(&sas_info->list);
720 kfree(sas_info);
721 }
722 }
723
724 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
725 if (sas_info) {
726 sas_info->fw.id = starget->id;
727 sas_info->os.id = starget->id;
728 sas_info->os.channel = starget->channel;
729 sas_info->is_logical_volume = 1;
730 INIT_LIST_HEAD(&sas_info->list);
731 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
732 }
733 mutex_unlock(&ioc->sas_device_info_mutex);
734
735 out:
736 if (buffer)
737 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
738 dma_handle);
739}
740
741/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530742 * mptsas_add_device_component_starget -
743 * @ioc: Pointer to MPT_ADAPTER structure
744 * @starget:
745 *
746 **/
747static void
748mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
749 struct scsi_target *starget)
750{
751 VirtTarget *vtarget;
752 struct sas_rphy *rphy;
753 struct mptsas_phyinfo *phy_info = NULL;
754 struct mptsas_enclosure enclosure_info;
755
756 rphy = dev_to_rphy(starget->dev.parent);
757 vtarget = starget->hostdata;
758 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
759 rphy->identify.sas_address);
760 if (!phy_info)
761 return;
762
763 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
764 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
765 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
766 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
767 phy_info->attached.handle_enclosure);
768
769 mptsas_add_device_component(ioc, phy_info->attached.channel,
770 phy_info->attached.id, phy_info->attached.sas_address,
771 phy_info->attached.device_info,
772 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
773}
774
775/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000776 * 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 +0530777 * @ioc: Pointer to MPT_ADAPTER structure
778 * @channel: os mapped id's
779 * @id:
780 *
781 **/
782static void
783mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
784{
785 struct mptsas_device_info *sas_info, *next;
786
787 /*
788 * Set is_cached flag
789 */
790 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
791 list) {
792 if (sas_info->os.channel == channel && sas_info->os.id == id)
793 sas_info->is_cached = 1;
794 }
795}
796
797/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530798 * mptsas_del_device_components - Cleaning the list
799 * @ioc: Pointer to MPT_ADAPTER structure
800 *
801 **/
802static void
803mptsas_del_device_components(MPT_ADAPTER *ioc)
804{
805 struct mptsas_device_info *sas_info, *next;
806
807 mutex_lock(&ioc->sas_device_info_mutex);
808 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
809 list) {
810 list_del(&sas_info->list);
811 kfree(sas_info);
812 }
813 mutex_unlock(&ioc->sas_device_info_mutex);
814}
815
Eric Moore547f9a22006-06-27 14:42:12 -0600816
817/*
818 * mptsas_setup_wide_ports
819 *
820 * Updates for new and existing narrow/wide port configuration
821 * in the sas_topology
822 */
Eric Moore376ac832006-06-29 17:36:26 -0600823static void
Eric Moore547f9a22006-06-27 14:42:12 -0600824mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
825{
826 struct mptsas_portinfo_details * port_details;
827 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
828 u64 sas_address;
829 int i, j;
830
831 mutex_lock(&ioc->sas_topology_mutex);
832
833 phy_info = port_info->phy_info;
834 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
835 if (phy_info->attached.handle)
836 continue;
837 port_details = phy_info->port_details;
838 if (!port_details)
839 continue;
840 if (port_details->num_phys < 2)
841 continue;
842 /*
843 * Removing a phy from a port, letting the last
844 * phy be removed by firmware events.
845 */
Eric Moore29dd3602007-09-14 18:46:51 -0600846 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
847 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700848 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600849 port_details->num_phys--;
850 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
851 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530852 if (phy_info->phy) {
853 devtprintk(ioc, dev_printk(KERN_DEBUG,
854 &phy_info->phy->dev, MYIOC_s_FMT
855 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
856 phy_info->phy_id, phy_info->phy));
857 sas_port_delete_phy(port_details->port, phy_info->phy);
858 }
Eric Moore547f9a22006-06-27 14:42:12 -0600859 phy_info->port_details = NULL;
860 }
861
862 /*
863 * Populate and refresh the tree
864 */
865 phy_info = port_info->phy_info;
866 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
867 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600868 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
869 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600870 if (!sas_address)
871 continue;
872 port_details = phy_info->port_details;
873 /*
874 * Forming a port
875 */
876 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530877 port_details = kzalloc(sizeof(struct
878 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600879 if (!port_details)
880 goto out;
881 port_details->num_phys = 1;
882 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600883 if (phy_info->phy_id < 64 )
884 port_details->phy_bitmask |=
885 (1 << phy_info->phy_id);
886 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600887 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700888 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600889 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600890 phy_info->port_details = port_details;
891 }
892
893 if (i == port_info->num_phys - 1)
894 continue;
895 phy_info_cmp = &port_info->phy_info[i + 1];
896 for (j = i + 1 ; j < port_info->num_phys ; j++,
897 phy_info_cmp++) {
898 if (!phy_info_cmp->attached.sas_address)
899 continue;
900 if (sas_address != phy_info_cmp->attached.sas_address)
901 continue;
902 if (phy_info_cmp->port_details == port_details )
903 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600904 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700905 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600906 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700907 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600908 if (phy_info_cmp->port_details) {
909 port_details->rphy =
910 mptsas_get_rphy(phy_info_cmp);
911 port_details->port =
912 mptsas_get_port(phy_info_cmp);
913 port_details->starget =
914 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600915 port_details->num_phys =
916 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600917 if (!phy_info_cmp->port_details->num_phys)
918 kfree(phy_info_cmp->port_details);
919 } else
920 phy_info_cmp->sas_port_add_phy=1;
921 /*
922 * Adding a phy to a port
923 */
924 phy_info_cmp->port_details = port_details;
925 if (phy_info_cmp->phy_id < 64 )
926 port_details->phy_bitmask |=
927 (1 << phy_info_cmp->phy_id);
928 port_details->num_phys++;
929 }
930 }
931
932 out:
933
Eric Moore547f9a22006-06-27 14:42:12 -0600934 for (i = 0; i < port_info->num_phys; i++) {
935 port_details = port_info->phy_info[i].port_details;
936 if (!port_details)
937 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600938 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700939 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700940 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700941 port_details, i, port_details->num_phys,
942 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600943 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
944 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600945 }
Eric Moore29dd3602007-09-14 18:46:51 -0600946 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600947 mutex_unlock(&ioc->sas_topology_mutex);
948}
949
Eric Mooredf9e0622007-01-29 09:46:21 -0700950/**
951 * csmisas_find_vtarget
952 *
953 * @ioc
954 * @volume_id
955 * @volume_bus
956 *
957 **/
958static VirtTarget *
959mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600960{
Eric Mooredf9e0622007-01-29 09:46:21 -0700961 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600962 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700963 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600964
Eric Mooredf9e0622007-01-29 09:46:21 -0700965 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530966 vdevice = sdev->hostdata;
967 if ((vdevice == NULL) ||
968 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700969 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530970 if ((vdevice->vtarget->tflags &
971 MPT_TARGET_FLAGS_RAID_COMPONENT ||
972 vdevice->vtarget->raidVolume))
973 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600974 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530975 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600976 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600977 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700978 return vtarget;
979}
980
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530981static void
982mptsas_queue_device_delete(MPT_ADAPTER *ioc,
983 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
984{
985 struct fw_event_work *fw_event;
986 int sz;
987
988 sz = offsetof(struct fw_event_work, event_data) +
989 sizeof(MpiEventDataSasDeviceStatusChange_t);
990 fw_event = kzalloc(sz, GFP_ATOMIC);
991 if (!fw_event) {
992 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
993 ioc->name, __func__, __LINE__);
994 return;
995 }
996 memcpy(fw_event->event_data, sas_event_data,
997 sizeof(MpiEventDataSasDeviceStatusChange_t));
998 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
999 fw_event->ioc = ioc;
1000 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1001}
1002
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301003static void
1004mptsas_queue_rescan(MPT_ADAPTER *ioc)
1005{
1006 struct fw_event_work *fw_event;
1007 int sz;
1008
1009 sz = offsetof(struct fw_event_work, event_data);
1010 fw_event = kzalloc(sz, GFP_ATOMIC);
1011 if (!fw_event) {
1012 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1013 ioc->name, __func__, __LINE__);
1014 return;
1015 }
1016 fw_event->event = -1;
1017 fw_event->ioc = ioc;
1018 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1019}
1020
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301021
Eric Mooredf9e0622007-01-29 09:46:21 -07001022/**
1023 * mptsas_target_reset
1024 *
1025 * Issues TARGET_RESET to end device using handshaking method
1026 *
1027 * @ioc
1028 * @channel
1029 * @id
1030 *
1031 * Returns (1) success
1032 * (0) failure
1033 *
1034 **/
1035static int
1036mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1037{
1038 MPT_FRAME_HDR *mf;
1039 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301040 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1041 return 0;
1042
Eric Mooredf9e0622007-01-29 09:46:21 -07001043
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301044 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1045 if (mf == NULL) {
1046 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301047 "%s, no msg frames @%d!!\n", ioc->name,
1048 __func__, __LINE__));
1049 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001050 }
1051
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301052 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1053 ioc->name, mf));
1054
Eric Mooredf9e0622007-01-29 09:46:21 -07001055 /* Format the Request
1056 */
1057 pScsiTm = (SCSITaskMgmt_t *) mf;
1058 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1059 pScsiTm->TargetID = id;
1060 pScsiTm->Bus = channel;
1061 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1062 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1063 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1064
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301065 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001066
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301067 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1068 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1069 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1070
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301071 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001072
1073 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301074
1075 out_fail:
1076
1077 mpt_clear_taskmgmt_in_progress_flag(ioc);
1078 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001079}
1080
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301081static void
1082mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1083{
1084 scsi_device_set_state(sdev, SDEV_BLOCK);
1085}
1086
1087static void
1088mptsas_block_io_starget(struct scsi_target *starget)
1089{
1090 if (starget)
1091 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1092}
1093
Eric Mooredf9e0622007-01-29 09:46:21 -07001094/**
1095 * mptsas_target_reset_queue
1096 *
1097 * Receive request for TARGET_RESET after recieving an firmware
1098 * event NOT_RESPONDING_EVENT, then put command in link list
1099 * and queue if task_queue already in use.
1100 *
1101 * @ioc
1102 * @sas_event_data
1103 *
1104 **/
1105static void
1106mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1107 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1108{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001109 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001110 VirtTarget *vtarget = NULL;
1111 struct mptsas_target_reset_event *target_reset_list;
1112 u8 id, channel;
1113
1114 id = sas_event_data->TargetID;
1115 channel = sas_event_data->Bus;
1116
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301117 vtarget = mptsas_find_vtarget(ioc, channel, id);
1118 if (vtarget) {
1119 mptsas_block_io_starget(vtarget->starget);
1120 vtarget->deleted = 1; /* block IO */
1121 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001122
Kashyap, Desai2f187862009-05-29 16:52:37 +05301123 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001124 GFP_ATOMIC);
1125 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301126 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1127 "%s, failed to allocate mem @%d..!!\n",
1128 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001129 return;
1130 }
1131
1132 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1133 sizeof(*sas_event_data));
1134 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1135
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301136 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001137
1138 if (mptsas_target_reset(ioc, channel, id)) {
1139 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001140 }
1141}
1142
1143/**
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301144 * mptsas_schedule_target_reset- send pending target reset
1145 * @iocp: per adapter object
1146 *
1147 * This function will delete scheduled target reset from the list and
1148 * try to send next target reset. This will be called from completion
1149 * context of any Task managment command.
1150 */
1151
1152void
1153mptsas_schedule_target_reset(void *iocp)
1154{
1155 MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
1156 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1157 struct list_head *head = &hd->target_reset_list;
1158 struct mptsas_target_reset_event *target_reset_list;
1159 u8 id, channel;
1160 /*
1161 * issue target reset to next device in the queue
1162 */
1163
1164 head = &hd->target_reset_list;
1165 if (list_empty(head))
1166 return;
1167
1168 target_reset_list = list_entry(head->next,
1169 struct mptsas_target_reset_event, list);
1170
1171 id = target_reset_list->sas_event_data.TargetID;
1172 channel = target_reset_list->sas_event_data.Bus;
1173 target_reset_list->time_count = jiffies;
1174
1175 if (mptsas_target_reset(ioc, channel, id))
1176 target_reset_list->target_reset_issued = 1;
1177 return;
1178}
1179
1180
1181/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001182 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301183 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001184 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001185 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1186 * queue to finish off removing device from upper layers. then send next
1187 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001188 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301189static int
1190mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001191{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001192 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001193 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001194 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301195 struct mptsas_target_reset_event *target_reset_list;
1196 SCSITaskMgmtReply_t *pScsiTmReply;
1197
1198 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1199 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1200
1201 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1202 if (pScsiTmReply) {
1203 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1204 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1205 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1206 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1207 "term_cmnds = %d\n", ioc->name,
1208 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1209 pScsiTmReply->TaskType,
1210 le16_to_cpu(pScsiTmReply->IOCStatus),
1211 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1212 pScsiTmReply->ResponseCode,
1213 le32_to_cpu(pScsiTmReply->TerminationCount)));
1214
1215 if (pScsiTmReply->ResponseCode)
1216 mptscsih_taskmgmt_response_code(ioc,
1217 pScsiTmReply->ResponseCode);
1218 }
1219
1220 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1221 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1222 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1223 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1224 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1225 memcpy(ioc->taskmgmt_cmds.reply, mr,
1226 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1227 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1228 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1229 complete(&ioc->taskmgmt_cmds.done);
1230 return 1;
1231 }
1232 return 0;
1233 }
1234
1235 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001236
1237 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301238 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001239
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301240 target_reset_list = list_entry(head->next,
1241 struct mptsas_target_reset_event, list);
1242
1243 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1244 "TaskMgmt: completed (%d seconds)\n",
1245 ioc->name, jiffies_to_msecs(jiffies -
1246 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001247
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301248 id = pScsiTmReply->TargetID;
1249 channel = pScsiTmReply->Bus;
1250 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001251
1252 /*
1253 * retry target reset
1254 */
1255 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301256 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001257 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301258 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001259 }
1260
1261 /*
1262 * enable work queue to remove device from upper layers
1263 */
1264 list_del(&target_reset_list->list);
Kei Tokunaga3e84beb2010-04-07 19:17:24 +09001265 if (!ioc->fw_events_off)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301266 mptsas_queue_device_delete(ioc,
1267 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301268
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301269
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301270 ioc->schedule_target_reset(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001271
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301272 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001273}
1274
1275/**
1276 * mptscsih_ioc_reset
1277 *
1278 * @ioc
1279 * @reset_phase
1280 *
1281 **/
1282static int
1283mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1284{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001285 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001286 int rc;
1287
1288 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301289 if ((ioc->bus_type != SAS) || (!rc))
1290 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001291
Eric Mooree7eae9f2007-09-29 10:15:59 -06001292 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001293 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001294 goto out;
1295
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301296 switch (reset_phase) {
1297 case MPT_IOC_SETUP_RESET:
1298 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1299 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1300 mptsas_fw_event_off(ioc);
1301 break;
1302 case MPT_IOC_PRE_RESET:
1303 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1304 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1305 break;
1306 case MPT_IOC_POST_RESET:
1307 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1308 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1309 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1310 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1311 complete(&ioc->sas_mgmt.done);
1312 }
1313 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301314 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301315 break;
1316 default:
1317 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001318 }
1319
1320 out:
1321 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001322}
1323
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301324
1325/**
1326 * enum device_state -
1327 * @DEVICE_RETRY: need to retry the TUR
1328 * @DEVICE_ERROR: TUR return error, don't add device
1329 * @DEVICE_READY: device can be added
1330 *
1331 */
1332enum device_state{
1333 DEVICE_RETRY,
1334 DEVICE_ERROR,
1335 DEVICE_READY,
1336};
1337
Christoph Hellwige3094442006-02-16 13:25:36 +01001338static int
Moore, Eric52435432006-03-14 09:14:15 -07001339mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001340 u32 form, u32 form_specific)
1341{
1342 ConfigExtendedPageHeader_t hdr;
1343 CONFIGPARMS cfg;
1344 SasEnclosurePage0_t *buffer;
1345 dma_addr_t dma_handle;
1346 int error;
1347 __le64 le_identifier;
1348
1349 memset(&hdr, 0, sizeof(hdr));
1350 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1351 hdr.PageNumber = 0;
1352 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1353 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1354
1355 cfg.cfghdr.ehdr = &hdr;
1356 cfg.physAddr = -1;
1357 cfg.pageAddr = form + form_specific;
1358 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1359 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301360 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001361
1362 error = mpt_config(ioc, &cfg);
1363 if (error)
1364 goto out;
1365 if (!hdr.ExtPageLength) {
1366 error = -ENXIO;
1367 goto out;
1368 }
1369
1370 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1371 &dma_handle);
1372 if (!buffer) {
1373 error = -ENOMEM;
1374 goto out;
1375 }
1376
1377 cfg.physAddr = dma_handle;
1378 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1379
1380 error = mpt_config(ioc, &cfg);
1381 if (error)
1382 goto out_free_consistent;
1383
1384 /* save config data */
1385 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1386 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1387 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1388 enclosure->flags = le16_to_cpu(buffer->Flags);
1389 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1390 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1391 enclosure->start_id = buffer->StartTargetID;
1392 enclosure->start_channel = buffer->StartBus;
1393 enclosure->sep_id = buffer->SEPTargetID;
1394 enclosure->sep_channel = buffer->SEPBus;
1395
1396 out_free_consistent:
1397 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1398 buffer, dma_handle);
1399 out:
1400 return error;
1401}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001402
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301403/**
1404 * mptsas_add_end_device - report a new end device to sas transport layer
1405 * @ioc: Pointer to MPT_ADAPTER structure
1406 * @phy_info: decribes attached device
1407 *
1408 * return (0) success (1) failure
1409 *
1410 **/
1411static int
1412mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1413{
1414 struct sas_rphy *rphy;
1415 struct sas_port *port;
1416 struct sas_identify identify;
1417 char *ds = NULL;
1418 u8 fw_id;
1419
1420 if (!phy_info) {
1421 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1422 "%s: exit at line=%d\n", ioc->name,
1423 __func__, __LINE__));
1424 return 1;
1425 }
1426
1427 fw_id = phy_info->attached.id;
1428
1429 if (mptsas_get_rphy(phy_info)) {
1430 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1431 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1432 __func__, fw_id, __LINE__));
1433 return 2;
1434 }
1435
1436 port = mptsas_get_port(phy_info);
1437 if (!port) {
1438 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1439 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1440 __func__, fw_id, __LINE__));
1441 return 3;
1442 }
1443
1444 if (phy_info->attached.device_info &
1445 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1446 ds = "ssp";
1447 if (phy_info->attached.device_info &
1448 MPI_SAS_DEVICE_INFO_STP_TARGET)
1449 ds = "stp";
1450 if (phy_info->attached.device_info &
1451 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1452 ds = "sata";
1453
1454 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1455 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1456 phy_info->attached.channel, phy_info->attached.id,
1457 phy_info->attached.phy_id, (unsigned long long)
1458 phy_info->attached.sas_address);
1459
1460 mptsas_parse_device_info(&identify, &phy_info->attached);
1461 rphy = sas_end_device_alloc(port);
1462 if (!rphy) {
1463 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1464 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1465 __func__, fw_id, __LINE__));
1466 return 5; /* non-fatal: an rphy can be added later */
1467 }
1468
1469 rphy->identify = identify;
1470 if (sas_rphy_add(rphy)) {
1471 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1472 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1473 __func__, fw_id, __LINE__));
1474 sas_rphy_free(rphy);
1475 return 6;
1476 }
1477 mptsas_set_rphy(ioc, phy_info, rphy);
1478 return 0;
1479}
1480
1481/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001482 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301483 * @ioc: Pointer to MPT_ADAPTER structure
1484 * @phy_info: decribes attached device
1485 *
1486 **/
1487static void
1488mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1489{
1490 struct sas_rphy *rphy;
1491 struct sas_port *port;
1492 struct mptsas_portinfo *port_info;
1493 struct mptsas_phyinfo *phy_info_parent;
1494 int i;
1495 char *ds = NULL;
1496 u8 fw_id;
1497 u64 sas_address;
1498
1499 if (!phy_info)
1500 return;
1501
1502 fw_id = phy_info->attached.id;
1503 sas_address = phy_info->attached.sas_address;
1504
1505 if (!phy_info->port_details) {
1506 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1507 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1508 __func__, fw_id, __LINE__));
1509 return;
1510 }
1511 rphy = mptsas_get_rphy(phy_info);
1512 if (!rphy) {
1513 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1514 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1515 __func__, fw_id, __LINE__));
1516 return;
1517 }
1518
1519 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1520 || phy_info->attached.device_info
1521 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1522 || phy_info->attached.device_info
1523 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1524 ds = "initiator";
1525 if (phy_info->attached.device_info &
1526 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1527 ds = "ssp";
1528 if (phy_info->attached.device_info &
1529 MPI_SAS_DEVICE_INFO_STP_TARGET)
1530 ds = "stp";
1531 if (phy_info->attached.device_info &
1532 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1533 ds = "sata";
1534
1535 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1536 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1537 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1538 phy_info->attached.id, phy_info->attached.phy_id,
1539 (unsigned long long) sas_address);
1540
1541 port = mptsas_get_port(phy_info);
1542 if (!port) {
1543 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1544 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1545 __func__, fw_id, __LINE__));
1546 return;
1547 }
1548 port_info = phy_info->portinfo;
1549 phy_info_parent = port_info->phy_info;
1550 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1551 if (!phy_info_parent->phy)
1552 continue;
1553 if (phy_info_parent->attached.sas_address !=
1554 sas_address)
1555 continue;
1556 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1557 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1558 ioc->name, phy_info_parent->phy_id,
1559 phy_info_parent->phy);
1560 sas_port_delete_phy(port, phy_info_parent->phy);
1561 }
1562
1563 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1564 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1565 port->port_identifier, (unsigned long long)sas_address);
1566 sas_port_delete(port);
1567 mptsas_set_port(ioc, phy_info, NULL);
1568 mptsas_port_delete(ioc, phy_info->port_details);
1569}
1570
1571struct mptsas_phyinfo *
1572mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1573 struct mptsas_devinfo *sas_device)
1574{
1575 struct mptsas_phyinfo *phy_info;
1576 struct mptsas_portinfo *port_info;
1577 int i;
1578
1579 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1580 sas_device->sas_address);
1581 if (!phy_info)
1582 goto out;
1583 port_info = phy_info->portinfo;
1584 if (!port_info)
1585 goto out;
1586 mutex_lock(&ioc->sas_topology_mutex);
1587 for (i = 0; i < port_info->num_phys; i++) {
1588 if (port_info->phy_info[i].attached.sas_address !=
1589 sas_device->sas_address)
1590 continue;
1591 port_info->phy_info[i].attached.channel = sas_device->channel;
1592 port_info->phy_info[i].attached.id = sas_device->id;
1593 port_info->phy_info[i].attached.sas_address =
1594 sas_device->sas_address;
1595 port_info->phy_info[i].attached.handle = sas_device->handle;
1596 port_info->phy_info[i].attached.handle_parent =
1597 sas_device->handle_parent;
1598 port_info->phy_info[i].attached.handle_enclosure =
1599 sas_device->handle_enclosure;
1600 }
1601 mutex_unlock(&ioc->sas_topology_mutex);
1602 out:
1603 return phy_info;
1604}
1605
1606/**
1607 * mptsas_firmware_event_work - work thread for processing fw events
1608 * @work: work queue payload containing info describing the event
1609 * Context: user
1610 *
1611 */
1612static void
1613mptsas_firmware_event_work(struct work_struct *work)
1614{
1615 struct fw_event_work *fw_event =
1616 container_of(work, struct fw_event_work, work.work);
1617 MPT_ADAPTER *ioc = fw_event->ioc;
1618
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301619 /* special rescan topology handling */
1620 if (fw_event->event == -1) {
1621 if (ioc->in_rescan) {
1622 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1623 "%s: rescan ignored as it is in progress\n",
1624 ioc->name, __func__));
1625 return;
1626 }
1627 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1628 "reset\n", ioc->name, __func__));
1629 ioc->in_rescan = 1;
1630 mptsas_not_responding_devices(ioc);
1631 mptsas_scan_sas_topology(ioc);
1632 ioc->in_rescan = 0;
1633 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301634 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301635 return;
1636 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301637
1638 /* events handling turned off during host reset */
1639 if (ioc->fw_events_off) {
1640 mptsas_free_fw_event(ioc, fw_event);
1641 return;
1642 }
1643
1644 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1645 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1646 (fw_event->event & 0xFF)));
1647
1648 switch (fw_event->event) {
1649 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1650 mptsas_send_sas_event(fw_event);
1651 break;
1652 case MPI_EVENT_INTEGRATED_RAID:
1653 mptsas_send_raid_event(fw_event);
1654 break;
1655 case MPI_EVENT_IR2:
1656 mptsas_send_ir2_event(fw_event);
1657 break;
1658 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1659 mptbase_sas_persist_operation(ioc,
1660 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1661 mptsas_free_fw_event(ioc, fw_event);
1662 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301663 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1664 mptsas_broadcast_primative_work(fw_event);
1665 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301666 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1667 mptsas_send_expander_event(fw_event);
1668 break;
1669 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1670 mptsas_send_link_status_event(fw_event);
1671 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301672 case MPI_EVENT_QUEUE_FULL:
1673 mptsas_handle_queue_full_event(fw_event);
1674 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301675 }
1676}
1677
1678
1679
James Bottomleyf013db32006-03-18 14:54:36 -06001680static int
1681mptsas_slave_configure(struct scsi_device *sdev)
1682{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301683 struct Scsi_Host *host = sdev->host;
1684 MPT_SCSI_HOST *hd = shost_priv(host);
1685 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301686 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001687
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301688 if (vdevice->vtarget->deleted) {
1689 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1690 vdevice->vtarget->deleted = 0;
1691 }
1692
1693 /*
1694 * RAID volumes placed beyond the last expected port.
1695 * Ignore sending sas mode pages in that case..
1696 */
1697 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1698 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001699 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301700 }
James Bottomleyf013db32006-03-18 14:54:36 -06001701
James Bottomleye8bf3942006-07-11 17:49:34 -04001702 sas_read_port_mode_page(sdev);
1703
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301704 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1705
James Bottomleye8bf3942006-07-11 17:49:34 -04001706 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001707 return mptscsih_slave_configure(sdev);
1708}
1709
Eric Moore547f9a22006-06-27 14:42:12 -06001710static int
1711mptsas_target_alloc(struct scsi_target *starget)
1712{
1713 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001714 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001715 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001716 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001717 struct sas_rphy *rphy;
1718 struct mptsas_portinfo *p;
1719 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001720 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001721
1722 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1723 if (!vtarget)
1724 return -ENOMEM;
1725
1726 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001727 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001728 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1729 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001730 channel = 0;
1731
Eric Moore793955f2007-01-29 09:42:20 -07001732 /*
1733 * RAID volumes placed beyond the last expected port.
1734 */
1735 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301736 if (!ioc->raid_data.pIocPg2) {
1737 kfree(vtarget);
1738 return -ENXIO;
1739 }
1740 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1741 if (id == ioc->raid_data.pIocPg2->
1742 RaidVolume[i].VolumeID) {
1743 channel = ioc->raid_data.pIocPg2->
1744 RaidVolume[i].VolumeBus;
1745 }
1746 }
1747 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001748 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001749 }
Eric Moore547f9a22006-06-27 14:42:12 -06001750
1751 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001752 mutex_lock(&ioc->sas_topology_mutex);
1753 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001754 for (i = 0; i < p->num_phys; i++) {
1755 if (p->phy_info[i].attached.sas_address !=
1756 rphy->identify.sas_address)
1757 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001758 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001759 channel = p->phy_info[i].attached.channel;
1760 mptsas_set_starget(&p->phy_info[i], starget);
1761
1762 /*
1763 * Exposing hidden raid components
1764 */
Eric Mooree80b0022007-09-14 18:49:03 -06001765 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1766 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001767 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001768 vtarget->tflags |=
1769 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001770 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001771 }
Eric Mooree80b0022007-09-14 18:49:03 -06001772 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001773 goto out;
1774 }
1775 }
Eric Mooree80b0022007-09-14 18:49:03 -06001776 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001777
1778 kfree(vtarget);
1779 return -ENXIO;
1780
1781 out:
Eric Moore793955f2007-01-29 09:42:20 -07001782 vtarget->id = id;
1783 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001784 starget->hostdata = vtarget;
1785 return 0;
1786}
1787
1788static void
1789mptsas_target_destroy(struct scsi_target *starget)
1790{
1791 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001792 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001793 struct sas_rphy *rphy;
1794 struct mptsas_portinfo *p;
1795 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301796 MPT_ADAPTER *ioc = hd->ioc;
1797 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001798
1799 if (!starget->hostdata)
1800 return;
1801
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301802 vtarget = starget->hostdata;
1803
Kashyap, Desai57e98512009-05-29 16:55:09 +05301804 mptsas_del_device_component_by_os(ioc, starget->channel,
1805 starget->id);
1806
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301807
James Bottomleye8bf3942006-07-11 17:49:34 -04001808 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001809 goto out;
1810
1811 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001812 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001813 for (i = 0; i < p->num_phys; i++) {
1814 if (p->phy_info[i].attached.sas_address !=
1815 rphy->identify.sas_address)
1816 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301817
1818 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1819 "delete device: fw_channel %d, fw_id %d, phy %d, "
1820 "sas_addr 0x%llx\n", ioc->name,
1821 p->phy_info[i].attached.channel,
1822 p->phy_info[i].attached.id,
1823 p->phy_info[i].attached.phy_id, (unsigned long long)
1824 p->phy_info[i].attached.sas_address);
1825
Eric Moore547f9a22006-06-27 14:42:12 -06001826 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001827 }
1828 }
1829
1830 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301831 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001832 kfree(starget->hostdata);
1833 starget->hostdata = NULL;
1834}
1835
1836
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001837static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001838mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001839{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001840 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001841 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001842 struct sas_rphy *rphy;
1843 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001844 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001845 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001846 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001847 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001848
Eric Moorea69de502007-09-14 18:48:19 -06001849 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1850 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001851 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001852 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001853 return -ENOMEM;
1854 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001855 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001856 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001857
James Bottomleye8bf3942006-07-11 17:49:34 -04001858 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001859 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001860
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001861 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001862 mutex_lock(&ioc->sas_topology_mutex);
1863 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001864 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001865 if (p->phy_info[i].attached.sas_address !=
1866 rphy->identify.sas_address)
1867 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001868 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001869 /*
1870 * Exposing hidden raid components
1871 */
Eric Mooree80b0022007-09-14 18:49:03 -06001872 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001873 p->phy_info[i].attached.channel,
1874 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001875 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001876 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001877 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001878 }
1879 }
Eric Mooree80b0022007-09-14 18:49:03 -06001880 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001881
Eric Moorea69de502007-09-14 18:48:19 -06001882 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001883 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001884
1885 out:
Eric Moorea69de502007-09-14 18:48:19 -06001886 vdevice->vtarget->num_luns++;
1887 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001888 return 0;
1889}
1890
Eric Moore547f9a22006-06-27 14:42:12 -06001891static int
1892mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001893{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301894 MPT_SCSI_HOST *hd;
1895 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001896 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001897
Eric Moorea69de502007-09-14 18:48:19 -06001898 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001899 SCpnt->result = DID_NO_CONNECT << 16;
1900 done(SCpnt);
1901 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001902 }
Eric Moore547f9a22006-06-27 14:42:12 -06001903
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301904 hd = shost_priv(SCpnt->device->host);
1905 ioc = hd->ioc;
1906
1907 if (ioc->sas_discovery_quiesce_io)
1908 return SCSI_MLQUEUE_HOST_BUSY;
1909
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301910 if (ioc->debug_level & MPT_DEBUG_SCSI)
1911 scsi_print_command(SCpnt);
Eric Moore793955f2007-01-29 09:42:20 -07001912
Eric Moore547f9a22006-06-27 14:42:12 -06001913 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01001914}
1915
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05301916/**
1917 * mptsas_mptsas_eh_timed_out - resets the scsi_cmnd timeout
1918 * if the device under question is currently in the
1919 * device removal delay.
1920 * @sc: scsi command that the midlayer is about to time out
1921 *
1922 **/
1923static enum blk_eh_timer_return mptsas_eh_timed_out(struct scsi_cmnd *sc)
1924{
1925 MPT_SCSI_HOST *hd;
1926 MPT_ADAPTER *ioc;
1927 VirtDevice *vdevice;
1928 enum blk_eh_timer_return rc = BLK_EH_NOT_HANDLED;
1929
1930 hd = shost_priv(sc->device->host);
1931 if (hd == NULL) {
1932 printk(KERN_ERR MYNAM ": %s: Can't locate host! (sc=%p)\n",
1933 __func__, sc);
1934 goto done;
1935 }
1936
1937 ioc = hd->ioc;
1938 if (ioc->bus_type != SAS) {
1939 printk(KERN_ERR MYNAM ": %s: Wrong bus type (sc=%p)\n",
1940 __func__, sc);
1941 goto done;
1942 }
1943
1944 vdevice = sc->device->hostdata;
1945 if (vdevice && vdevice->vtarget && (vdevice->vtarget->inDMD
1946 || vdevice->vtarget->deleted)) {
1947 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT ": %s: target removed "
1948 "or in device removal delay (sc=%p)\n",
1949 ioc->name, __func__, sc));
1950 rc = BLK_EH_RESET_TIMER;
1951 goto done;
1952 }
1953
1954done:
1955 return rc;
1956}
1957
Eric Moore547f9a22006-06-27 14:42:12 -06001958
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001959static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001960 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001961 .proc_name = "mptsas",
1962 .proc_info = mptscsih_proc_info,
Kashyap, Desai568da762010-03-18 19:23:50 +05301963 .name = "MPT SAS Host",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001964 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001965 .queuecommand = mptsas_qcmd,
1966 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001967 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001968 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001969 .target_destroy = mptsas_target_destroy,
1970 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001971 .change_queue_depth = mptscsih_change_queue_depth,
1972 .eh_abort_handler = mptscsih_abort,
1973 .eh_device_reset_handler = mptscsih_dev_reset,
1974 .eh_bus_reset_handler = mptscsih_bus_reset,
1975 .eh_host_reset_handler = mptscsih_host_reset,
1976 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301977 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001978 .this_id = -1,
1979 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1980 .max_sectors = 8192,
1981 .cmd_per_lun = 7,
1982 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301983 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001984};
1985
Christoph Hellwigb5141122005-10-28 22:07:41 +02001986static int mptsas_get_linkerrors(struct sas_phy *phy)
1987{
1988 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1989 ConfigExtendedPageHeader_t hdr;
1990 CONFIGPARMS cfg;
1991 SasPhyPage1_t *buffer;
1992 dma_addr_t dma_handle;
1993 int error;
1994
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001995 /* FIXME: only have link errors on local phys */
1996 if (!scsi_is_sas_phy_local(phy))
1997 return -EINVAL;
1998
Christoph Hellwigb5141122005-10-28 22:07:41 +02001999 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
2000 hdr.ExtPageLength = 0;
2001 hdr.PageNumber = 1 /* page number 1*/;
2002 hdr.Reserved1 = 0;
2003 hdr.Reserved2 = 0;
2004 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2005 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2006
2007 cfg.cfghdr.ehdr = &hdr;
2008 cfg.physAddr = -1;
2009 cfg.pageAddr = phy->identify.phy_identifier;
2010 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2011 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302012 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02002013
2014 error = mpt_config(ioc, &cfg);
2015 if (error)
2016 return error;
2017 if (!hdr.ExtPageLength)
2018 return -ENXIO;
2019
2020 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2021 &dma_handle);
2022 if (!buffer)
2023 return -ENOMEM;
2024
2025 cfg.physAddr = dma_handle;
2026 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2027
2028 error = mpt_config(ioc, &cfg);
2029 if (error)
2030 goto out_free_consistent;
2031
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302032 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02002033
2034 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
2035 phy->running_disparity_error_count =
2036 le32_to_cpu(buffer->RunningDisparityErrorCount);
2037 phy->loss_of_dword_sync_count =
2038 le32_to_cpu(buffer->LossDwordSynchCount);
2039 phy->phy_reset_problem_count =
2040 le32_to_cpu(buffer->PhyResetProblemCount);
2041
2042 out_free_consistent:
2043 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2044 buffer, dma_handle);
2045 return error;
2046}
2047
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002048static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2049 MPT_FRAME_HDR *reply)
2050{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302051 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002052 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302053 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002054 memcpy(ioc->sas_mgmt.reply, reply,
2055 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
2056 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302057
2058 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
2059 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
2060 complete(&ioc->sas_mgmt.done);
2061 return 1;
2062 }
2063 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002064}
2065
2066static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2067{
2068 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2069 SasIoUnitControlRequest_t *req;
2070 SasIoUnitControlReply_t *reply;
2071 MPT_FRAME_HDR *mf;
2072 MPIHeader_t *hdr;
2073 unsigned long timeleft;
2074 int error = -ERESTARTSYS;
2075
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002076 /* FIXME: fusion doesn't allow non-local phy reset */
2077 if (!scsi_is_sas_phy_local(phy))
2078 return -EINVAL;
2079
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002080 /* not implemented for expanders */
2081 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2082 return -ENXIO;
2083
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002084 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002085 goto out;
2086
2087 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2088 if (!mf) {
2089 error = -ENOMEM;
2090 goto out_unlock;
2091 }
2092
2093 hdr = (MPIHeader_t *) mf;
2094 req = (SasIoUnitControlRequest_t *)mf;
2095 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2096 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2097 req->MsgContext = hdr->MsgContext;
2098 req->Operation = hard_reset ?
2099 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2100 req->PhyNum = phy->identify.phy_identifier;
2101
Kashyap, Desai2f187862009-05-29 16:52:37 +05302102 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002103 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2104
2105 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2106 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302107 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2108 error = -ETIME;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002109 mpt_free_msg_frame(ioc, mf);
Kashyap, Desai568da762010-03-18 19:23:50 +05302110 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2111 goto out_unlock;
2112 if (!timeleft)
2113 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002114 goto out_unlock;
2115 }
2116
2117 /* a reply frame is expected */
2118 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302119 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002120 error = -ENXIO;
2121 goto out_unlock;
2122 }
2123
2124 /* process the completed Reply Message Frame */
2125 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2126 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002127 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002128 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002129 error = -ENXIO;
2130 goto out_unlock;
2131 }
2132
2133 error = 0;
2134
2135 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302136 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002137 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002138 out:
2139 return error;
2140}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002141
Christoph Hellwige3094442006-02-16 13:25:36 +01002142static int
2143mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2144{
2145 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2146 int i, error;
2147 struct mptsas_portinfo *p;
2148 struct mptsas_enclosure enclosure_info;
2149 u64 enclosure_handle;
2150
2151 mutex_lock(&ioc->sas_topology_mutex);
2152 list_for_each_entry(p, &ioc->sas_topology, list) {
2153 for (i = 0; i < p->num_phys; i++) {
2154 if (p->phy_info[i].attached.sas_address ==
2155 rphy->identify.sas_address) {
2156 enclosure_handle = p->phy_info[i].
2157 attached.handle_enclosure;
2158 goto found_info;
2159 }
2160 }
2161 }
2162 mutex_unlock(&ioc->sas_topology_mutex);
2163 return -ENXIO;
2164
2165 found_info:
2166 mutex_unlock(&ioc->sas_topology_mutex);
2167 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002168 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002169 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2170 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2171 if (!error)
2172 *identifier = enclosure_info.enclosure_logical_id;
2173 return error;
2174}
2175
2176static int
2177mptsas_get_bay_identifier(struct sas_rphy *rphy)
2178{
2179 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2180 struct mptsas_portinfo *p;
2181 int i, rc;
2182
2183 mutex_lock(&ioc->sas_topology_mutex);
2184 list_for_each_entry(p, &ioc->sas_topology, list) {
2185 for (i = 0; i < p->num_phys; i++) {
2186 if (p->phy_info[i].attached.sas_address ==
2187 rphy->identify.sas_address) {
2188 rc = p->phy_info[i].attached.slot;
2189 goto out;
2190 }
2191 }
2192 }
2193 rc = -ENXIO;
2194 out:
2195 mutex_unlock(&ioc->sas_topology_mutex);
2196 return rc;
2197}
2198
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002199static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2200 struct request *req)
2201{
2202 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2203 MPT_FRAME_HDR *mf;
2204 SmpPassthroughRequest_t *smpreq;
2205 struct request *rsp = req->next_rq;
2206 int ret;
2207 int flagsLength;
2208 unsigned long timeleft;
2209 char *psge;
2210 dma_addr_t dma_addr_in = 0;
2211 dma_addr_t dma_addr_out = 0;
2212 u64 sas_address = 0;
2213
2214 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002215 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002216 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002217 return -EINVAL;
2218 }
2219
2220 /* do we need to support multiple segments? */
2221 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002222 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002223 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2224 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002225 return -EINVAL;
2226 }
2227
2228 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2229 if (ret)
2230 goto out;
2231
2232 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2233 if (!mf) {
2234 ret = -ENOMEM;
2235 goto out_unlock;
2236 }
2237
2238 smpreq = (SmpPassthroughRequest_t *)mf;
2239 memset(smpreq, 0, sizeof(*smpreq));
2240
Tejun Heob0790412009-05-07 22:24:42 +09002241 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002242 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2243
2244 if (rphy)
2245 sas_address = rphy->identify.sas_address;
2246 else {
2247 struct mptsas_portinfo *port_info;
2248
2249 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302250 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002251 if (port_info && port_info->phy_info)
2252 sas_address =
2253 port_info->phy_info[0].phy->identify.sas_address;
2254 mutex_unlock(&ioc->sas_topology_mutex);
2255 }
2256
2257 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2258
2259 psge = (char *)
2260 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2261
2262 /* request */
2263 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2264 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302265 MPI_SGE_FLAGS_DIRECTION)
2266 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002267 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002268
2269 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002270 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002271 if (!dma_addr_out)
2272 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302273 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302274 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002275
2276 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302277 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2278 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2279 MPI_SGE_FLAGS_IOC_TO_HOST |
2280 MPI_SGE_FLAGS_END_OF_BUFFER;
2281
2282 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002283 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002284 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002285 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002286 if (!dma_addr_in)
2287 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302288 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002289
Kashyap, Desai2f187862009-05-29 16:52:37 +05302290 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002291 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2292
2293 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302294 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2295 ret = -ETIME;
2296 mpt_free_msg_frame(ioc, mf);
2297 mf = NULL;
2298 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2299 goto unmap;
2300 if (!timeleft)
2301 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002302 goto unmap;
2303 }
2304 mf = NULL;
2305
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302306 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002307 SmpPassthroughReply_t *smprep;
2308
2309 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2310 memcpy(req->sense, smprep, sizeof(*smprep));
2311 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002312 req->resid_len = 0;
2313 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002314 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302315 printk(MYIOC_s_ERR_FMT
2316 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002317 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002318 ret = -ENXIO;
2319 }
2320unmap:
2321 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002322 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002323 PCI_DMA_BIDIRECTIONAL);
2324 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002325 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002326 PCI_DMA_BIDIRECTIONAL);
2327put_mf:
2328 if (mf)
2329 mpt_free_msg_frame(ioc, mf);
2330out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302331 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002332 mutex_unlock(&ioc->sas_mgmt.mutex);
2333out:
2334 return ret;
2335}
2336
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002337static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002338 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002339 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2340 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002341 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002342 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002343};
2344
2345static struct scsi_transport_template *mptsas_transport_template;
2346
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002347static int
2348mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2349{
2350 ConfigExtendedPageHeader_t hdr;
2351 CONFIGPARMS cfg;
2352 SasIOUnitPage0_t *buffer;
2353 dma_addr_t dma_handle;
2354 int error, i;
2355
2356 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2357 hdr.ExtPageLength = 0;
2358 hdr.PageNumber = 0;
2359 hdr.Reserved1 = 0;
2360 hdr.Reserved2 = 0;
2361 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2362 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2363
2364 cfg.cfghdr.ehdr = &hdr;
2365 cfg.physAddr = -1;
2366 cfg.pageAddr = 0;
2367 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2368 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302369 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002370
2371 error = mpt_config(ioc, &cfg);
2372 if (error)
2373 goto out;
2374 if (!hdr.ExtPageLength) {
2375 error = -ENXIO;
2376 goto out;
2377 }
2378
2379 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2380 &dma_handle);
2381 if (!buffer) {
2382 error = -ENOMEM;
2383 goto out;
2384 }
2385
2386 cfg.physAddr = dma_handle;
2387 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2388
2389 error = mpt_config(ioc, &cfg);
2390 if (error)
2391 goto out_free_consistent;
2392
2393 port_info->num_phys = buffer->NumPhys;
2394 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302395 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002396 if (!port_info->phy_info) {
2397 error = -ENOMEM;
2398 goto out_free_consistent;
2399 }
2400
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302401 ioc->nvdata_version_persistent =
2402 le16_to_cpu(buffer->NvdataVersionPersistent);
2403 ioc->nvdata_version_default =
2404 le16_to_cpu(buffer->NvdataVersionDefault);
2405
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002406 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302407 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002408 port_info->phy_info[i].phy_id = i;
2409 port_info->phy_info[i].port_id =
2410 buffer->PhyData[i].Port;
2411 port_info->phy_info[i].negotiated_link_rate =
2412 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002413 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002414 port_info->phy_info[i].handle =
2415 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002416 }
2417
2418 out_free_consistent:
2419 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2420 buffer, dma_handle);
2421 out:
2422 return error;
2423}
2424
2425static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302426mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2427{
2428 ConfigExtendedPageHeader_t hdr;
2429 CONFIGPARMS cfg;
2430 SasIOUnitPage1_t *buffer;
2431 dma_addr_t dma_handle;
2432 int error;
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302433 u8 device_missing_delay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302434
2435 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2436 memset(&cfg, 0, sizeof(CONFIGPARMS));
2437
2438 cfg.cfghdr.ehdr = &hdr;
2439 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302440 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302441 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2442 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2443 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2444 cfg.cfghdr.ehdr->PageNumber = 1;
2445
2446 error = mpt_config(ioc, &cfg);
2447 if (error)
2448 goto out;
2449 if (!hdr.ExtPageLength) {
2450 error = -ENXIO;
2451 goto out;
2452 }
2453
2454 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2455 &dma_handle);
2456 if (!buffer) {
2457 error = -ENOMEM;
2458 goto out;
2459 }
2460
2461 cfg.physAddr = dma_handle;
2462 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2463
2464 error = mpt_config(ioc, &cfg);
2465 if (error)
2466 goto out_free_consistent;
2467
2468 ioc->io_missing_delay =
2469 le16_to_cpu(buffer->IODeviceMissingDelay);
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302470 device_missing_delay = buffer->ReportDeviceMissingDelay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302471 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2472 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2473 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2474
2475 out_free_consistent:
2476 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2477 buffer, dma_handle);
2478 out:
2479 return error;
2480}
2481
2482static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002483mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2484 u32 form, u32 form_specific)
2485{
2486 ConfigExtendedPageHeader_t hdr;
2487 CONFIGPARMS cfg;
2488 SasPhyPage0_t *buffer;
2489 dma_addr_t dma_handle;
2490 int error;
2491
2492 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2493 hdr.ExtPageLength = 0;
2494 hdr.PageNumber = 0;
2495 hdr.Reserved1 = 0;
2496 hdr.Reserved2 = 0;
2497 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2498 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2499
2500 cfg.cfghdr.ehdr = &hdr;
2501 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302502 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002503
2504 /* Get Phy Pg 0 for each Phy. */
2505 cfg.physAddr = -1;
2506 cfg.pageAddr = form + form_specific;
2507 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2508
2509 error = mpt_config(ioc, &cfg);
2510 if (error)
2511 goto out;
2512
2513 if (!hdr.ExtPageLength) {
2514 error = -ENXIO;
2515 goto out;
2516 }
2517
2518 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2519 &dma_handle);
2520 if (!buffer) {
2521 error = -ENOMEM;
2522 goto out;
2523 }
2524
2525 cfg.physAddr = dma_handle;
2526 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2527
2528 error = mpt_config(ioc, &cfg);
2529 if (error)
2530 goto out_free_consistent;
2531
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302532 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002533
2534 phy_info->hw_link_rate = buffer->HwLinkRate;
2535 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2536 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2537 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2538
2539 out_free_consistent:
2540 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2541 buffer, dma_handle);
2542 out:
2543 return error;
2544}
2545
2546static int
2547mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2548 u32 form, u32 form_specific)
2549{
2550 ConfigExtendedPageHeader_t hdr;
2551 CONFIGPARMS cfg;
2552 SasDevicePage0_t *buffer;
2553 dma_addr_t dma_handle;
2554 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002555 int error=0;
2556
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002557 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2558 hdr.ExtPageLength = 0;
2559 hdr.PageNumber = 0;
2560 hdr.Reserved1 = 0;
2561 hdr.Reserved2 = 0;
2562 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2563 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2564
2565 cfg.cfghdr.ehdr = &hdr;
2566 cfg.pageAddr = form + form_specific;
2567 cfg.physAddr = -1;
2568 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2569 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302570 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002571
Moore, Ericdb9c9172006-03-14 09:14:18 -07002572 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002573 error = mpt_config(ioc, &cfg);
2574 if (error)
2575 goto out;
2576 if (!hdr.ExtPageLength) {
2577 error = -ENXIO;
2578 goto out;
2579 }
2580
2581 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2582 &dma_handle);
2583 if (!buffer) {
2584 error = -ENOMEM;
2585 goto out;
2586 }
2587
2588 cfg.physAddr = dma_handle;
2589 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2590
2591 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302592
2593 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2594 error = -ENODEV;
2595 goto out_free_consistent;
2596 }
2597
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002598 if (error)
2599 goto out_free_consistent;
2600
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302601 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002602
Kashyap, Desai2f187862009-05-29 16:52:37 +05302603 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002604 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002605 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002606 device_info->handle_enclosure =
2607 le16_to_cpu(buffer->EnclosureHandle);
2608 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002609 device_info->phy_id = buffer->PhyNum;
2610 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002611 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002612 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01002613 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002614 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2615 device_info->sas_address = le64_to_cpu(sas_address);
2616 device_info->device_info =
2617 le32_to_cpu(buffer->DeviceInfo);
Kashyap, Desai51106ab2010-06-17 14:40:10 +05302618 device_info->flags = le16_to_cpu(buffer->Flags);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002619
2620 out_free_consistent:
2621 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2622 buffer, dma_handle);
2623 out:
2624 return error;
2625}
2626
2627static int
2628mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2629 u32 form, u32 form_specific)
2630{
2631 ConfigExtendedPageHeader_t hdr;
2632 CONFIGPARMS cfg;
2633 SasExpanderPage0_t *buffer;
2634 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002635 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302636 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002637
Kashyap, Desai2f187862009-05-29 16:52:37 +05302638 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002639 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2640 hdr.ExtPageLength = 0;
2641 hdr.PageNumber = 0;
2642 hdr.Reserved1 = 0;
2643 hdr.Reserved2 = 0;
2644 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2645 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2646
2647 cfg.cfghdr.ehdr = &hdr;
2648 cfg.physAddr = -1;
2649 cfg.pageAddr = form + form_specific;
2650 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2651 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302652 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002653
Moore, Ericdb9c9172006-03-14 09:14:18 -07002654 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002655 error = mpt_config(ioc, &cfg);
2656 if (error)
2657 goto out;
2658
2659 if (!hdr.ExtPageLength) {
2660 error = -ENXIO;
2661 goto out;
2662 }
2663
2664 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2665 &dma_handle);
2666 if (!buffer) {
2667 error = -ENOMEM;
2668 goto out;
2669 }
2670
2671 cfg.physAddr = dma_handle;
2672 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2673
2674 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302675 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002676 error = -ENODEV;
2677 goto out_free_consistent;
2678 }
2679
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302680 if (error)
2681 goto out_free_consistent;
2682
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002683 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302684 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002685 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302686 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002687 if (!port_info->phy_info) {
2688 error = -ENOMEM;
2689 goto out_free_consistent;
2690 }
2691
Kashyap, Desai2f187862009-05-29 16:52:37 +05302692 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002693 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002694 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002695 port_info->phy_info[i].handle =
2696 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302697 port_info->phy_info[i].identify.sas_address =
2698 le64_to_cpu(sas_address);
2699 port_info->phy_info[i].identify.handle_parent =
2700 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002701 }
Eric Moore547f9a22006-06-27 14:42:12 -06002702
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002703 out_free_consistent:
2704 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2705 buffer, dma_handle);
2706 out:
2707 return error;
2708}
2709
2710static int
2711mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2712 u32 form, u32 form_specific)
2713{
2714 ConfigExtendedPageHeader_t hdr;
2715 CONFIGPARMS cfg;
2716 SasExpanderPage1_t *buffer;
2717 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002718 int error=0;
2719
Kashyap, Desai2f187862009-05-29 16:52:37 +05302720 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002721 hdr.ExtPageLength = 0;
2722 hdr.PageNumber = 1;
2723 hdr.Reserved1 = 0;
2724 hdr.Reserved2 = 0;
2725 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2726 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2727
2728 cfg.cfghdr.ehdr = &hdr;
2729 cfg.physAddr = -1;
2730 cfg.pageAddr = form + form_specific;
2731 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2732 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302733 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002734
2735 error = mpt_config(ioc, &cfg);
2736 if (error)
2737 goto out;
2738
2739 if (!hdr.ExtPageLength) {
2740 error = -ENXIO;
2741 goto out;
2742 }
2743
2744 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2745 &dma_handle);
2746 if (!buffer) {
2747 error = -ENOMEM;
2748 goto out;
2749 }
2750
2751 cfg.physAddr = dma_handle;
2752 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2753
2754 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302755
2756 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2757 error = -ENODEV;
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302758 goto out_free_consistent;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302759 }
2760
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002761 if (error)
2762 goto out_free_consistent;
2763
2764
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302765 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002766
2767 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002768 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002769 phy_info->port_id = buffer->PhysicalPort;
2770 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2771 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2772 phy_info->hw_link_rate = buffer->HwLinkRate;
2773 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2774 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2775
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002776 out_free_consistent:
2777 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2778 buffer, dma_handle);
2779 out:
2780 return error;
2781}
2782
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302783struct rep_manu_request{
2784 u8 smp_frame_type;
2785 u8 function;
2786 u8 reserved;
2787 u8 request_length;
2788};
2789
2790struct rep_manu_reply{
2791 u8 smp_frame_type; /* 0x41 */
2792 u8 function; /* 0x01 */
2793 u8 function_result;
2794 u8 response_length;
2795 u16 expander_change_count;
2796 u8 reserved0[2];
2797 u8 sas_format:1;
2798 u8 reserved1:7;
2799 u8 reserved2[3];
2800 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2801 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2802 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2803 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2804 u16 component_id;
2805 u8 component_revision_id;
2806 u8 reserved3;
2807 u8 vendor_specific[8];
2808};
2809
2810/**
2811 * mptsas_exp_repmanufacture_info -
2812 * @ioc: per adapter object
2813 * @sas_address: expander sas address
2814 * @edev: the sas_expander_device object
2815 *
2816 * Fills in the sas_expander_device object when SMP port is created.
2817 *
2818 * Returns 0 for success, non-zero for failure.
2819 */
2820static int
2821mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2822 u64 sas_address, struct sas_expander_device *edev)
2823{
2824 MPT_FRAME_HDR *mf;
2825 SmpPassthroughRequest_t *smpreq;
2826 SmpPassthroughReply_t *smprep;
2827 struct rep_manu_reply *manufacture_reply;
2828 struct rep_manu_request *manufacture_request;
2829 int ret;
2830 int flagsLength;
2831 unsigned long timeleft;
2832 char *psge;
2833 unsigned long flags;
2834 void *data_out = NULL;
2835 dma_addr_t data_out_dma = 0;
2836 u32 sz;
2837
2838 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2839 if (ioc->ioc_reset_in_progress) {
2840 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2841 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2842 __func__, ioc->name);
2843 return -EFAULT;
2844 }
2845 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2846
2847 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2848 if (ret)
2849 goto out;
2850
2851 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2852 if (!mf) {
2853 ret = -ENOMEM;
2854 goto out_unlock;
2855 }
2856
2857 smpreq = (SmpPassthroughRequest_t *)mf;
2858 memset(smpreq, 0, sizeof(*smpreq));
2859
2860 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2861
2862 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2863 if (!data_out) {
2864 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2865 __FILE__, __LINE__, __func__);
2866 ret = -ENOMEM;
2867 goto put_mf;
2868 }
2869
2870 manufacture_request = data_out;
2871 manufacture_request->smp_frame_type = 0x40;
2872 manufacture_request->function = 1;
2873 manufacture_request->reserved = 0;
2874 manufacture_request->request_length = 0;
2875
2876 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2877 smpreq->PhysicalPort = 0xFF;
2878 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2879 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2880
2881 psge = (char *)
2882 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2883
2884 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2885 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2886 MPI_SGE_FLAGS_HOST_TO_IOC |
2887 MPI_SGE_FLAGS_END_OF_BUFFER;
2888 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2889 flagsLength |= sizeof(struct rep_manu_request);
2890
2891 ioc->add_sge(psge, flagsLength, data_out_dma);
2892 psge += ioc->SGE_size;
2893
2894 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2895 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2896 MPI_SGE_FLAGS_IOC_TO_HOST |
2897 MPI_SGE_FLAGS_END_OF_BUFFER;
2898 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2899 flagsLength |= sizeof(struct rep_manu_reply);
2900 ioc->add_sge(psge, flagsLength, data_out_dma +
2901 sizeof(struct rep_manu_request));
2902
2903 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2904 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2905
2906 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2907 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2908 ret = -ETIME;
2909 mpt_free_msg_frame(ioc, mf);
2910 mf = NULL;
2911 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2912 goto out_free;
2913 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302914 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302915 goto out_free;
2916 }
2917
2918 mf = NULL;
2919
2920 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2921 u8 *tmp;
2922
2923 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2924 if (le16_to_cpu(smprep->ResponseDataLength) !=
2925 sizeof(struct rep_manu_reply))
2926 goto out_free;
2927
2928 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2929 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2930 SAS_EXPANDER_VENDOR_ID_LEN);
2931 strncpy(edev->product_id, manufacture_reply->product_id,
2932 SAS_EXPANDER_PRODUCT_ID_LEN);
2933 strncpy(edev->product_rev, manufacture_reply->product_rev,
2934 SAS_EXPANDER_PRODUCT_REV_LEN);
2935 edev->level = manufacture_reply->sas_format;
2936 if (manufacture_reply->sas_format) {
2937 strncpy(edev->component_vendor_id,
2938 manufacture_reply->component_vendor_id,
2939 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2940 tmp = (u8 *)&manufacture_reply->component_id;
2941 edev->component_id = tmp[0] << 8 | tmp[1];
2942 edev->component_revision_id =
2943 manufacture_reply->component_revision_id;
2944 }
2945 } else {
2946 printk(MYIOC_s_ERR_FMT
2947 "%s: smp passthru reply failed to be returned\n",
2948 ioc->name, __func__);
2949 ret = -ENXIO;
2950 }
2951out_free:
2952 if (data_out_dma)
2953 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2954put_mf:
2955 if (mf)
2956 mpt_free_msg_frame(ioc, mf);
2957out_unlock:
2958 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2959 mutex_unlock(&ioc->sas_mgmt.mutex);
2960out:
2961 return ret;
2962 }
2963
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002964static void
2965mptsas_parse_device_info(struct sas_identify *identify,
2966 struct mptsas_devinfo *device_info)
2967{
2968 u16 protocols;
2969
2970 identify->sas_address = device_info->sas_address;
2971 identify->phy_identifier = device_info->phy_id;
2972
2973 /*
2974 * Fill in Phy Initiator Port Protocol.
2975 * Bits 6:3, more than one bit can be set, fall through cases.
2976 */
2977 protocols = device_info->device_info & 0x78;
2978 identify->initiator_port_protocols = 0;
2979 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2980 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2981 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2982 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2983 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2984 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2985 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2986 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2987
2988 /*
2989 * Fill in Phy Target Port Protocol.
2990 * Bits 10:7, more than one bit can be set, fall through cases.
2991 */
2992 protocols = device_info->device_info & 0x780;
2993 identify->target_port_protocols = 0;
2994 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2995 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2996 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2997 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2998 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2999 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
3000 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
3001 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
3002
3003 /*
3004 * Fill in Attached device type.
3005 */
3006 switch (device_info->device_info &
3007 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
3008 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
3009 identify->device_type = SAS_PHY_UNUSED;
3010 break;
3011 case MPI_SAS_DEVICE_INFO_END_DEVICE:
3012 identify->device_type = SAS_END_DEVICE;
3013 break;
3014 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
3015 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
3016 break;
3017 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
3018 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
3019 break;
3020 }
3021}
3022
3023static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003024 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003025{
Moore, Erice6b2d762006-03-14 09:14:24 -07003026 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003027 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06003028 struct sas_port *port;
3029 int error = 0;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303030 VirtTarget *vtarget;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003031
Eric Moore547f9a22006-06-27 14:42:12 -06003032 if (!dev) {
3033 error = -ENODEV;
3034 goto out;
3035 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003036
3037 if (!phy_info->phy) {
3038 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06003039 if (!phy) {
3040 error = -ENOMEM;
3041 goto out;
3042 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003043 } else
3044 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003045
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003046 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003047
3048 /*
3049 * Set Negotiated link rate.
3050 */
3051 switch (phy_info->negotiated_link_rate) {
3052 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003053 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003054 break;
3055 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003056 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003057 break;
3058 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003059 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003060 break;
3061 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003062 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003063 break;
3064 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
3065 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
3066 default:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003067 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003068 break;
3069 }
3070
3071 /*
3072 * Set Max hardware link rate.
3073 */
3074 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3075 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003076 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003077 break;
3078 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003079 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003080 break;
3081 default:
3082 break;
3083 }
3084
3085 /*
3086 * Set Max programmed link rate.
3087 */
3088 switch (phy_info->programmed_link_rate &
3089 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3090 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003091 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003092 break;
3093 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003094 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003095 break;
3096 default:
3097 break;
3098 }
3099
3100 /*
3101 * Set Min hardware link rate.
3102 */
3103 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3104 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003105 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003106 break;
3107 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003108 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003109 break;
3110 default:
3111 break;
3112 }
3113
3114 /*
3115 * Set Min programmed link rate.
3116 */
3117 switch (phy_info->programmed_link_rate &
3118 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3119 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003120 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003121 break;
3122 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003123 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003124 break;
3125 default:
3126 break;
3127 }
3128
Moore, Erice6b2d762006-03-14 09:14:24 -07003129 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003130
Moore, Erice6b2d762006-03-14 09:14:24 -07003131 error = sas_phy_add(phy);
3132 if (error) {
3133 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003134 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003135 }
3136 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003137 }
3138
Eric Moore547f9a22006-06-27 14:42:12 -06003139 if (!phy_info->attached.handle ||
3140 !phy_info->port_details)
3141 goto out;
3142
3143 port = mptsas_get_port(phy_info);
3144 ioc = phy_to_ioc(phy_info->phy);
3145
3146 if (phy_info->sas_port_add_phy) {
3147
3148 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003149 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003150 if (!port) {
3151 error = -ENOMEM;
3152 goto out;
3153 }
3154 error = sas_port_add(port);
3155 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303156 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003157 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003158 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003159 goto out;
3160 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303161 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303162 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3163 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3164 ioc->name, port->port_identifier,
3165 (unsigned long long)phy_info->
3166 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003167 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303168 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3169 "sas_port_add_phy: phy_id=%d\n",
3170 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003171 sas_port_add_phy(port, phy_info->phy);
3172 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303173 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3174 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3175 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003176 }
Eric Moore547f9a22006-06-27 14:42:12 -06003177 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003178
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003179 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003180 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003181 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003182
James Bottomley2686de22006-06-30 12:54:02 -05003183 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003184 /*
3185 * Let the hotplug_work thread handle processing
3186 * the adding/removing of devices that occur
3187 * after start of day.
3188 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303189 if (mptsas_is_end_device(&phy_info->attached) &&
3190 phy_info->attached.handle_parent) {
3191 goto out;
3192 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003193
James Bottomleyf013db32006-03-18 14:54:36 -06003194 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003195 if (scsi_is_host_device(parent)) {
3196 struct mptsas_portinfo *port_info;
3197 int i;
3198
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303199 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003200
3201 for (i = 0; i < port_info->num_phys; i++)
3202 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003203 identify.sas_address) {
3204 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003205 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003206 }
James Bottomley2686de22006-06-30 12:54:02 -05003207
3208 } else if (scsi_is_sas_rphy(parent)) {
3209 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3210 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003211 parent_rphy->identify.sas_address) {
3212 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003213 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003214 }
James Bottomley2686de22006-06-30 12:54:02 -05003215 }
3216
James Bottomleyf013db32006-03-18 14:54:36 -06003217 switch (identify.device_type) {
3218 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003219 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003220 break;
3221 case SAS_EDGE_EXPANDER_DEVICE:
3222 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003223 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003224 break;
3225 default:
3226 rphy = NULL;
3227 break;
3228 }
Eric Moore547f9a22006-06-27 14:42:12 -06003229 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303230 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003231 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003232 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003233 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003234 }
3235
Eric Moore547f9a22006-06-27 14:42:12 -06003236 rphy->identify = identify;
3237 error = sas_rphy_add(rphy);
3238 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303239 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003240 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003241 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003242 sas_rphy_free(rphy);
3243 goto out;
3244 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303245 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303246 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3247 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3248 mptsas_exp_repmanufacture_info(ioc,
3249 identify.sas_address,
3250 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003251 }
3252
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303253 /* If the device exists,verify it wasn't previously flagged
3254 as a missing device. If so, clear it */
3255 vtarget = mptsas_find_vtarget(ioc,
3256 phy_info->attached.channel,
3257 phy_info->attached.id);
3258 if (vtarget && vtarget->inDMD) {
3259 printk(KERN_INFO "Device returned, unsetting inDMD\n");
3260 vtarget->inDMD = 0;
3261 }
3262
Eric Moore547f9a22006-06-27 14:42:12 -06003263 out:
3264 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003265}
3266
3267static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003268mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003269{
Moore, Erice6b2d762006-03-14 09:14:24 -07003270 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003271 int error = -ENOMEM, i;
3272
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303273 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003274 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003275 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003276
Moore, Erice6b2d762006-03-14 09:14:24 -07003277 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003278 if (error)
3279 goto out_free_port_info;
3280
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303281 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003282 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303283 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003284 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303285 ioc->hba_port_info = port_info = hba;
3286 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003287 list_add_tail(&port_info->list, &ioc->sas_topology);
3288 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003289 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003290 port_info->phy_info[i].negotiated_link_rate =
3291 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003292 port_info->phy_info[i].handle =
3293 hba->phy_info[i].handle;
3294 port_info->phy_info[i].port_id =
3295 hba->phy_info[i].port_id;
3296 }
Eric Moore547f9a22006-06-27 14:42:12 -06003297 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003298 kfree(hba);
3299 hba = NULL;
3300 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01003301 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303302#if defined(CPQ_CIM)
3303 ioc->num_ports = port_info->num_phys;
3304#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003305 for (i = 0; i < port_info->num_phys; i++) {
3306 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3307 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3308 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303309 port_info->phy_info[i].identify.handle =
3310 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003311 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003312 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3313 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303314 port_info->phy_info[i].identify.handle);
3315 if (!ioc->hba_port_sas_addr)
3316 ioc->hba_port_sas_addr =
3317 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003318 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003319 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003320 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003321 mptsas_sas_device_pg0(ioc,
3322 &port_info->phy_info[i].attached,
3323 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3324 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3325 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003326 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003327
Eric Moore547f9a22006-06-27 14:42:12 -06003328 mptsas_setup_wide_ports(ioc, port_info);
3329
3330 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003331 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003332 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003333
3334 return 0;
3335
3336 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003337 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003338 out:
3339 return error;
3340}
3341
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303342static void
3343mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003344{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303345 struct mptsas_portinfo *parent;
3346 struct device *parent_dev;
3347 struct sas_rphy *rphy;
3348 int i;
3349 u64 sas_address; /* expander sas address */
3350 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003351
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303352 handle = port_info->phy_info[0].handle;
3353 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003354 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003355 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303356 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3357 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003358
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303359 mptsas_sas_device_pg0(ioc,
3360 &port_info->phy_info[i].identify,
3361 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3362 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3363 port_info->phy_info[i].identify.handle);
3364 port_info->phy_info[i].identify.phy_id =
3365 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003366
3367 if (port_info->phy_info[i].attached.handle) {
3368 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303369 &port_info->phy_info[i].attached,
3370 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3371 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3372 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003373 port_info->phy_info[i].attached.phy_id =
3374 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003375 }
Eric Moore547f9a22006-06-27 14:42:12 -06003376 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003377
Moore, Erice6b2d762006-03-14 09:14:24 -07003378 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303379 parent = mptsas_find_portinfo_by_handle(ioc,
3380 port_info->phy_info[0].identify.handle_parent);
3381 if (!parent) {
3382 mutex_unlock(&ioc->sas_topology_mutex);
3383 return;
3384 }
3385 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3386 i++) {
3387 if (parent->phy_info[i].attached.sas_address == sas_address) {
3388 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3389 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003390 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003391 }
3392 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303393
3394 mptsas_setup_wide_ports(ioc, port_info);
3395 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3396 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3397 ioc->sas_index, 0);
3398}
3399
3400static void
3401mptsas_expander_event_add(MPT_ADAPTER *ioc,
3402 MpiEventDataSasExpanderStatusChange_t *expander_data)
3403{
3404 struct mptsas_portinfo *port_info;
3405 int i;
3406 __le64 sas_address;
3407
3408 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3409 if (!port_info)
3410 BUG();
3411 port_info->num_phys = (expander_data->NumPhys) ?
3412 expander_data->NumPhys : 1;
3413 port_info->phy_info = kcalloc(port_info->num_phys,
3414 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3415 if (!port_info->phy_info)
3416 BUG();
3417 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3418 for (i = 0; i < port_info->num_phys; i++) {
3419 port_info->phy_info[i].portinfo = port_info;
3420 port_info->phy_info[i].handle =
3421 le16_to_cpu(expander_data->DevHandle);
3422 port_info->phy_info[i].identify.sas_address =
3423 le64_to_cpu(sas_address);
3424 port_info->phy_info[i].identify.handle_parent =
3425 le16_to_cpu(expander_data->ParentDevHandle);
3426 }
3427
3428 mutex_lock(&ioc->sas_topology_mutex);
3429 list_add_tail(&port_info->list, &ioc->sas_topology);
3430 mutex_unlock(&ioc->sas_topology_mutex);
3431
3432 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3433 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3434 (unsigned long long)sas_address);
3435
3436 mptsas_expander_refresh(ioc, port_info);
3437}
3438
3439/**
3440 * mptsas_delete_expander_siblings - remove siblings attached to expander
3441 * @ioc: Pointer to MPT_ADAPTER structure
3442 * @parent: the parent port_info object
3443 * @expander: the expander port_info object
3444 **/
3445static void
3446mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3447 *parent, struct mptsas_portinfo *expander)
3448{
3449 struct mptsas_phyinfo *phy_info;
3450 struct mptsas_portinfo *port_info;
3451 struct sas_rphy *rphy;
3452 int i;
3453
3454 phy_info = expander->phy_info;
3455 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3456 rphy = mptsas_get_rphy(phy_info);
3457 if (!rphy)
3458 continue;
3459 if (rphy->identify.device_type == SAS_END_DEVICE)
3460 mptsas_del_end_device(ioc, phy_info);
3461 }
3462
3463 phy_info = expander->phy_info;
3464 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3465 rphy = mptsas_get_rphy(phy_info);
3466 if (!rphy)
3467 continue;
3468 if (rphy->identify.device_type ==
3469 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3470 rphy->identify.device_type ==
3471 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3472 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3473 rphy->identify.sas_address);
3474 if (!port_info)
3475 continue;
3476 if (port_info == parent) /* backlink rphy */
3477 continue;
3478 /*
3479 Delete this expander even if the expdevpage is exists
3480 because the parent expander is already deleted
3481 */
3482 mptsas_expander_delete(ioc, port_info, 1);
3483 }
3484 }
3485}
3486
3487
3488/**
3489 * mptsas_expander_delete - remove this expander
3490 * @ioc: Pointer to MPT_ADAPTER structure
3491 * @port_info: expander port_info struct
3492 * @force: Flag to forcefully delete the expander
3493 *
3494 **/
3495
3496static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3497 struct mptsas_portinfo *port_info, u8 force)
3498{
3499
3500 struct mptsas_portinfo *parent;
3501 int i;
3502 u64 expander_sas_address;
3503 struct mptsas_phyinfo *phy_info;
3504 struct mptsas_portinfo buffer;
3505 struct mptsas_portinfo_details *port_details;
3506 struct sas_port *port;
3507
3508 if (!port_info)
3509 return;
3510
3511 /* see if expander is still there before deleting */
3512 mptsas_sas_expander_pg0(ioc, &buffer,
3513 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3514 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3515 port_info->phy_info[0].identify.handle);
3516
3517 if (buffer.num_phys) {
3518 kfree(buffer.phy_info);
3519 if (!force)
3520 return;
3521 }
3522
3523
3524 /*
3525 * Obtain the port_info instance to the parent port
3526 */
3527 port_details = NULL;
3528 expander_sas_address =
3529 port_info->phy_info[0].identify.sas_address;
3530 parent = mptsas_find_portinfo_by_handle(ioc,
3531 port_info->phy_info[0].identify.handle_parent);
3532 mptsas_delete_expander_siblings(ioc, parent, port_info);
3533 if (!parent)
3534 goto out;
3535
3536 /*
3537 * Delete rphys in the parent that point
3538 * to this expander.
3539 */
3540 phy_info = parent->phy_info;
3541 port = NULL;
3542 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3543 if (!phy_info->phy)
3544 continue;
3545 if (phy_info->attached.sas_address !=
3546 expander_sas_address)
3547 continue;
3548 if (!port) {
3549 port = mptsas_get_port(phy_info);
3550 port_details = phy_info->port_details;
3551 }
3552 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3553 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3554 phy_info->phy_id, phy_info->phy);
3555 sas_port_delete_phy(port, phy_info->phy);
3556 }
3557 if (port) {
3558 dev_printk(KERN_DEBUG, &port->dev,
3559 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3560 ioc->name, port->port_identifier,
3561 (unsigned long long)expander_sas_address);
3562 sas_port_delete(port);
3563 mptsas_port_delete(ioc, port_details);
3564 }
3565 out:
3566
3567 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3568 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3569 (unsigned long long)expander_sas_address);
3570
3571 /*
3572 * free link
3573 */
3574 list_del(&port_info->list);
3575 kfree(port_info->phy_info);
3576 kfree(port_info);
3577}
3578
3579
3580/**
3581 * mptsas_send_expander_event - expanders events
3582 * @ioc: Pointer to MPT_ADAPTER structure
3583 * @expander_data: event data
3584 *
3585 *
3586 * This function handles adding, removing, and refreshing
3587 * device handles within the expander objects.
3588 */
3589static void
3590mptsas_send_expander_event(struct fw_event_work *fw_event)
3591{
3592 MPT_ADAPTER *ioc;
3593 MpiEventDataSasExpanderStatusChange_t *expander_data;
3594 struct mptsas_portinfo *port_info;
3595 __le64 sas_address;
3596 int i;
3597
3598 ioc = fw_event->ioc;
3599 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3600 fw_event->event_data;
3601 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303602 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303603 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3604
3605 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3606 if (port_info) {
3607 for (i = 0; i < port_info->num_phys; i++) {
3608 port_info->phy_info[i].portinfo = port_info;
3609 port_info->phy_info[i].handle =
3610 le16_to_cpu(expander_data->DevHandle);
3611 port_info->phy_info[i].identify.sas_address =
3612 le64_to_cpu(sas_address);
3613 port_info->phy_info[i].identify.handle_parent =
3614 le16_to_cpu(expander_data->ParentDevHandle);
3615 }
3616 mptsas_expander_refresh(ioc, port_info);
3617 } else if (!port_info && expander_data->NumPhys)
3618 mptsas_expander_event_add(ioc, expander_data);
3619 } else if (expander_data->ReasonCode ==
3620 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3621 mptsas_expander_delete(ioc, port_info, 0);
3622
3623 mptsas_free_fw_event(ioc, fw_event);
3624}
3625
3626
3627/**
3628 * mptsas_expander_add -
3629 * @ioc: Pointer to MPT_ADAPTER structure
3630 * @handle:
3631 *
3632 */
3633struct mptsas_portinfo *
3634mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3635{
3636 struct mptsas_portinfo buffer, *port_info;
3637 int i;
3638
3639 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3640 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3641 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3642 return NULL;
3643
3644 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3645 if (!port_info) {
3646 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3647 "%s: exit at line=%d\n", ioc->name,
3648 __func__, __LINE__));
3649 return NULL;
3650 }
3651 port_info->num_phys = buffer.num_phys;
3652 port_info->phy_info = buffer.phy_info;
3653 for (i = 0; i < port_info->num_phys; i++)
3654 port_info->phy_info[i].portinfo = port_info;
3655 mutex_lock(&ioc->sas_topology_mutex);
3656 list_add_tail(&port_info->list, &ioc->sas_topology);
3657 mutex_unlock(&ioc->sas_topology_mutex);
3658 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3659 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3660 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3661 mptsas_expander_refresh(ioc, port_info);
3662 return port_info;
3663}
3664
3665static void
3666mptsas_send_link_status_event(struct fw_event_work *fw_event)
3667{
3668 MPT_ADAPTER *ioc;
3669 MpiEventDataSasPhyLinkStatus_t *link_data;
3670 struct mptsas_portinfo *port_info;
3671 struct mptsas_phyinfo *phy_info = NULL;
3672 __le64 sas_address;
3673 u8 phy_num;
3674 u8 link_rate;
3675
3676 ioc = fw_event->ioc;
3677 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3678
3679 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3680 sas_address = le64_to_cpu(sas_address);
3681 link_rate = link_data->LinkRates >> 4;
3682 phy_num = link_data->PhyNum;
3683
3684 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3685 if (port_info) {
3686 phy_info = &port_info->phy_info[phy_num];
3687 if (phy_info)
3688 phy_info->negotiated_link_rate = link_rate;
3689 }
3690
3691 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3692 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3693
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303694 if (!port_info) {
3695 if (ioc->old_sas_discovery_protocal) {
3696 port_info = mptsas_expander_add(ioc,
3697 le16_to_cpu(link_data->DevHandle));
3698 if (port_info)
3699 goto out;
3700 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303701 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303702 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303703
3704 if (port_info == ioc->hba_port_info)
3705 mptsas_probe_hba_phys(ioc);
3706 else
3707 mptsas_expander_refresh(ioc, port_info);
3708 } else if (phy_info && phy_info->phy) {
3709 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3710 phy_info->phy->negotiated_linkrate =
3711 SAS_PHY_DISABLED;
3712 else if (link_rate ==
3713 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3714 phy_info->phy->negotiated_linkrate =
3715 SAS_LINK_RATE_FAILED;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303716 else {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303717 phy_info->phy->negotiated_linkrate =
3718 SAS_LINK_RATE_UNKNOWN;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05303719 if (ioc->device_missing_delay &&
3720 mptsas_is_end_device(&phy_info->attached)) {
3721 struct scsi_device *sdev;
3722 VirtDevice *vdevice;
3723 u8 channel, id;
3724 id = phy_info->attached.id;
3725 channel = phy_info->attached.channel;
3726 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3727 "Link down for fw_id %d:fw_channel %d\n",
3728 ioc->name, phy_info->attached.id,
3729 phy_info->attached.channel));
3730
3731 shost_for_each_device(sdev, ioc->sh) {
3732 vdevice = sdev->hostdata;
3733 if ((vdevice == NULL) ||
3734 (vdevice->vtarget == NULL))
3735 continue;
3736 if ((vdevice->vtarget->tflags &
3737 MPT_TARGET_FLAGS_RAID_COMPONENT ||
3738 vdevice->vtarget->raidVolume))
3739 continue;
3740 if (vdevice->vtarget->id == id &&
3741 vdevice->vtarget->channel ==
3742 channel)
3743 devtprintk(ioc,
3744 printk(MYIOC_s_DEBUG_FMT
3745 "SDEV OUTSTANDING CMDS"
3746 "%d\n", ioc->name,
3747 sdev->device_busy));
3748 }
3749
3750 }
3751 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303752 }
3753 out:
3754 mptsas_free_fw_event(ioc, fw_event);
3755}
3756
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303757static void
3758mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3759{
3760 struct mptsas_portinfo buffer, *port_info;
3761 struct mptsas_device_info *sas_info;
3762 struct mptsas_devinfo sas_device;
3763 u32 handle;
3764 VirtTarget *vtarget = NULL;
3765 struct mptsas_phyinfo *phy_info;
3766 u8 found_expander;
3767 int retval, retry_count;
3768 unsigned long flags;
3769
3770 mpt_findImVolumes(ioc);
3771
3772 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3773 if (ioc->ioc_reset_in_progress) {
3774 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3775 "%s: exiting due to a parallel reset \n", ioc->name,
3776 __func__));
3777 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3778 return;
3779 }
3780 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3781
3782 /* devices, logical volumes */
3783 mutex_lock(&ioc->sas_device_info_mutex);
3784 redo_device_scan:
3785 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303786 if (sas_info->is_cached)
3787 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303788 if (!sas_info->is_logical_volume) {
3789 sas_device.handle = 0;
3790 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303791retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303792 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303793 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3794 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3795 (sas_info->fw.channel << 8) +
3796 sas_info->fw.id);
3797
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303798 if (sas_device.handle)
3799 continue;
3800 if (retval == -EBUSY) {
3801 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3802 if (ioc->ioc_reset_in_progress) {
3803 dfailprintk(ioc,
3804 printk(MYIOC_s_DEBUG_FMT
3805 "%s: exiting due to reset\n",
3806 ioc->name, __func__));
3807 spin_unlock_irqrestore
3808 (&ioc->taskmgmt_lock, flags);
3809 mutex_unlock(&ioc->
3810 sas_device_info_mutex);
3811 return;
3812 }
3813 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3814 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303815 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303816
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303817 if (retval && (retval != -ENODEV)) {
3818 if (retry_count < 10) {
3819 retry_count++;
3820 goto retry_page;
3821 } else {
3822 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3823 "%s: Config page retry exceeded retry "
3824 "count deleting device 0x%llx\n",
3825 ioc->name, __func__,
3826 sas_info->sas_address));
3827 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303828 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303829
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303830 /* delete device */
3831 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303832 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303833
3834 if (vtarget)
3835 vtarget->deleted = 1;
3836
3837 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3838 sas_info->sas_address);
3839
3840 if (phy_info) {
3841 mptsas_del_end_device(ioc, phy_info);
3842 goto redo_device_scan;
3843 }
3844 } else
3845 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303846 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003847 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303848
3849 /* expanders */
3850 mutex_lock(&ioc->sas_topology_mutex);
3851 redo_expander_scan:
3852 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3853
3854 if (port_info->phy_info &&
3855 (!(port_info->phy_info[0].identify.device_info &
3856 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3857 continue;
3858 found_expander = 0;
3859 handle = 0xFFFF;
3860 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3861 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3862 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3863 !found_expander) {
3864
3865 handle = buffer.phy_info[0].handle;
3866 if (buffer.phy_info[0].identify.sas_address ==
3867 port_info->phy_info[0].identify.sas_address) {
3868 found_expander = 1;
3869 }
3870 kfree(buffer.phy_info);
3871 }
3872
3873 if (!found_expander) {
3874 mptsas_expander_delete(ioc, port_info, 0);
3875 goto redo_expander_scan;
3876 }
3877 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003878 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303879}
3880
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303881/**
3882 * mptsas_probe_expanders - adding expanders
3883 * @ioc: Pointer to MPT_ADAPTER structure
3884 *
3885 **/
3886static void
3887mptsas_probe_expanders(MPT_ADAPTER *ioc)
3888{
3889 struct mptsas_portinfo buffer, *port_info;
3890 u32 handle;
3891 int i;
3892
3893 handle = 0xFFFF;
3894 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3895 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3896 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3897
3898 handle = buffer.phy_info[0].handle;
3899 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3900 buffer.phy_info[0].identify.sas_address);
3901
3902 if (port_info) {
3903 /* refreshing handles */
3904 for (i = 0; i < buffer.num_phys; i++) {
3905 port_info->phy_info[i].handle = handle;
3906 port_info->phy_info[i].identify.handle_parent =
3907 buffer.phy_info[0].identify.handle_parent;
3908 }
3909 mptsas_expander_refresh(ioc, port_info);
3910 kfree(buffer.phy_info);
3911 continue;
3912 }
3913
3914 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3915 if (!port_info) {
3916 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3917 "%s: exit at line=%d\n", ioc->name,
3918 __func__, __LINE__));
3919 return;
3920 }
3921 port_info->num_phys = buffer.num_phys;
3922 port_info->phy_info = buffer.phy_info;
3923 for (i = 0; i < port_info->num_phys; i++)
3924 port_info->phy_info[i].portinfo = port_info;
3925 mutex_lock(&ioc->sas_topology_mutex);
3926 list_add_tail(&port_info->list, &ioc->sas_topology);
3927 mutex_unlock(&ioc->sas_topology_mutex);
3928 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3929 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3930 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3931 mptsas_expander_refresh(ioc, port_info);
3932 }
3933}
3934
3935static void
3936mptsas_probe_devices(MPT_ADAPTER *ioc)
3937{
3938 u16 handle;
3939 struct mptsas_devinfo sas_device;
3940 struct mptsas_phyinfo *phy_info;
3941
3942 handle = 0xFFFF;
3943 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3944 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3945
3946 handle = sas_device.handle;
3947
3948 if ((sas_device.device_info &
3949 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3950 MPI_SAS_DEVICE_INFO_STP_TARGET |
3951 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3952 continue;
3953
Kashyap, Desai51106ab2010-06-17 14:40:10 +05303954 /* If there is no FW B_T mapping for this device then continue
3955 * */
3956 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
3957 || !(sas_device.flags &
3958 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
3959 continue;
3960
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303961 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3962 if (!phy_info)
3963 continue;
3964
3965 if (mptsas_get_rphy(phy_info))
3966 continue;
3967
3968 mptsas_add_end_device(ioc, phy_info);
3969 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003970}
3971
Kashyap, Desai2f187862009-05-29 16:52:37 +05303972/**
3973 * mptsas_scan_sas_topology -
3974 * @ioc: Pointer to MPT_ADAPTER structure
3975 * @sas_address:
3976 *
3977 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003978static void
3979mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3980{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303981 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003982 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003983
Moore, Erice6b2d762006-03-14 09:14:24 -07003984 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303985 mptsas_probe_expanders(ioc);
3986 mptsas_probe_devices(ioc);
3987
Moore, Ericf44e5462006-03-14 09:14:21 -07003988 /*
3989 Reporting RAID volumes.
3990 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303991 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3992 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3993 return;
Eric Moore793955f2007-01-29 09:42:20 -07003994 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303995 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3996 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3997 if (sdev) {
3998 scsi_device_put(sdev);
3999 continue;
4000 }
4001 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4002 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4003 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04004004 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07004005 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
4006 }
Moore, Erice6b2d762006-03-14 09:14:24 -07004007}
4008
Kashyap, Desai57e98512009-05-29 16:55:09 +05304009
4010static void
4011mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
4012{
4013 MPT_ADAPTER *ioc;
4014 EventDataQueueFull_t *qfull_data;
4015 struct mptsas_device_info *sas_info;
4016 struct scsi_device *sdev;
4017 int depth;
4018 int id = -1;
4019 int channel = -1;
4020 int fw_id, fw_channel;
4021 u16 current_depth;
4022
4023
4024 ioc = fw_event->ioc;
4025 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
4026 fw_id = qfull_data->TargetID;
4027 fw_channel = qfull_data->Bus;
4028 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
4029
4030 /* if hidden raid component, look for the volume id */
4031 mutex_lock(&ioc->sas_device_info_mutex);
4032 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
4033 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4034 list) {
4035 if (sas_info->is_cached ||
4036 sas_info->is_logical_volume)
4037 continue;
4038 if (sas_info->is_hidden_raid_component &&
4039 (sas_info->fw.channel == fw_channel &&
4040 sas_info->fw.id == fw_id)) {
4041 id = sas_info->volume_id;
4042 channel = MPTSAS_RAID_CHANNEL;
4043 goto out;
4044 }
4045 }
4046 } else {
4047 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
4048 list) {
4049 if (sas_info->is_cached ||
4050 sas_info->is_hidden_raid_component ||
4051 sas_info->is_logical_volume)
4052 continue;
4053 if (sas_info->fw.channel == fw_channel &&
4054 sas_info->fw.id == fw_id) {
4055 id = sas_info->os.id;
4056 channel = sas_info->os.channel;
4057 goto out;
4058 }
4059 }
4060
4061 }
4062
4063 out:
4064 mutex_unlock(&ioc->sas_device_info_mutex);
4065
4066 if (id != -1) {
4067 shost_for_each_device(sdev, ioc->sh) {
4068 if (sdev->id == id && sdev->channel == channel) {
4069 if (current_depth > sdev->queue_depth) {
4070 sdev_printk(KERN_INFO, sdev,
4071 "strange observation, the queue "
4072 "depth is (%d) meanwhile fw queue "
4073 "depth (%d)\n", sdev->queue_depth,
4074 current_depth);
4075 continue;
4076 }
4077 depth = scsi_track_queue_full(sdev,
4078 current_depth - 1);
4079 if (depth > 0)
4080 sdev_printk(KERN_INFO, sdev,
4081 "Queue depth reduced to (%d)\n",
4082 depth);
4083 else if (depth < 0)
4084 sdev_printk(KERN_INFO, sdev,
4085 "Tagged Command Queueing is being "
4086 "disabled\n");
4087 else if (depth == 0)
4088 sdev_printk(KERN_INFO, sdev,
4089 "Queue depth not changed yet\n");
4090 }
4091 }
4092 }
4093
4094 mptsas_free_fw_event(ioc, fw_event);
4095}
4096
4097
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004098static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06004099mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004100{
4101 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004102 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06004103 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004104
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004105 mutex_lock(&ioc->sas_topology_mutex);
4106 list_for_each_entry(port_info, &ioc->sas_topology, list) {
4107 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06004108 if (!mptsas_is_end_device(
4109 &port_info->phy_info[i].attached))
4110 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004111 if (port_info->phy_info[i].attached.sas_address
4112 != sas_address)
4113 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06004114 phy_info = &port_info->phy_info[i];
4115 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004116 }
4117 }
4118 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004119 return phy_info;
4120}
4121
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304122/**
4123 * mptsas_find_phyinfo_by_phys_disk_num -
4124 * @ioc: Pointer to MPT_ADAPTER structure
4125 * @phys_disk_num:
4126 * @channel:
4127 * @id:
4128 *
4129 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004130static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304131mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4132 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004133{
Eric Mooreb506ade2007-01-29 09:45:37 -07004134 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304135 struct mptsas_portinfo *port_info;
4136 RaidPhysDiskPage1_t *phys_disk = NULL;
4137 int num_paths;
4138 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004139 int i;
4140
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304141 phy_info = NULL;
4142 if (!ioc->raid_data.pIocPg3)
4143 return NULL;
4144 /* dual port support */
4145 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4146 if (!num_paths)
4147 goto out;
4148 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4149 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4150 if (!phys_disk)
4151 goto out;
4152 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4153 for (i = 0; i < num_paths; i++) {
4154 if ((phys_disk->Path[i].Flags & 1) != 0)
4155 /* entry no longer valid */
4156 continue;
4157 if ((id == phys_disk->Path[i].PhysDiskID) &&
4158 (channel == phys_disk->Path[i].PhysDiskBus)) {
4159 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4160 sizeof(u64));
4161 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4162 sas_address);
4163 goto out;
4164 }
4165 }
4166
4167 out:
4168 kfree(phys_disk);
4169 if (phy_info)
4170 return phy_info;
4171
4172 /*
4173 * Extra code to handle RAID0 case, where the sas_address is not updated
4174 * in phys_disk_page_1 when hotswapped
4175 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004176 mutex_lock(&ioc->sas_topology_mutex);
4177 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304178 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004179 if (!mptsas_is_end_device(
4180 &port_info->phy_info[i].attached))
4181 continue;
4182 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4183 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304184 if ((port_info->phy_info[i].attached.phys_disk_num ==
4185 phys_disk_num) &&
4186 (port_info->phy_info[i].attached.id == id) &&
4187 (port_info->phy_info[i].attached.channel ==
4188 channel))
4189 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004190 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004191 }
4192 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004193 return phy_info;
4194}
4195
4196static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004197mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4198{
Eric Mooref99be432007-01-04 20:46:54 -07004199 int rc;
4200
Moore, Ericf44e5462006-03-14 09:14:21 -07004201 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004202 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004203}
4204
4205static void
4206mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4207{
4208 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4209 mptsas_reprobe_lun);
4210}
4211
Eric Mooreb506ade2007-01-29 09:45:37 -07004212static void
4213mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4214{
4215 CONFIGPARMS cfg;
4216 ConfigPageHeader_t hdr;
4217 dma_addr_t dma_handle;
4218 pRaidVolumePage0_t buffer = NULL;
4219 RaidPhysDiskPage0_t phys_disk;
4220 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304221 struct mptsas_phyinfo *phy_info;
4222 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004223
4224 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4225 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4226 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4227 cfg.pageAddr = (channel << 8) + id;
4228 cfg.cfghdr.hdr = &hdr;
4229 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai568da762010-03-18 19:23:50 +05304230 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Eric Mooreb506ade2007-01-29 09:45:37 -07004231
4232 if (mpt_config(ioc, &cfg) != 0)
4233 goto out;
4234
4235 if (!hdr.PageLength)
4236 goto out;
4237
4238 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4239 &dma_handle);
4240
4241 if (!buffer)
4242 goto out;
4243
4244 cfg.physAddr = dma_handle;
4245 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4246
4247 if (mpt_config(ioc, &cfg) != 0)
4248 goto out;
4249
4250 if (!(buffer->VolumeStatus.Flags &
4251 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4252 goto out;
4253
4254 if (!buffer->NumPhysDisks)
4255 goto out;
4256
4257 for (i = 0; i < buffer->NumPhysDisks; i++) {
4258
4259 if (mpt_raid_phys_disk_pg0(ioc,
4260 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4261 continue;
4262
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304263 if (mptsas_sas_device_pg0(ioc, &sas_device,
4264 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4265 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4266 (phys_disk.PhysDiskBus << 8) +
4267 phys_disk.PhysDiskID))
4268 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004269
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304270 /* If there is no FW B_T mapping for this device then continue
4271 * */
4272 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4273 || !(sas_device.flags &
4274 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4275 continue;
4276
4277
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304278 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4279 sas_device.sas_address);
4280 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004281 }
4282
4283 out:
4284 if (buffer)
4285 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4286 dma_handle);
4287}
Moore, Erice6b2d762006-03-14 09:14:24 -07004288/*
4289 * Work queue thread to handle SAS hotplug events
4290 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004291static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304292mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4293 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004294{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004295 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004296 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004297 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004298 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304299 int i;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304300 struct mptsas_portinfo *port_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004301
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304302 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004303
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304304 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004305
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304306 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004307 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004308
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304309 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4310 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4311 hot_plug_info->id) {
4312 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4313 "to add hidden disk - target_id matchs "
4314 "volume_id\n", ioc->name);
4315 mptsas_free_fw_event(ioc, fw_event);
4316 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004317 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004318 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304319 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004320
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004321 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304322 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4323 mptsas_sas_device_pg0(ioc, &sas_device,
4324 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4325 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4326 (hot_plug_info->channel << 8) +
4327 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004328
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304329 /* If there is no FW B_T mapping for this device then break
4330 * */
4331 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4332 || !(sas_device.flags &
4333 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4334 break;
4335
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304336 if (!sas_device.handle)
4337 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004338
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304339 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304340 /* Only For SATA Device ADD */
4341 if (!phy_info && (sas_device.device_info &
4342 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
4343 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4344 "%s %d SATA HOT PLUG: "
4345 "parent handle of device %x\n", ioc->name,
4346 __func__, __LINE__, sas_device.handle_parent));
4347 port_info = mptsas_find_portinfo_by_handle(ioc,
4348 sas_device.handle_parent);
4349
4350 if (port_info == ioc->hba_port_info)
4351 mptsas_probe_hba_phys(ioc);
4352 else if (port_info)
4353 mptsas_expander_refresh(ioc, port_info);
4354 else {
4355 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4356 "%s %d port info is NULL\n",
4357 ioc->name, __func__, __LINE__));
4358 break;
4359 }
4360 phy_info = mptsas_refreshing_device_handles
4361 (ioc, &sas_device);
4362 }
4363
4364 if (!phy_info) {
4365 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4366 "%s %d phy info is NULL\n",
4367 ioc->name, __func__, __LINE__));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304368 break;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304369 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304370
4371 if (mptsas_get_rphy(phy_info))
4372 break;
4373
4374 mptsas_add_end_device(ioc, phy_info);
4375 break;
4376
4377 case MPTSAS_DEL_DEVICE:
4378 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4379 hot_plug_info->sas_address);
4380 mptsas_del_end_device(ioc, phy_info);
4381 break;
4382
4383 case MPTSAS_DEL_PHYSDISK:
4384
4385 mpt_findImVolumes(ioc);
4386
4387 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304388 ioc, hot_plug_info->phys_disk_num,
4389 hot_plug_info->channel,
4390 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304391 mptsas_del_end_device(ioc, phy_info);
4392 break;
4393
4394 case MPTSAS_ADD_PHYSDISK_REPROBE:
4395
Christoph Hellwige3094442006-02-16 13:25:36 +01004396 if (mptsas_sas_device_pg0(ioc, &sas_device,
4397 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004398 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304399 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4400 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4401 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4402 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004403 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004404 }
4405
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304406 /* If there is no FW B_T mapping for this device then break
4407 * */
4408 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4409 || !(sas_device.flags &
4410 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4411 break;
4412
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304413 phy_info = mptsas_find_phyinfo_by_sas_address(
4414 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004415
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304416 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304417 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304418 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4419 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004420 break;
4421 }
4422
4423 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304424 if (!starget) {
4425 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4426 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4427 __func__, hot_plug_info->id, __LINE__));
4428 break;
4429 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004430
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304431 vtarget = starget->hostdata;
4432 if (!vtarget) {
4433 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4434 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4435 __func__, hot_plug_info->id, __LINE__));
4436 break;
4437 }
Eric Moore547f9a22006-06-27 14:42:12 -06004438
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304439 mpt_findImVolumes(ioc);
4440
4441 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4442 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4443 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4444 hot_plug_info->phys_disk_num, (unsigned long long)
4445 sas_device.sas_address);
4446
4447 vtarget->id = hot_plug_info->phys_disk_num;
4448 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4449 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4450 mptsas_reprobe_target(starget, 1);
4451 break;
4452
4453 case MPTSAS_DEL_PHYSDISK_REPROBE:
4454
4455 if (mptsas_sas_device_pg0(ioc, &sas_device,
4456 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4457 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4458 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304459 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304460 "%s: fw_id=%d exit at line=%d\n",
4461 ioc->name, __func__,
4462 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004463 break;
4464 }
4465
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304466 /* If there is no FW B_T mapping for this device then break
4467 * */
4468 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4469 || !(sas_device.flags &
4470 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4471 break;
4472
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304473 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4474 sas_device.sas_address);
4475 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304476 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304477 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4478 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004479 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004480 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004481
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304482 starget = mptsas_get_starget(phy_info);
4483 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304484 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304485 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4486 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004487 break;
4488 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004489
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304490 vtarget = starget->hostdata;
4491 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304492 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304493 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4494 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004495 break;
4496 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304497
4498 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4499 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4500 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4501 __func__, hot_plug_info->id, __LINE__));
4502 break;
4503 }
4504
4505 mpt_findImVolumes(ioc);
4506
4507 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4508 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4509 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4510 hot_plug_info->phys_disk_num, (unsigned long long)
4511 sas_device.sas_address);
4512
4513 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4514 vtarget->id = hot_plug_info->id;
4515 phy_info->attached.phys_disk_num = ~0;
4516 mptsas_reprobe_target(starget, 0);
4517 mptsas_add_device_component_by_fw(ioc,
4518 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004519 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304520
Moore, Ericc73787ee2006-01-26 16:20:06 -07004521 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304522
Moore, Ericc73787ee2006-01-26 16:20:06 -07004523 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304524 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4525 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4526 hot_plug_info->id);
4527 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4528 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004529 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304530
Moore, Ericc73787ee2006-01-26 16:20:06 -07004531 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304532
Moore, Ericc73787ee2006-01-26 16:20:06 -07004533 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304534 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4535 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4536 hot_plug_info->id);
4537 scsi_remove_device(hot_plug_info->sdev);
4538 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004539 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304540
Eric Mooreb506ade2007-01-29 09:45:37 -07004541 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304542
4543 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004544 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304545 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004546 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304547
Moore, Ericbd23e942006-04-17 12:43:04 -06004548 default:
4549 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004550 }
4551
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304552 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004553}
4554
4555static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304556mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004557{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304558 MPT_ADAPTER *ioc;
4559 struct mptsas_hotplug_event hot_plug_info;
4560 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4561 u32 device_info;
4562 u64 sas_address;
4563
4564 ioc = fw_event->ioc;
4565 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4566 fw_event->event_data;
4567 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004568
4569 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304570 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4571 MPI_SAS_DEVICE_INFO_STP_TARGET |
4572 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4573 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004574 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304575 }
4576
4577 if (sas_event_data->ReasonCode ==
4578 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4579 mptbase_sas_persist_operation(ioc,
4580 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4581 mptsas_free_fw_event(ioc, fw_event);
4582 return;
4583 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004584
Moore, Eric4b766472006-03-14 09:14:12 -07004585 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004586 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004587 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304588 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4589 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4590 hot_plug_info.channel = sas_event_data->Bus;
4591 hot_plug_info.id = sas_event_data->TargetID;
4592 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004593 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304594 sizeof(u64));
4595 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4596 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004597 if (sas_event_data->ReasonCode &
4598 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304599 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004600 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304601 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4602 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004603 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304604
Moore, Eric4b766472006-03-14 09:14:12 -07004605 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304606 mptbase_sas_persist_operation(ioc,
4607 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4608 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004609 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304610
Moore, Eric4b766472006-03-14 09:14:12 -07004611 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304612 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004613 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304614 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004615 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304616 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004617 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004618 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004619}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304620
Moore, Ericc73787ee2006-01-26 16:20:06 -07004621static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304622mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004623{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304624 MPT_ADAPTER *ioc;
4625 EVENT_DATA_RAID *raid_event_data;
4626 struct mptsas_hotplug_event hot_plug_info;
4627 int status;
4628 int state;
4629 struct scsi_device *sdev = NULL;
4630 VirtDevice *vdevice = NULL;
4631 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004632
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304633 ioc = fw_event->ioc;
4634 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4635 status = le32_to_cpu(raid_event_data->SettingsStatus);
4636 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004637
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304638 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4639 hot_plug_info.id = raid_event_data->VolumeID;
4640 hot_plug_info.channel = raid_event_data->VolumeBus;
4641 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4642
4643 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4644 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4645 raid_event_data->ReasonCode ==
4646 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4647 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4648 hot_plug_info.id, 0);
4649 hot_plug_info.sdev = sdev;
4650 if (sdev)
4651 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004652 }
4653
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304654 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4655 "ReasonCode=%02x\n", ioc->name, __func__,
4656 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004657
4658 switch (raid_event_data->ReasonCode) {
4659 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304660 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004661 break;
4662 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304663 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004664 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004665 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4666 switch (state) {
4667 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004668 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304669 mpt_raid_phys_disk_pg0(ioc,
4670 raid_event_data->PhysDiskNum, &phys_disk);
4671 hot_plug_info.id = phys_disk.PhysDiskID;
4672 hot_plug_info.channel = phys_disk.PhysDiskBus;
4673 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004674 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304675 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004676 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004677 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4678 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4679 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304680 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004681 break;
4682 default:
4683 break;
4684 }
4685 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004686 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304687 if (!sdev)
4688 break;
4689 vdevice->vtarget->deleted = 1; /* block IO */
4690 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004691 break;
4692 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304693 if (sdev) {
4694 scsi_device_put(sdev);
4695 break;
4696 }
4697 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004698 break;
4699 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304700 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4701 if (!sdev)
4702 break;
4703 vdevice->vtarget->deleted = 1; /* block IO */
4704 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4705 break;
4706 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004707 switch (state) {
4708 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4709 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304710 if (!sdev)
4711 break;
4712 vdevice->vtarget->deleted = 1; /* block IO */
4713 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004714 break;
4715 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4716 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304717 if (sdev) {
4718 scsi_device_put(sdev);
4719 break;
4720 }
4721 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004722 break;
4723 default:
4724 break;
4725 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004726 break;
4727 default:
4728 break;
4729 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304730
4731 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4732 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4733 else
4734 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004735}
4736
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304737/**
4738 * mptsas_issue_tm - send mptsas internal tm request
4739 * @ioc: Pointer to MPT_ADAPTER structure
4740 * @type: Task Management type
4741 * @channel: channel number for task management
4742 * @id: Logical Target ID for reset (if appropriate)
4743 * @lun: Logical unit for reset (if appropriate)
4744 * @task_context: Context for the task to be aborted
4745 * @timeout: timeout for task management control
4746 *
4747 * return 0 on success and -1 on failure:
4748 *
4749 */
4750static int
4751mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4752 int task_context, ulong timeout, u8 *issue_reset)
4753{
4754 MPT_FRAME_HDR *mf;
4755 SCSITaskMgmt_t *pScsiTm;
4756 int retval;
4757 unsigned long timeleft;
4758
4759 *issue_reset = 0;
4760 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4761 if (mf == NULL) {
4762 retval = -1; /* return failure */
4763 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4764 "msg frames!!\n", ioc->name));
4765 goto out;
4766 }
4767
4768 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4769 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4770 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4771 type, timeout, channel, id, (unsigned long long)lun,
4772 task_context));
4773
4774 pScsiTm = (SCSITaskMgmt_t *) mf;
4775 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4776 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4777 pScsiTm->TaskType = type;
4778 pScsiTm->MsgFlags = 0;
4779 pScsiTm->TargetID = id;
4780 pScsiTm->Bus = channel;
4781 pScsiTm->ChainOffset = 0;
4782 pScsiTm->Reserved = 0;
4783 pScsiTm->Reserved1 = 0;
4784 pScsiTm->TaskMsgContext = task_context;
4785 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4786
4787 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4788 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4789 retval = 0;
4790 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4791
4792 /* Now wait for the command to complete */
4793 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4794 timeout*HZ);
4795 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4796 retval = -1; /* return failure */
4797 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4798 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4799 mpt_free_msg_frame(ioc, mf);
4800 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4801 goto out;
4802 *issue_reset = 1;
4803 goto out;
4804 }
4805
4806 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4807 retval = -1; /* return failure */
4808 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4809 "TaskMgmt request: failed with no reply\n", ioc->name));
4810 goto out;
4811 }
4812
4813 out:
4814 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4815 return retval;
4816}
4817
4818/**
4819 * mptsas_broadcast_primative_work - Handle broadcast primitives
4820 * @work: work queue payload containing info describing the event
4821 *
4822 * this will be handled in workqueue context.
4823 */
4824static void
4825mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4826{
4827 MPT_ADAPTER *ioc = fw_event->ioc;
4828 MPT_FRAME_HDR *mf;
4829 VirtDevice *vdevice;
4830 int ii;
4831 struct scsi_cmnd *sc;
4832 SCSITaskMgmtReply_t *pScsiTmReply;
4833 u8 issue_reset;
4834 int task_context;
4835 u8 channel, id;
4836 int lun;
4837 u32 termination_count;
4838 u32 query_count;
4839
4840 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4841 "%s - enter\n", ioc->name, __func__));
4842
4843 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4844 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4845 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4846 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4847 return;
4848 }
4849
4850 issue_reset = 0;
4851 termination_count = 0;
4852 query_count = 0;
4853 mpt_findImVolumes(ioc);
4854 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4855
4856 for (ii = 0; ii < ioc->req_depth; ii++) {
4857 if (ioc->fw_events_off)
4858 goto out;
4859 sc = mptscsih_get_scsi_lookup(ioc, ii);
4860 if (!sc)
4861 continue;
4862 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4863 if (!mf)
4864 continue;
4865 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4866 vdevice = sc->device->hostdata;
4867 if (!vdevice || !vdevice->vtarget)
4868 continue;
4869 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4870 continue; /* skip hidden raid components */
4871 if (vdevice->vtarget->raidVolume)
4872 continue; /* skip hidden raid components */
4873 channel = vdevice->vtarget->channel;
4874 id = vdevice->vtarget->id;
4875 lun = vdevice->lun;
4876 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4877 channel, id, (u64)lun, task_context, 30, &issue_reset))
4878 goto out;
4879 query_count++;
4880 termination_count +=
4881 le32_to_cpu(pScsiTmReply->TerminationCount);
4882 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4883 (pScsiTmReply->ResponseCode ==
4884 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4885 pScsiTmReply->ResponseCode ==
4886 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4887 continue;
4888 if (mptsas_issue_tm(ioc,
4889 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4890 channel, id, (u64)lun, 0, 30, &issue_reset))
4891 goto out;
4892 termination_count +=
4893 le32_to_cpu(pScsiTmReply->TerminationCount);
4894 }
4895
4896 out:
4897 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4898 "%s - exit, query_count = %d termination_count = %d\n",
4899 ioc->name, __func__, query_count, termination_count));
4900
4901 ioc->broadcast_aen_busy = 0;
4902 mpt_clear_taskmgmt_in_progress_flag(ioc);
4903 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4904
4905 if (issue_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09004906 printk(MYIOC_s_WARN_FMT
4907 "Issuing Reset from %s!! doorbell=0x%08x\n",
4908 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304909 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304910 }
4911 mptsas_free_fw_event(ioc, fw_event);
4912}
4913
Eric Mooreb506ade2007-01-29 09:45:37 -07004914/*
4915 * mptsas_send_ir2_event - handle exposing hidden disk when
4916 * an inactive raid volume is added
4917 *
4918 * @ioc: Pointer to MPT_ADAPTER structure
4919 * @ir2_data
4920 *
4921 */
4922static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304923mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004924{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304925 MPT_ADAPTER *ioc;
4926 struct mptsas_hotplug_event hot_plug_info;
4927 MPI_EVENT_DATA_IR2 *ir2_data;
4928 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304929 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004930
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304931 ioc = fw_event->ioc;
4932 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4933 reasonCode = ir2_data->ReasonCode;
4934
4935 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4936 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4937
4938 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4939 hot_plug_info.id = ir2_data->TargetID;
4940 hot_plug_info.channel = ir2_data->Bus;
4941 switch (reasonCode) {
4942 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4943 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4944 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304945 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4946 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4947 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4948 break;
4949 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4950 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4951 mpt_raid_phys_disk_pg0(ioc,
4952 ir2_data->PhysDiskNum, &phys_disk);
4953 hot_plug_info.id = phys_disk.PhysDiskID;
4954 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4955 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304956 default:
4957 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004958 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304959 }
4960 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4961}
Moore, Erice6b2d762006-03-14 09:14:24 -07004962
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004963static int
4964mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4965{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304966 u32 event = le32_to_cpu(reply->Event);
4967 int sz, event_data_sz;
4968 struct fw_event_work *fw_event;
4969 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004970
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304971 if (ioc->bus_type != SAS)
4972 return 0;
4973
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304974 /* events turned off due to host reset or driver unloading */
4975 if (ioc->fw_events_off)
4976 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004977
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304978 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004979 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304980 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4981 {
4982 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4983 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4984 if (broadcast_event_data->Primitive !=
4985 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4986 return 0;
4987 if (ioc->broadcast_aen_busy)
4988 return 0;
4989 ioc->broadcast_aen_busy = 1;
4990 break;
4991 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004992 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304993 {
4994 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4995 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05304996 u16 ioc_stat;
4997 ioc_stat = le16_to_cpu(reply->IOCStatus);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304998
4999 if (sas_event_data->ReasonCode ==
5000 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
5001 mptsas_target_reset_queue(ioc, sas_event_data);
5002 return 0;
5003 }
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305004 if (sas_event_data->ReasonCode ==
5005 MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET &&
5006 ioc->device_missing_delay &&
5007 (ioc_stat & MPI_IOCSTATUS_FLAG_LOG_INFO_AVAILABLE)) {
5008 VirtTarget *vtarget = NULL;
5009 u8 id, channel;
5010 u32 log_info = le32_to_cpu(reply->IOCLogInfo);
5011
5012 id = sas_event_data->TargetID;
5013 channel = sas_event_data->Bus;
5014
5015 vtarget = mptsas_find_vtarget(ioc, channel, id);
5016 if (vtarget) {
5017 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5018 "LogInfo (0x%x) available for "
5019 "INTERNAL_DEVICE_RESET"
5020 "fw_id %d fw_channel %d\n", ioc->name,
5021 log_info, id, channel));
5022 if (vtarget->raidVolume) {
5023 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5024 "Skipping Raid Volume for inDMD\n",
5025 ioc->name));
5026 } else {
5027 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
5028 "Setting device flag inDMD\n",
5029 ioc->name));
5030 vtarget->inDMD = 1;
5031 }
5032
5033 }
5034
5035 }
5036
Moore, Ericc73787ee2006-01-26 16:20:06 -07005037 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305038 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305039 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
5040 {
5041 MpiEventDataSasExpanderStatusChange_t *expander_data =
5042 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
5043
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305044 if (ioc->old_sas_discovery_protocal)
5045 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305046
5047 if (expander_data->ReasonCode ==
5048 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
5049 ioc->device_missing_delay)
5050 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07005051 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305052 }
5053 case MPI_EVENT_SAS_DISCOVERY:
5054 {
5055 u32 discovery_status;
5056 EventDataSasDiscovery_t *discovery_data =
5057 (EventDataSasDiscovery_t *)reply->Data;
5058
5059 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
5060 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305061 if (ioc->old_sas_discovery_protocal && !discovery_status)
5062 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305063 return 0;
5064 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305065 case MPI_EVENT_INTEGRATED_RAID:
5066 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07005067 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305068 case MPI_EVENT_SAS_PHY_LINK_STATUS:
5069 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07005070 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005071 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305072 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005073 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07005074
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305075 event_data_sz = ((reply->MsgLength * 4) -
5076 offsetof(EventNotificationReply_t, Data));
5077 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
5078 fw_event = kzalloc(sz, GFP_ATOMIC);
5079 if (!fw_event) {
5080 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
5081 __func__, __LINE__);
5082 return 0;
5083 }
5084 memcpy(fw_event->event_data, reply->Data, event_data_sz);
5085 fw_event->event = event;
5086 fw_event->ioc = ioc;
5087 mptsas_add_fw_event(ioc, fw_event, delay);
5088 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005089}
5090
Kashyap, Desaia7938b02009-05-29 16:53:56 +05305091/* Delete a volume when no longer listed in ioc pg2
5092 */
5093static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
5094{
5095 struct scsi_device *sdev;
5096 int i;
5097
5098 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
5099 if (!sdev)
5100 return;
5101 if (!ioc->raid_data.pIocPg2)
5102 goto out;
5103 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
5104 goto out;
5105 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
5106 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
5107 goto release_sdev;
5108 out:
5109 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
5110 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
5111 scsi_remove_device(sdev);
5112 release_sdev:
5113 scsi_device_put(sdev);
5114}
5115
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005116static int
5117mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
5118{
5119 struct Scsi_Host *sh;
5120 MPT_SCSI_HOST *hd;
5121 MPT_ADAPTER *ioc;
5122 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01005123 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005124 int numSGE = 0;
5125 int scale;
5126 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005127 int error=0;
5128 int r;
5129
5130 r = mpt_attach(pdev,id);
5131 if (r)
5132 return r;
5133
5134 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305135 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005136 ioc->DoneCtx = mptsasDoneCtx;
5137 ioc->TaskCtx = mptsasTaskCtx;
5138 ioc->InternalCtx = mptsasInternalCtx;
Kashyap, Desaib68bf092010-06-17 14:40:56 +05305139 ioc->schedule_target_reset = &mptsas_schedule_target_reset;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005140 /* Added sanity check on readiness of the MPT adapter.
5141 */
5142 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
5143 printk(MYIOC_s_WARN_FMT
5144 "Skipping because it's not operational!\n",
5145 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005146 error = -ENODEV;
5147 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005148 }
5149
5150 if (!ioc->active) {
5151 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
5152 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005153 error = -ENODEV;
5154 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005155 }
5156
5157 /* Sanity check - ensure at least 1 port is INITIATOR capable
5158 */
5159 ioc_cap = 0;
5160 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
5161 if (ioc->pfacts[ii].ProtocolFlags &
5162 MPI_PORTFACTS_PROTOCOL_INITIATOR)
5163 ioc_cap++;
5164 }
5165
5166 if (!ioc_cap) {
5167 printk(MYIOC_s_WARN_FMT
5168 "Skipping ioc=%p because SCSI Initiator mode "
5169 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005170 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005171 }
5172
5173 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
5174 if (!sh) {
5175 printk(MYIOC_s_WARN_FMT
5176 "Unable to register controller with SCSI subsystem\n",
5177 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005178 error = -1;
5179 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005180 }
5181
5182 spin_lock_irqsave(&ioc->FreeQlock, flags);
5183
5184 /* Attach the SCSI Host to the IOC structure
5185 */
5186 ioc->sh = sh;
5187
5188 sh->io_port = 0;
5189 sh->n_io_port = 0;
5190 sh->irq = 0;
5191
5192 /* set 16 byte cdb's */
5193 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05305194 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5195 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07005196 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005197 sh->transportt = mptsas_transport_template;
5198
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005199 /* Required entry.
5200 */
5201 sh->unique_id = ioc->id;
5202
5203 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005204 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07005205 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01005206 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005207 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005208
5209 /* Verify that we won't exceed the maximum
5210 * number of chain buffers
5211 * We can optimize: ZZ = req_sz/sizeof(SGE)
5212 * For 32bit SGE's:
5213 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5214 * + (req_sz - 64)/sizeof(SGE)
5215 * A slightly different algorithm is required for
5216 * 64bit SGEs.
5217 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305218 scale = ioc->req_sz/ioc->SGE_size;
5219 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005220 numSGE = (scale - 1) *
5221 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305222 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005223 } else {
5224 numSGE = 1 + (scale - 1) *
5225 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305226 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005227 }
5228
5229 if (numSGE < sh->sg_tablesize) {
5230 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305231 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005232 "Resetting sg_tablesize to %d from %d\n",
5233 ioc->name, numSGE, sh->sg_tablesize));
5234 sh->sg_tablesize = numSGE;
5235 }
5236
Eric Mooree7eae9f2007-09-29 10:15:59 -06005237 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005238 hd->ioc = ioc;
5239
5240 /* SCSI needs scsi_cmnd lookup table!
5241 * (with size equal to req_depth*PtrSz!)
5242 */
Eric Mooree8206382007-09-29 10:16:53 -06005243 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5244 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005245 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005246 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005247 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005248 }
Eric Mooree8206382007-09-29 10:16:53 -06005249 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005250
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305251 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005252 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005253
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005254 ioc->sas_data.ptClear = mpt_pt_clear;
5255
Eric Mooredf9e0622007-01-29 09:46:21 -07005256 hd->last_queue_full = 0;
5257 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305258 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5259 mutex_init(&ioc->sas_device_info_mutex);
5260
Eric Mooredf9e0622007-01-29 09:46:21 -07005261 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5262
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005263 if (ioc->sas_data.ptClear==1) {
5264 mptbase_sas_persist_operation(
5265 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5266 }
5267
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005268 error = scsi_add_host(sh, &ioc->pcidev->dev);
5269 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005270 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5271 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005272 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005273 }
5274
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305275 /* older firmware doesn't support expander events */
5276 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5277 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005278 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305279 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005280 return 0;
5281
Eric Moore547f9a22006-06-27 14:42:12 -06005282 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005283
5284 mptscsih_remove(pdev);
5285 return error;
5286}
5287
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305288void
5289mptsas_shutdown(struct pci_dev *pdev)
5290{
5291 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5292
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305293 mptsas_fw_event_off(ioc);
5294 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305295}
5296
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005297static void __devexit mptsas_remove(struct pci_dev *pdev)
5298{
5299 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5300 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005301 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005302
Kashyap, Desai48959f12010-03-18 19:18:30 +05305303 if (!ioc->sh) {
5304 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5305 mpt_detach(pdev);
5306 return;
5307 }
5308
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305309 mptsas_shutdown(pdev);
5310
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305311 mptsas_del_device_components(ioc);
5312
Eric Mooreb506ade2007-01-29 09:45:37 -07005313 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005314 sas_remove_host(ioc->sh);
5315
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005316 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005317 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5318 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005319 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305320 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305321
Eric Moore547f9a22006-06-27 14:42:12 -06005322 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005323 kfree(p);
5324 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005325 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305326 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005327 mptscsih_remove(pdev);
5328}
5329
5330static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005331 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005332 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005333 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005334 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005335 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005336 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005337 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005338 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005339 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005340 PCI_ANY_ID, PCI_ANY_ID },
5341 {0} /* Terminating entry */
5342};
5343MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5344
5345
5346static struct pci_driver mptsas_driver = {
5347 .name = "mptsas",
5348 .id_table = mptsas_pci_table,
5349 .probe = mptsas_probe,
5350 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305351 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005352#ifdef CONFIG_PM
5353 .suspend = mptscsih_suspend,
5354 .resume = mptscsih_resume,
5355#endif
5356};
5357
5358static int __init
5359mptsas_init(void)
5360{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305361 int error;
5362
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005363 show_mptmod_ver(my_NAME, my_VERSION);
5364
5365 mptsas_transport_template =
5366 sas_attach_transport(&mptsas_transport_functions);
5367 if (!mptsas_transport_template)
5368 return -ENODEV;
Kashyap, Desaic9de7dc2010-07-26 18:56:21 +05305369 mptsas_transport_template->eh_timed_out = mptsas_eh_timed_out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005370
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305371 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER,
5372 "mptscsih_io_done");
5373 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER,
5374 "mptscsih_taskmgmt_complete");
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005375 mptsasInternalCtx =
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305376 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER,
5377 "mptscsih_scandv_complete");
5378 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER,
5379 "mptsas_mgmt_done");
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305380 mptsasDeviceResetCtx =
Kashyap, Desai213aaca2010-07-26 18:57:36 +05305381 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER,
5382 "mptsas_taskmgmt_complete");
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005383
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305384 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5385 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005386
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305387 error = pci_register_driver(&mptsas_driver);
5388 if (error)
5389 sas_release_transport(mptsas_transport_template);
5390
5391 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005392}
5393
5394static void __exit
5395mptsas_exit(void)
5396{
5397 pci_unregister_driver(&mptsas_driver);
5398 sas_release_transport(mptsas_transport_template);
5399
5400 mpt_reset_deregister(mptsasDoneCtx);
5401 mpt_event_deregister(mptsasDoneCtx);
5402
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005403 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005404 mpt_deregister(mptsasInternalCtx);
5405 mpt_deregister(mptsasTaskCtx);
5406 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305407 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005408}
5409
5410module_init(mptsas_init);
5411module_exit(mptsas_exit);