blob: a94655162347d03d025dd53c82c3ae8cae41e7a9 [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>
Eric Moore547f9a22006-06-27 14:42:12 -060060#include <scsi/scsi_dbg.h>
Christoph Hellwig0c33b272005-09-09 16:27:19 +020061
62#include "mptbase.h"
63#include "mptscsih.h"
Prakash, Sathya56af97a2007-08-14 16:15:38 +053064#include "mptsas.h"
Christoph Hellwig0c33b272005-09-09 16:27:19 +020065
66
67#define my_NAME "Fusion MPT SAS Host driver"
68#define my_VERSION MPT_LINUX_VERSION_COMMON
69#define MYNAM "mptsas"
70
James Bottomleye8bf3942006-07-11 17:49:34 -040071/*
72 * Reserved channel for integrated raid
73 */
74#define MPTSAS_RAID_CHANNEL 1
75
Kashyap, Desai4b976502009-08-05 12:52:03 +053076#define SAS_CONFIG_PAGE_TIMEOUT 30
Christoph Hellwig0c33b272005-09-09 16:27:19 +020077MODULE_AUTHOR(MODULEAUTHOR);
78MODULE_DESCRIPTION(my_NAME);
79MODULE_LICENSE("GPL");
Eric Moore9f4203b2007-01-04 20:47:47 -070080MODULE_VERSION(my_VERSION);
Christoph Hellwig0c33b272005-09-09 16:27:19 +020081
Christoph Hellwig0c33b272005-09-09 16:27:19 +020082static int mpt_pt_clear;
83module_param(mpt_pt_clear, int, 0);
84MODULE_PARM_DESC(mpt_pt_clear,
Eric Mooreba856d32006-07-11 17:34:01 -060085 " Clear persistency table: enable=1 "
Christoph Hellwig0c33b272005-09-09 16:27:19 +020086 "(default=MPTSCSIH_PT_CLEAR=0)");
87
Eric Moore793955f2007-01-29 09:42:20 -070088/* scsi-mid layer global parmeter is max_report_luns, which is 511 */
89#define MPTSAS_MAX_LUN (16895)
90static int max_lun = MPTSAS_MAX_LUN;
91module_param(max_lun, int, 0);
92MODULE_PARM_DESC(max_lun, " max lun, default=16895 ");
93
Prakash, Sathyaf606f572007-08-14 16:12:53 +053094static u8 mptsasDoneCtx = MPT_MAX_PROTOCOL_DRIVERS;
95static u8 mptsasTaskCtx = MPT_MAX_PROTOCOL_DRIVERS;
96static u8 mptsasInternalCtx = MPT_MAX_PROTOCOL_DRIVERS; /* Used only for internal commands */
97static u8 mptsasMgmtCtx = MPT_MAX_PROTOCOL_DRIVERS;
Kashyap, Desaie7deff32009-05-29 16:46:07 +053098static u8 mptsasDeviceResetCtx = MPT_MAX_PROTOCOL_DRIVERS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +020099
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530100static void mptsas_firmware_event_work(struct work_struct *work);
101static void mptsas_send_sas_event(struct fw_event_work *fw_event);
102static void mptsas_send_raid_event(struct fw_event_work *fw_event);
103static void mptsas_send_ir2_event(struct fw_event_work *fw_event);
104static void mptsas_parse_device_info(struct sas_identify *identify,
105 struct mptsas_devinfo *device_info);
106static inline void mptsas_set_rphy(MPT_ADAPTER *ioc,
107 struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy);
108static struct mptsas_phyinfo *mptsas_find_phyinfo_by_sas_address
109 (MPT_ADAPTER *ioc, u64 sas_address);
110static int mptsas_sas_device_pg0(MPT_ADAPTER *ioc,
111 struct mptsas_devinfo *device_info, u32 form, u32 form_specific);
112static int mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc,
113 struct mptsas_enclosure *enclosure, u32 form, u32 form_specific);
114static int mptsas_add_end_device(MPT_ADAPTER *ioc,
115 struct mptsas_phyinfo *phy_info);
116static void mptsas_del_end_device(MPT_ADAPTER *ioc,
117 struct mptsas_phyinfo *phy_info);
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530118static void mptsas_send_link_status_event(struct fw_event_work *fw_event);
119static struct mptsas_portinfo *mptsas_find_portinfo_by_sas_address
120 (MPT_ADAPTER *ioc, u64 sas_address);
121static void mptsas_expander_delete(MPT_ADAPTER *ioc,
122 struct mptsas_portinfo *port_info, u8 force);
123static void mptsas_send_expander_event(struct fw_event_work *fw_event);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +0530124static void mptsas_not_responding_devices(MPT_ADAPTER *ioc);
125static void mptsas_scan_sas_topology(MPT_ADAPTER *ioc);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530126static void mptsas_broadcast_primative_work(struct fw_event_work *fw_event);
Kashyap, Desai57e98512009-05-29 16:55:09 +0530127static void mptsas_handle_queue_full_event(struct fw_event_work *fw_event);
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530128static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id);
Kashyap, Desaib68bf092010-06-17 14:40:56 +0530129void mptsas_schedule_target_reset(void *ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +0200130
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530131static void mptsas_print_phy_data(MPT_ADAPTER *ioc,
132 MPI_SAS_IO_UNIT0_PHY_DATA *phy_data)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200133{
Eric Moore29dd3602007-09-14 18:46:51 -0600134 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
135 "---- IO UNIT PAGE 0 ------------\n", ioc->name));
136 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
137 ioc->name, le16_to_cpu(phy_data->AttachedDeviceHandle)));
138 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Controller Handle=0x%X\n",
139 ioc->name, le16_to_cpu(phy_data->ControllerDevHandle)));
140 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port=0x%X\n",
141 ioc->name, phy_data->Port));
142 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Port Flags=0x%X\n",
143 ioc->name, phy_data->PortFlags));
144 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Flags=0x%X\n",
145 ioc->name, phy_data->PhyFlags));
146 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
147 ioc->name, phy_data->NegotiatedLinkRate));
148 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
149 "Controller PHY Device Info=0x%X\n", ioc->name,
150 le32_to_cpu(phy_data->ControllerPhyDeviceInfo)));
151 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "DiscoveryStatus=0x%X\n\n",
152 ioc->name, le32_to_cpu(phy_data->DiscoveryStatus)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200153}
154
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530155static void mptsas_print_phy_pg0(MPT_ADAPTER *ioc, SasPhyPage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200156{
157 __le64 sas_address;
158
159 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
160
Eric Moore29dd3602007-09-14 18:46:51 -0600161 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
162 "---- SAS PHY PAGE 0 ------------\n", ioc->name));
163 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
164 "Attached Device Handle=0x%X\n", ioc->name,
165 le16_to_cpu(pg0->AttachedDevHandle)));
166 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
167 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
168 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
169 "Attached PHY Identifier=0x%X\n", ioc->name,
170 pg0->AttachedPhyIdentifier));
171 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Attached Device Info=0x%X\n",
172 ioc->name, le32_to_cpu(pg0->AttachedDeviceInfo)));
173 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
174 ioc->name, pg0->ProgrammedLinkRate));
175 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Change Count=0x%X\n",
176 ioc->name, pg0->ChangeCount));
177 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Info=0x%X\n\n",
178 ioc->name, le32_to_cpu(pg0->PhyInfo)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200179}
180
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530181static void mptsas_print_phy_pg1(MPT_ADAPTER *ioc, SasPhyPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200182{
Eric Moore29dd3602007-09-14 18:46:51 -0600183 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
184 "---- SAS PHY PAGE 1 ------------\n", ioc->name));
185 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Invalid Dword Count=0x%x\n",
186 ioc->name, pg1->InvalidDwordCount));
187 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
188 "Running Disparity Error Count=0x%x\n", ioc->name,
189 pg1->RunningDisparityErrorCount));
190 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
191 "Loss Dword Synch Count=0x%x\n", ioc->name,
192 pg1->LossDwordSynchCount));
193 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
194 "PHY Reset Problem Count=0x%x\n\n", ioc->name,
195 pg1->PhyResetProblemCount));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200196}
197
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530198static void mptsas_print_device_pg0(MPT_ADAPTER *ioc, SasDevicePage0_t *pg0)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200199{
200 __le64 sas_address;
201
202 memcpy(&sas_address, &pg0->SASAddress, sizeof(__le64));
203
Eric Moore29dd3602007-09-14 18:46:51 -0600204 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
205 "---- SAS DEVICE PAGE 0 ---------\n", ioc->name));
206 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Handle=0x%X\n",
207 ioc->name, le16_to_cpu(pg0->DevHandle)));
208 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Handle=0x%X\n",
209 ioc->name, le16_to_cpu(pg0->ParentDevHandle)));
210 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Enclosure Handle=0x%X\n",
211 ioc->name, le16_to_cpu(pg0->EnclosureHandle)));
212 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Slot=0x%X\n",
213 ioc->name, le16_to_cpu(pg0->Slot)));
214 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "SAS Address=0x%llX\n",
215 ioc->name, (unsigned long long)le64_to_cpu(sas_address)));
216 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Target ID=0x%X\n",
217 ioc->name, pg0->TargetID));
218 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Bus=0x%X\n",
219 ioc->name, pg0->Bus));
220 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Parent Phy Num=0x%X\n",
221 ioc->name, pg0->PhyNum));
222 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Access Status=0x%X\n",
223 ioc->name, le16_to_cpu(pg0->AccessStatus)));
224 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Device Info=0x%X\n",
225 ioc->name, le32_to_cpu(pg0->DeviceInfo)));
226 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Flags=0x%X\n",
227 ioc->name, le16_to_cpu(pg0->Flags)));
228 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n\n",
229 ioc->name, pg0->PhysicalPort));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200230}
231
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530232static void mptsas_print_expander_pg1(MPT_ADAPTER *ioc, SasExpanderPage1_t *pg1)
Christoph Hellwigb5141122005-10-28 22:07:41 +0200233{
Eric Moore29dd3602007-09-14 18:46:51 -0600234 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
235 "---- SAS EXPANDER PAGE 1 ------------\n", ioc->name));
236 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Physical Port=0x%X\n",
237 ioc->name, pg1->PhysicalPort));
238 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "PHY Identifier=0x%X\n",
239 ioc->name, pg1->PhyIdentifier));
240 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Negotiated Link Rate=0x%X\n",
241 ioc->name, pg1->NegotiatedLinkRate));
242 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Programmed Link Rate=0x%X\n",
243 ioc->name, pg1->ProgrammedLinkRate));
244 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Hardware Link Rate=0x%X\n",
245 ioc->name, pg1->HwLinkRate));
246 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Owner Device Handle=0x%X\n",
247 ioc->name, le16_to_cpu(pg1->OwnerDevHandle)));
248 dsasprintk(ioc, printk(MYIOC_s_DEBUG_FMT
249 "Attached Device Handle=0x%X\n\n", ioc->name,
250 le16_to_cpu(pg1->AttachedDevHandle)));
Christoph Hellwigb5141122005-10-28 22:07:41 +0200251}
Christoph Hellwigb5141122005-10-28 22:07:41 +0200252
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530253/* inhibit sas firmware event handling */
254static void
255mptsas_fw_event_off(MPT_ADAPTER *ioc)
256{
257 unsigned long flags;
258
259 spin_lock_irqsave(&ioc->fw_event_lock, flags);
260 ioc->fw_events_off = 1;
261 ioc->sas_discovery_quiesce_io = 0;
262 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
263
264}
265
266/* enable sas firmware event handling */
267static void
268mptsas_fw_event_on(MPT_ADAPTER *ioc)
269{
270 unsigned long flags;
271
272 spin_lock_irqsave(&ioc->fw_event_lock, flags);
273 ioc->fw_events_off = 0;
274 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
275}
276
277/* queue a sas firmware event */
278static void
279mptsas_add_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
280 unsigned long delay)
281{
282 unsigned long flags;
283
284 spin_lock_irqsave(&ioc->fw_event_lock, flags);
285 list_add_tail(&fw_event->list, &ioc->fw_event_list);
286 INIT_DELAYED_WORK(&fw_event->work, mptsas_firmware_event_work);
287 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: add (fw_event=0x%p)\n",
288 ioc->name, __func__, fw_event));
289 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
290 delay);
291 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
292}
293
Kashyap, Desaidb7051b2009-05-29 16:56:59 +0530294/* requeue a sas firmware event */
295static void
296mptsas_requeue_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
297 unsigned long delay)
298{
299 unsigned long flags;
300 spin_lock_irqsave(&ioc->fw_event_lock, flags);
301 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: reschedule task "
302 "(fw_event=0x%p)\n", ioc->name, __func__, fw_event));
303 fw_event->retries++;
304 queue_delayed_work(ioc->fw_event_q, &fw_event->work,
305 msecs_to_jiffies(delay));
306 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
307}
308
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530309/* free memory assoicated to a sas firmware event */
310static void
311mptsas_free_fw_event(MPT_ADAPTER *ioc, struct fw_event_work *fw_event)
312{
313 unsigned long flags;
314
315 spin_lock_irqsave(&ioc->fw_event_lock, flags);
316 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: kfree (fw_event=0x%p)\n",
317 ioc->name, __func__, fw_event));
318 list_del(&fw_event->list);
319 kfree(fw_event);
320 spin_unlock_irqrestore(&ioc->fw_event_lock, flags);
321}
322
323/* walk the firmware event queue, and either stop or wait for
324 * outstanding events to complete */
325static void
326mptsas_cleanup_fw_event_q(MPT_ADAPTER *ioc)
327{
328 struct fw_event_work *fw_event, *next;
329 struct mptsas_target_reset_event *target_reset_list, *n;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530330 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
331
332 /* flush the target_reset_list */
333 if (!list_empty(&hd->target_reset_list)) {
334 list_for_each_entry_safe(target_reset_list, n,
335 &hd->target_reset_list, list) {
336 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
337 "%s: removing target reset for id=%d\n",
338 ioc->name, __func__,
339 target_reset_list->sas_event_data.TargetID));
340 list_del(&target_reset_list->list);
341 kfree(target_reset_list);
342 }
343 }
344
345 if (list_empty(&ioc->fw_event_list) ||
346 !ioc->fw_event_q || in_interrupt())
347 return;
348
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530349 list_for_each_entry_safe(fw_event, next, &ioc->fw_event_list, list) {
350 if (cancel_delayed_work(&fw_event->work))
351 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530352 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530353}
354
355
Christoph Hellwige3094442006-02-16 13:25:36 +0100356static inline MPT_ADAPTER *phy_to_ioc(struct sas_phy *phy)
357{
358 struct Scsi_Host *shost = dev_to_shost(phy->dev.parent);
359 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
360}
361
362static inline MPT_ADAPTER *rphy_to_ioc(struct sas_rphy *rphy)
363{
364 struct Scsi_Host *shost = dev_to_shost(rphy->dev.parent->parent);
365 return ((MPT_SCSI_HOST *)shost->hostdata)->ioc;
366}
367
Moore, Erice6b2d762006-03-14 09:14:24 -0700368/*
369 * mptsas_find_portinfo_by_handle
370 *
371 * This function should be called with the sas_topology_mutex already held
372 */
373static struct mptsas_portinfo *
374mptsas_find_portinfo_by_handle(MPT_ADAPTER *ioc, u16 handle)
375{
376 struct mptsas_portinfo *port_info, *rc=NULL;
377 int i;
378
379 list_for_each_entry(port_info, &ioc->sas_topology, list)
380 for (i = 0; i < port_info->num_phys; i++)
381 if (port_info->phy_info[i].identify.handle == handle) {
382 rc = port_info;
383 goto out;
384 }
385 out:
386 return rc;
387}
388
Kashyap, Desaif9c34022009-05-29 16:49:36 +0530389/**
390 * mptsas_find_portinfo_by_sas_address -
391 * @ioc: Pointer to MPT_ADAPTER structure
392 * @handle:
393 *
394 * This function should be called with the sas_topology_mutex already held
395 *
396 **/
397static struct mptsas_portinfo *
398mptsas_find_portinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
399{
400 struct mptsas_portinfo *port_info, *rc = NULL;
401 int i;
402
403 if (sas_address >= ioc->hba_port_sas_addr &&
404 sas_address < (ioc->hba_port_sas_addr +
405 ioc->hba_port_num_phy))
406 return ioc->hba_port_info;
407
408 mutex_lock(&ioc->sas_topology_mutex);
409 list_for_each_entry(port_info, &ioc->sas_topology, list)
410 for (i = 0; i < port_info->num_phys; i++)
411 if (port_info->phy_info[i].identify.sas_address ==
412 sas_address) {
413 rc = port_info;
414 goto out;
415 }
416 out:
417 mutex_unlock(&ioc->sas_topology_mutex);
418 return rc;
419}
420
Moore, Ericbd23e942006-04-17 12:43:04 -0600421/*
422 * Returns true if there is a scsi end device
423 */
424static inline int
425mptsas_is_end_device(struct mptsas_devinfo * attached)
426{
Eric Moore547f9a22006-06-27 14:42:12 -0600427 if ((attached->sas_address) &&
Moore, Ericbd23e942006-04-17 12:43:04 -0600428 (attached->device_info &
429 MPI_SAS_DEVICE_INFO_END_DEVICE) &&
430 ((attached->device_info &
431 MPI_SAS_DEVICE_INFO_SSP_TARGET) |
432 (attached->device_info &
433 MPI_SAS_DEVICE_INFO_STP_TARGET) |
434 (attached->device_info &
435 MPI_SAS_DEVICE_INFO_SATA_DEVICE)))
436 return 1;
437 else
438 return 0;
439}
440
Eric Moore547f9a22006-06-27 14:42:12 -0600441/* no mutex */
Eric Moore376ac832006-06-29 17:36:26 -0600442static void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530443mptsas_port_delete(MPT_ADAPTER *ioc, struct mptsas_portinfo_details * port_details)
Eric Moore547f9a22006-06-27 14:42:12 -0600444{
445 struct mptsas_portinfo *port_info;
446 struct mptsas_phyinfo *phy_info;
447 u8 i;
448
449 if (!port_details)
450 return;
451
452 port_info = port_details->port_info;
453 phy_info = port_info->phy_info;
454
Eric Moore29dd3602007-09-14 18:46:51 -0600455 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: [%p]: num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700456 "bitmask=0x%016llX\n", ioc->name, __func__, port_details,
Eric Mooref99be432007-01-04 20:46:54 -0700457 port_details->num_phys, (unsigned long long)
458 port_details->phy_bitmask));
Eric Moore547f9a22006-06-27 14:42:12 -0600459
460 for (i = 0; i < port_info->num_phys; i++, phy_info++) {
461 if(phy_info->port_details != port_details)
462 continue;
463 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530464 mptsas_set_rphy(ioc, phy_info, NULL);
Eric Moore547f9a22006-06-27 14:42:12 -0600465 phy_info->port_details = NULL;
466 }
467 kfree(port_details);
468}
469
470static inline struct sas_rphy *
471mptsas_get_rphy(struct mptsas_phyinfo *phy_info)
472{
473 if (phy_info->port_details)
474 return phy_info->port_details->rphy;
475 else
476 return NULL;
477}
478
479static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530480mptsas_set_rphy(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_rphy *rphy)
Eric Moore547f9a22006-06-27 14:42:12 -0600481{
482 if (phy_info->port_details) {
483 phy_info->port_details->rphy = rphy;
Eric Moore29dd3602007-09-14 18:46:51 -0600484 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "sas_rphy_add: rphy=%p\n",
485 ioc->name, rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600486 }
487
Eric Moore547f9a22006-06-27 14:42:12 -0600488 if (rphy) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600489 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
490 &rphy->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600491 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "rphy=%p release=%p\n",
492 ioc->name, rphy, rphy->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600493 }
Eric Moore547f9a22006-06-27 14:42:12 -0600494}
495
496static inline struct sas_port *
497mptsas_get_port(struct mptsas_phyinfo *phy_info)
498{
499 if (phy_info->port_details)
500 return phy_info->port_details->port;
501 else
502 return NULL;
503}
504
505static inline void
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +0530506mptsas_set_port(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info, struct sas_port *port)
Eric Moore547f9a22006-06-27 14:42:12 -0600507{
508 if (phy_info->port_details)
509 phy_info->port_details->port = port;
510
Eric Moore547f9a22006-06-27 14:42:12 -0600511 if (port) {
Eric Moorec51d0be2007-09-29 10:17:21 -0600512 dsaswideprintk(ioc, dev_printk(KERN_DEBUG,
513 &port->dev, MYIOC_s_FMT "add:", ioc->name));
Eric Moore29dd3602007-09-14 18:46:51 -0600514 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "port=%p release=%p\n",
515 ioc->name, port, port->dev.release));
Eric Moore547f9a22006-06-27 14:42:12 -0600516 }
Eric Moore547f9a22006-06-27 14:42:12 -0600517}
518
519static inline struct scsi_target *
520mptsas_get_starget(struct mptsas_phyinfo *phy_info)
521{
522 if (phy_info->port_details)
523 return phy_info->port_details->starget;
524 else
525 return NULL;
526}
527
528static inline void
529mptsas_set_starget(struct mptsas_phyinfo *phy_info, struct scsi_target *
530starget)
531{
532 if (phy_info->port_details)
533 phy_info->port_details->starget = starget;
534}
535
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530536/**
537 * mptsas_add_device_component -
538 * @ioc: Pointer to MPT_ADAPTER structure
539 * @channel: fw mapped id's
540 * @id:
541 * @sas_address:
542 * @device_info:
543 *
544 **/
545static void
546mptsas_add_device_component(MPT_ADAPTER *ioc, u8 channel, u8 id,
547 u64 sas_address, u32 device_info, u16 slot, u64 enclosure_logical_id)
548{
549 struct mptsas_device_info *sas_info, *next;
550 struct scsi_device *sdev;
551 struct scsi_target *starget;
552 struct sas_rphy *rphy;
553
554 /*
555 * Delete all matching devices out of the list
556 */
557 mutex_lock(&ioc->sas_device_info_mutex);
558 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
559 list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530560 if (!sas_info->is_logical_volume &&
561 (sas_info->sas_address == sas_address ||
562 (sas_info->fw.channel == channel &&
563 sas_info->fw.id == id))) {
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530564 list_del(&sas_info->list);
565 kfree(sas_info);
566 }
567 }
568
569 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
570 if (!sas_info)
571 goto out;
572
573 /*
574 * Set Firmware mapping
575 */
576 sas_info->fw.id = id;
577 sas_info->fw.channel = channel;
578
579 sas_info->sas_address = sas_address;
580 sas_info->device_info = device_info;
581 sas_info->slot = slot;
582 sas_info->enclosure_logical_id = enclosure_logical_id;
583 INIT_LIST_HEAD(&sas_info->list);
584 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
585
586 /*
587 * Set OS mapping
588 */
589 shost_for_each_device(sdev, ioc->sh) {
590 starget = scsi_target(sdev);
591 rphy = dev_to_rphy(starget->dev.parent);
592 if (rphy->identify.sas_address == sas_address) {
593 sas_info->os.id = starget->id;
594 sas_info->os.channel = starget->channel;
595 }
596 }
597
598 out:
599 mutex_unlock(&ioc->sas_device_info_mutex);
600 return;
601}
602
603/**
604 * mptsas_add_device_component_by_fw -
605 * @ioc: Pointer to MPT_ADAPTER structure
606 * @channel: fw mapped id's
607 * @id:
608 *
609 **/
610static void
611mptsas_add_device_component_by_fw(MPT_ADAPTER *ioc, u8 channel, u8 id)
612{
613 struct mptsas_devinfo sas_device;
614 struct mptsas_enclosure enclosure_info;
615 int rc;
616
617 rc = mptsas_sas_device_pg0(ioc, &sas_device,
618 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
619 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
620 (channel << 8) + id);
621 if (rc)
622 return;
623
624 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
625 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
626 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
627 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
628 sas_device.handle_enclosure);
629
630 mptsas_add_device_component(ioc, sas_device.channel,
631 sas_device.id, sas_device.sas_address, sas_device.device_info,
632 sas_device.slot, enclosure_info.enclosure_logical_id);
633}
634
635/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000636 * mptsas_add_device_component_starget_ir - Handle Integrated RAID, adding each individual device to list
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530637 * @ioc: Pointer to MPT_ADAPTER structure
638 * @channel: fw mapped id's
639 * @id:
640 *
641 **/
642static void
643mptsas_add_device_component_starget_ir(MPT_ADAPTER *ioc,
644 struct scsi_target *starget)
645{
646 CONFIGPARMS cfg;
647 ConfigPageHeader_t hdr;
648 dma_addr_t dma_handle;
649 pRaidVolumePage0_t buffer = NULL;
650 int i;
651 RaidPhysDiskPage0_t phys_disk;
652 struct mptsas_device_info *sas_info, *next;
653
654 memset(&cfg, 0 , sizeof(CONFIGPARMS));
655 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
656 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
657 /* assumption that all volumes on channel = 0 */
658 cfg.pageAddr = starget->id;
659 cfg.cfghdr.hdr = &hdr;
660 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +0530661 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530662
663 if (mpt_config(ioc, &cfg) != 0)
664 goto out;
665
666 if (!hdr.PageLength)
667 goto out;
668
669 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
670 &dma_handle);
671
672 if (!buffer)
673 goto out;
674
675 cfg.physAddr = dma_handle;
676 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
677
678 if (mpt_config(ioc, &cfg) != 0)
679 goto out;
680
681 if (!buffer->NumPhysDisks)
682 goto out;
683
684 /*
685 * Adding entry for hidden components
686 */
687 for (i = 0; i < buffer->NumPhysDisks; i++) {
688
689 if (mpt_raid_phys_disk_pg0(ioc,
690 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
691 continue;
692
693 mptsas_add_device_component_by_fw(ioc, phys_disk.PhysDiskBus,
694 phys_disk.PhysDiskID);
695
Kashyap, Desai57e98512009-05-29 16:55:09 +0530696 mutex_lock(&ioc->sas_device_info_mutex);
697 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
698 list) {
699 if (!sas_info->is_logical_volume &&
700 (sas_info->fw.channel == phys_disk.PhysDiskBus &&
701 sas_info->fw.id == phys_disk.PhysDiskID)) {
702 sas_info->is_hidden_raid_component = 1;
703 sas_info->volume_id = starget->id;
704 }
705 }
706 mutex_unlock(&ioc->sas_device_info_mutex);
707
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530708 }
709
710 /*
711 * Delete all matching devices out of the list
712 */
713 mutex_lock(&ioc->sas_device_info_mutex);
714 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
715 list) {
716 if (sas_info->is_logical_volume && sas_info->fw.id ==
717 starget->id) {
718 list_del(&sas_info->list);
719 kfree(sas_info);
720 }
721 }
722
723 sas_info = kzalloc(sizeof(struct mptsas_device_info), GFP_KERNEL);
724 if (sas_info) {
725 sas_info->fw.id = starget->id;
726 sas_info->os.id = starget->id;
727 sas_info->os.channel = starget->channel;
728 sas_info->is_logical_volume = 1;
729 INIT_LIST_HEAD(&sas_info->list);
730 list_add_tail(&sas_info->list, &ioc->sas_device_info_list);
731 }
732 mutex_unlock(&ioc->sas_device_info_mutex);
733
734 out:
735 if (buffer)
736 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
737 dma_handle);
738}
739
740/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530741 * mptsas_add_device_component_starget -
742 * @ioc: Pointer to MPT_ADAPTER structure
743 * @starget:
744 *
745 **/
746static void
747mptsas_add_device_component_starget(MPT_ADAPTER *ioc,
748 struct scsi_target *starget)
749{
750 VirtTarget *vtarget;
751 struct sas_rphy *rphy;
752 struct mptsas_phyinfo *phy_info = NULL;
753 struct mptsas_enclosure enclosure_info;
754
755 rphy = dev_to_rphy(starget->dev.parent);
756 vtarget = starget->hostdata;
757 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
758 rphy->identify.sas_address);
759 if (!phy_info)
760 return;
761
762 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
763 mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
764 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
765 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT),
766 phy_info->attached.handle_enclosure);
767
768 mptsas_add_device_component(ioc, phy_info->attached.channel,
769 phy_info->attached.id, phy_info->attached.sas_address,
770 phy_info->attached.device_info,
771 phy_info->attached.slot, enclosure_info.enclosure_logical_id);
772}
773
774/**
James Bottomleyfc847ab2009-06-09 23:01:01 +0000775 * 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 +0530776 * @ioc: Pointer to MPT_ADAPTER structure
777 * @channel: os mapped id's
778 * @id:
779 *
780 **/
781static void
782mptsas_del_device_component_by_os(MPT_ADAPTER *ioc, u8 channel, u8 id)
783{
784 struct mptsas_device_info *sas_info, *next;
785
786 /*
787 * Set is_cached flag
788 */
789 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
790 list) {
791 if (sas_info->os.channel == channel && sas_info->os.id == id)
792 sas_info->is_cached = 1;
793 }
794}
795
796/**
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530797 * mptsas_del_device_components - Cleaning the list
798 * @ioc: Pointer to MPT_ADAPTER structure
799 *
800 **/
801static void
802mptsas_del_device_components(MPT_ADAPTER *ioc)
803{
804 struct mptsas_device_info *sas_info, *next;
805
806 mutex_lock(&ioc->sas_device_info_mutex);
807 list_for_each_entry_safe(sas_info, next, &ioc->sas_device_info_list,
808 list) {
809 list_del(&sas_info->list);
810 kfree(sas_info);
811 }
812 mutex_unlock(&ioc->sas_device_info_mutex);
813}
814
Eric Moore547f9a22006-06-27 14:42:12 -0600815
816/*
817 * mptsas_setup_wide_ports
818 *
819 * Updates for new and existing narrow/wide port configuration
820 * in the sas_topology
821 */
Eric Moore376ac832006-06-29 17:36:26 -0600822static void
Eric Moore547f9a22006-06-27 14:42:12 -0600823mptsas_setup_wide_ports(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
824{
825 struct mptsas_portinfo_details * port_details;
826 struct mptsas_phyinfo *phy_info, *phy_info_cmp;
827 u64 sas_address;
828 int i, j;
829
830 mutex_lock(&ioc->sas_topology_mutex);
831
832 phy_info = port_info->phy_info;
833 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
834 if (phy_info->attached.handle)
835 continue;
836 port_details = phy_info->port_details;
837 if (!port_details)
838 continue;
839 if (port_details->num_phys < 2)
840 continue;
841 /*
842 * Removing a phy from a port, letting the last
843 * phy be removed by firmware events.
844 */
Eric Moore29dd3602007-09-14 18:46:51 -0600845 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
846 "%s: [%p]: deleting phy = %d\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700847 ioc->name, __func__, port_details, i));
Eric Moore547f9a22006-06-27 14:42:12 -0600848 port_details->num_phys--;
849 port_details->phy_bitmask &= ~ (1 << phy_info->phy_id);
850 memset(&phy_info->attached, 0, sizeof(struct mptsas_devinfo));
Kashyap, Desai9e390892009-09-02 11:43:36 +0530851 if (phy_info->phy) {
852 devtprintk(ioc, dev_printk(KERN_DEBUG,
853 &phy_info->phy->dev, MYIOC_s_FMT
854 "delete phy %d, phy-obj (0x%p)\n", ioc->name,
855 phy_info->phy_id, phy_info->phy));
856 sas_port_delete_phy(port_details->port, phy_info->phy);
857 }
Eric Moore547f9a22006-06-27 14:42:12 -0600858 phy_info->port_details = NULL;
859 }
860
861 /*
862 * Populate and refresh the tree
863 */
864 phy_info = port_info->phy_info;
865 for (i = 0 ; i < port_info->num_phys ; i++, phy_info++) {
866 sas_address = phy_info->attached.sas_address;
Eric Moore29dd3602007-09-14 18:46:51 -0600867 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "phy_id=%d sas_address=0x%018llX\n",
868 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600869 if (!sas_address)
870 continue;
871 port_details = phy_info->port_details;
872 /*
873 * Forming a port
874 */
875 if (!port_details) {
Kashyap, Desai2f187862009-05-29 16:52:37 +0530876 port_details = kzalloc(sizeof(struct
877 mptsas_portinfo_details), GFP_KERNEL);
Eric Moore547f9a22006-06-27 14:42:12 -0600878 if (!port_details)
879 goto out;
880 port_details->num_phys = 1;
881 port_details->port_info = port_info;
Eric Moore547f9a22006-06-27 14:42:12 -0600882 if (phy_info->phy_id < 64 )
883 port_details->phy_bitmask |=
884 (1 << phy_info->phy_id);
885 phy_info->sas_port_add_phy=1;
Eric Moore29dd3602007-09-14 18:46:51 -0600886 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tForming port\n\t\t"
Eric Mooref99be432007-01-04 20:46:54 -0700887 "phy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600888 ioc->name, i, (unsigned long long)sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600889 phy_info->port_details = port_details;
890 }
891
892 if (i == port_info->num_phys - 1)
893 continue;
894 phy_info_cmp = &port_info->phy_info[i + 1];
895 for (j = i + 1 ; j < port_info->num_phys ; j++,
896 phy_info_cmp++) {
897 if (!phy_info_cmp->attached.sas_address)
898 continue;
899 if (sas_address != phy_info_cmp->attached.sas_address)
900 continue;
901 if (phy_info_cmp->port_details == port_details )
902 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600903 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700904 "\t\tphy_id=%d sas_address=0x%018llX\n",
Eric Moore29dd3602007-09-14 18:46:51 -0600905 ioc->name, j, (unsigned long long)
Eric Mooref99be432007-01-04 20:46:54 -0700906 phy_info_cmp->attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -0600907 if (phy_info_cmp->port_details) {
908 port_details->rphy =
909 mptsas_get_rphy(phy_info_cmp);
910 port_details->port =
911 mptsas_get_port(phy_info_cmp);
912 port_details->starget =
913 mptsas_get_starget(phy_info_cmp);
Eric Moore547f9a22006-06-27 14:42:12 -0600914 port_details->num_phys =
915 phy_info_cmp->port_details->num_phys;
Eric Moore547f9a22006-06-27 14:42:12 -0600916 if (!phy_info_cmp->port_details->num_phys)
917 kfree(phy_info_cmp->port_details);
918 } else
919 phy_info_cmp->sas_port_add_phy=1;
920 /*
921 * Adding a phy to a port
922 */
923 phy_info_cmp->port_details = port_details;
924 if (phy_info_cmp->phy_id < 64 )
925 port_details->phy_bitmask |=
926 (1 << phy_info_cmp->phy_id);
927 port_details->num_phys++;
928 }
929 }
930
931 out:
932
Eric Moore547f9a22006-06-27 14:42:12 -0600933 for (i = 0; i < port_info->num_phys; i++) {
934 port_details = port_info->phy_info[i].port_details;
935 if (!port_details)
936 continue;
Eric Moore29dd3602007-09-14 18:46:51 -0600937 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Eric Mooref99be432007-01-04 20:46:54 -0700938 "%s: [%p]: phy_id=%02d num_phys=%02d "
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -0700939 "bitmask=0x%016llX\n", ioc->name, __func__,
Eric Mooref99be432007-01-04 20:46:54 -0700940 port_details, i, port_details->num_phys,
941 (unsigned long long)port_details->phy_bitmask));
Eric Moore29dd3602007-09-14 18:46:51 -0600942 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT "\t\tport = %p rphy=%p\n",
943 ioc->name, port_details->port, port_details->rphy));
Eric Moore547f9a22006-06-27 14:42:12 -0600944 }
Eric Moore29dd3602007-09-14 18:46:51 -0600945 dsaswideprintk(ioc, printk("\n"));
Eric Moore547f9a22006-06-27 14:42:12 -0600946 mutex_unlock(&ioc->sas_topology_mutex);
947}
948
Eric Mooredf9e0622007-01-29 09:46:21 -0700949/**
950 * csmisas_find_vtarget
951 *
952 * @ioc
953 * @volume_id
954 * @volume_bus
955 *
956 **/
957static VirtTarget *
958mptsas_find_vtarget(MPT_ADAPTER *ioc, u8 channel, u8 id)
Eric Moore547f9a22006-06-27 14:42:12 -0600959{
Eric Mooredf9e0622007-01-29 09:46:21 -0700960 struct scsi_device *sdev;
Eric Moorea69de502007-09-14 18:48:19 -0600961 VirtDevice *vdevice;
Eric Mooredf9e0622007-01-29 09:46:21 -0700962 VirtTarget *vtarget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -0600963
Eric Mooredf9e0622007-01-29 09:46:21 -0700964 shost_for_each_device(sdev, ioc->sh) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530965 vdevice = sdev->hostdata;
966 if ((vdevice == NULL) ||
967 (vdevice->vtarget == NULL))
Eric Mooredf9e0622007-01-29 09:46:21 -0700968 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +0530969 if ((vdevice->vtarget->tflags &
970 MPT_TARGET_FLAGS_RAID_COMPONENT ||
971 vdevice->vtarget->raidVolume))
972 continue;
Eric Moorea69de502007-09-14 18:48:19 -0600973 if (vdevice->vtarget->id == id &&
Kashyap, Desaie7deff32009-05-29 16:46:07 +0530974 vdevice->vtarget->channel == channel)
Eric Moorea69de502007-09-14 18:48:19 -0600975 vtarget = vdevice->vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -0600976 }
Eric Mooredf9e0622007-01-29 09:46:21 -0700977 return vtarget;
978}
979
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +0530980static void
981mptsas_queue_device_delete(MPT_ADAPTER *ioc,
982 MpiEventDataSasDeviceStatusChange_t *sas_event_data)
983{
984 struct fw_event_work *fw_event;
985 int sz;
986
987 sz = offsetof(struct fw_event_work, event_data) +
988 sizeof(MpiEventDataSasDeviceStatusChange_t);
989 fw_event = kzalloc(sz, GFP_ATOMIC);
990 if (!fw_event) {
991 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
992 ioc->name, __func__, __LINE__);
993 return;
994 }
995 memcpy(fw_event->event_data, sas_event_data,
996 sizeof(MpiEventDataSasDeviceStatusChange_t));
997 fw_event->event = MPI_EVENT_SAS_DEVICE_STATUS_CHANGE;
998 fw_event->ioc = ioc;
999 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1000}
1001
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301002static void
1003mptsas_queue_rescan(MPT_ADAPTER *ioc)
1004{
1005 struct fw_event_work *fw_event;
1006 int sz;
1007
1008 sz = offsetof(struct fw_event_work, event_data);
1009 fw_event = kzalloc(sz, GFP_ATOMIC);
1010 if (!fw_event) {
1011 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n",
1012 ioc->name, __func__, __LINE__);
1013 return;
1014 }
1015 fw_event->event = -1;
1016 fw_event->ioc = ioc;
1017 mptsas_add_fw_event(ioc, fw_event, msecs_to_jiffies(1));
1018}
1019
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301020
Eric Mooredf9e0622007-01-29 09:46:21 -07001021/**
1022 * mptsas_target_reset
1023 *
1024 * Issues TARGET_RESET to end device using handshaking method
1025 *
1026 * @ioc
1027 * @channel
1028 * @id
1029 *
1030 * Returns (1) success
1031 * (0) failure
1032 *
1033 **/
1034static int
1035mptsas_target_reset(MPT_ADAPTER *ioc, u8 channel, u8 id)
1036{
1037 MPT_FRAME_HDR *mf;
1038 SCSITaskMgmt_t *pScsiTm;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301039 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0)
1040 return 0;
1041
Eric Mooredf9e0622007-01-29 09:46:21 -07001042
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301043 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
1044 if (mf == NULL) {
1045 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301046 "%s, no msg frames @%d!!\n", ioc->name,
1047 __func__, __LINE__));
1048 goto out_fail;
Eric Mooredf9e0622007-01-29 09:46:21 -07001049 }
1050
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301051 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request (mf=%p)\n",
1052 ioc->name, mf));
1053
Eric Mooredf9e0622007-01-29 09:46:21 -07001054 /* Format the Request
1055 */
1056 pScsiTm = (SCSITaskMgmt_t *) mf;
1057 memset (pScsiTm, 0, sizeof(SCSITaskMgmt_t));
1058 pScsiTm->TargetID = id;
1059 pScsiTm->Bus = channel;
1060 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
1061 pScsiTm->TaskType = MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET;
1062 pScsiTm->MsgFlags = MPI_SCSITASKMGMT_MSGFLAGS_LIPRESET_RESET_OPTION;
1063
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301064 DBG_DUMP_TM_REQUEST_FRAME(ioc, (u32 *)mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001065
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301066 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1067 "TaskMgmt type=%d (sas device delete) fw_channel = %d fw_id = %d)\n",
1068 ioc->name, MPI_SCSITASKMGMT_TASKTYPE_TARGET_RESET, channel, id));
1069
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301070 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
Eric Mooredf9e0622007-01-29 09:46:21 -07001071
1072 return 1;
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301073
1074 out_fail:
1075
1076 mpt_clear_taskmgmt_in_progress_flag(ioc);
1077 return 0;
Eric Mooredf9e0622007-01-29 09:46:21 -07001078}
1079
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301080static void
1081mptsas_block_io_sdev(struct scsi_device *sdev, void *data)
1082{
1083 scsi_device_set_state(sdev, SDEV_BLOCK);
1084}
1085
1086static void
1087mptsas_block_io_starget(struct scsi_target *starget)
1088{
1089 if (starget)
1090 starget_for_each_device(starget, NULL, mptsas_block_io_sdev);
1091}
1092
Eric Mooredf9e0622007-01-29 09:46:21 -07001093/**
1094 * mptsas_target_reset_queue
1095 *
1096 * Receive request for TARGET_RESET after recieving an firmware
1097 * event NOT_RESPONDING_EVENT, then put command in link list
1098 * and queue if task_queue already in use.
1099 *
1100 * @ioc
1101 * @sas_event_data
1102 *
1103 **/
1104static void
1105mptsas_target_reset_queue(MPT_ADAPTER *ioc,
1106 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data)
1107{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001108 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001109 VirtTarget *vtarget = NULL;
1110 struct mptsas_target_reset_event *target_reset_list;
1111 u8 id, channel;
1112
1113 id = sas_event_data->TargetID;
1114 channel = sas_event_data->Bus;
1115
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301116 vtarget = mptsas_find_vtarget(ioc, channel, id);
1117 if (vtarget) {
1118 mptsas_block_io_starget(vtarget->starget);
1119 vtarget->deleted = 1; /* block IO */
1120 }
Eric Mooredf9e0622007-01-29 09:46:21 -07001121
Kashyap, Desai2f187862009-05-29 16:52:37 +05301122 target_reset_list = kzalloc(sizeof(struct mptsas_target_reset_event),
Eric Mooredf9e0622007-01-29 09:46:21 -07001123 GFP_ATOMIC);
1124 if (!target_reset_list) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301125 dfailprintk(ioc, printk(MYIOC_s_WARN_FMT
1126 "%s, failed to allocate mem @%d..!!\n",
1127 ioc->name, __func__, __LINE__));
Eric Mooredf9e0622007-01-29 09:46:21 -07001128 return;
1129 }
1130
1131 memcpy(&target_reset_list->sas_event_data, sas_event_data,
1132 sizeof(*sas_event_data));
1133 list_add_tail(&target_reset_list->list, &hd->target_reset_list);
1134
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301135 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001136
1137 if (mptsas_target_reset(ioc, channel, id)) {
1138 target_reset_list->target_reset_issued = 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001139 }
1140}
1141
1142/**
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301143 * mptsas_schedule_target_reset- send pending target reset
1144 * @iocp: per adapter object
1145 *
1146 * This function will delete scheduled target reset from the list and
1147 * try to send next target reset. This will be called from completion
1148 * context of any Task managment command.
1149 */
1150
1151void
1152mptsas_schedule_target_reset(void *iocp)
1153{
1154 MPT_ADAPTER *ioc = (MPT_ADAPTER *)(iocp);
1155 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
1156 struct list_head *head = &hd->target_reset_list;
1157 struct mptsas_target_reset_event *target_reset_list;
1158 u8 id, channel;
1159 /*
1160 * issue target reset to next device in the queue
1161 */
1162
1163 head = &hd->target_reset_list;
1164 if (list_empty(head))
1165 return;
1166
1167 target_reset_list = list_entry(head->next,
1168 struct mptsas_target_reset_event, list);
1169
1170 id = target_reset_list->sas_event_data.TargetID;
1171 channel = target_reset_list->sas_event_data.Bus;
1172 target_reset_list->time_count = jiffies;
1173
1174 if (mptsas_target_reset(ioc, channel, id))
1175 target_reset_list->target_reset_issued = 1;
1176 return;
1177}
1178
1179
1180/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001181 * mptsas_taskmgmt_complete - complete SAS task management function
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301182 * @ioc: Pointer to MPT_ADAPTER structure
Eric Mooredf9e0622007-01-29 09:46:21 -07001183 *
James Bottomleyfc847ab2009-06-09 23:01:01 +00001184 * Completion for TARGET_RESET after NOT_RESPONDING_EVENT, enable work
1185 * queue to finish off removing device from upper layers. then send next
1186 * TARGET_RESET in the queue.
Eric Mooredf9e0622007-01-29 09:46:21 -07001187 **/
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301188static int
1189mptsas_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *mr)
Eric Mooredf9e0622007-01-29 09:46:21 -07001190{
Eric Mooree7eae9f2007-09-29 10:15:59 -06001191 MPT_SCSI_HOST *hd = shost_priv(ioc->sh);
Eric Mooredf9e0622007-01-29 09:46:21 -07001192 struct list_head *head = &hd->target_reset_list;
Eric Mooredf9e0622007-01-29 09:46:21 -07001193 u8 id, channel;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301194 struct mptsas_target_reset_event *target_reset_list;
1195 SCSITaskMgmtReply_t *pScsiTmReply;
1196
1197 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt completed: "
1198 "(mf = %p, mr = %p)\n", ioc->name, mf, mr));
1199
1200 pScsiTmReply = (SCSITaskMgmtReply_t *)mr;
1201 if (pScsiTmReply) {
1202 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1203 "\tTaskMgmt completed: fw_channel = %d, fw_id = %d,\n"
1204 "\ttask_type = 0x%02X, iocstatus = 0x%04X "
1205 "loginfo = 0x%08X,\n\tresponse_code = 0x%02X, "
1206 "term_cmnds = %d\n", ioc->name,
1207 pScsiTmReply->Bus, pScsiTmReply->TargetID,
1208 pScsiTmReply->TaskType,
1209 le16_to_cpu(pScsiTmReply->IOCStatus),
1210 le32_to_cpu(pScsiTmReply->IOCLogInfo),
1211 pScsiTmReply->ResponseCode,
1212 le32_to_cpu(pScsiTmReply->TerminationCount)));
1213
1214 if (pScsiTmReply->ResponseCode)
1215 mptscsih_taskmgmt_response_code(ioc,
1216 pScsiTmReply->ResponseCode);
1217 }
1218
1219 if (pScsiTmReply && (pScsiTmReply->TaskType ==
1220 MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK || pScsiTmReply->TaskType ==
1221 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET)) {
1222 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
1223 ioc->taskmgmt_cmds.status |= MPT_MGMT_STATUS_RF_VALID;
1224 memcpy(ioc->taskmgmt_cmds.reply, mr,
1225 min(MPT_DEFAULT_FRAME_SIZE, 4 * mr->u.reply.MsgLength));
1226 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_PENDING) {
1227 ioc->taskmgmt_cmds.status &= ~MPT_MGMT_STATUS_PENDING;
1228 complete(&ioc->taskmgmt_cmds.done);
1229 return 1;
1230 }
1231 return 0;
1232 }
1233
1234 mpt_clear_taskmgmt_in_progress_flag(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001235
1236 if (list_empty(head))
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301237 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001238
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301239 target_reset_list = list_entry(head->next,
1240 struct mptsas_target_reset_event, list);
1241
1242 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1243 "TaskMgmt: completed (%d seconds)\n",
1244 ioc->name, jiffies_to_msecs(jiffies -
1245 target_reset_list->time_count)/1000));
Eric Mooredf9e0622007-01-29 09:46:21 -07001246
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301247 id = pScsiTmReply->TargetID;
1248 channel = pScsiTmReply->Bus;
1249 target_reset_list->time_count = jiffies;
Eric Mooredf9e0622007-01-29 09:46:21 -07001250
1251 /*
1252 * retry target reset
1253 */
1254 if (!target_reset_list->target_reset_issued) {
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301255 if (mptsas_target_reset(ioc, channel, id))
Eric Mooredf9e0622007-01-29 09:46:21 -07001256 target_reset_list->target_reset_issued = 1;
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301257 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001258 }
1259
1260 /*
1261 * enable work queue to remove device from upper layers
1262 */
1263 list_del(&target_reset_list->list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301264 if ((mptsas_find_vtarget(ioc, channel, id)) && !ioc->fw_events_off)
1265 mptsas_queue_device_delete(ioc,
1266 &target_reset_list->sas_event_data);
Kashyap, Desaiea2a7882009-05-29 16:46:50 +05301267
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301268
Kashyap, Desaib68bf092010-06-17 14:40:56 +05301269 ioc->schedule_target_reset(ioc);
Eric Mooredf9e0622007-01-29 09:46:21 -07001270
Kashyap, Desaie7deff32009-05-29 16:46:07 +05301271 return 1;
Eric Mooredf9e0622007-01-29 09:46:21 -07001272}
1273
1274/**
1275 * mptscsih_ioc_reset
1276 *
1277 * @ioc
1278 * @reset_phase
1279 *
1280 **/
1281static int
1282mptsas_ioc_reset(MPT_ADAPTER *ioc, int reset_phase)
1283{
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001284 MPT_SCSI_HOST *hd;
Eric Mooredf9e0622007-01-29 09:46:21 -07001285 int rc;
1286
1287 rc = mptscsih_ioc_reset(ioc, reset_phase);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301288 if ((ioc->bus_type != SAS) || (!rc))
1289 return rc;
Eric Mooredf9e0622007-01-29 09:46:21 -07001290
Eric Mooree7eae9f2007-09-29 10:15:59 -06001291 hd = shost_priv(ioc->sh);
Judith Lebzelterba76ef22007-03-09 13:07:44 -08001292 if (!hd->ioc)
Eric Mooredf9e0622007-01-29 09:46:21 -07001293 goto out;
1294
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301295 switch (reset_phase) {
1296 case MPT_IOC_SETUP_RESET:
1297 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1298 "%s: MPT_IOC_SETUP_RESET\n", ioc->name, __func__));
1299 mptsas_fw_event_off(ioc);
1300 break;
1301 case MPT_IOC_PRE_RESET:
1302 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1303 "%s: MPT_IOC_PRE_RESET\n", ioc->name, __func__));
1304 break;
1305 case MPT_IOC_POST_RESET:
1306 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1307 "%s: MPT_IOC_POST_RESET\n", ioc->name, __func__));
1308 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
1309 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_DID_IOCRESET;
1310 complete(&ioc->sas_mgmt.done);
1311 }
1312 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301313 mptsas_queue_rescan(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301314 break;
1315 default:
1316 break;
Eric Mooredf9e0622007-01-29 09:46:21 -07001317 }
1318
1319 out:
1320 return rc;
Eric Moore547f9a22006-06-27 14:42:12 -06001321}
1322
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301323
1324/**
1325 * enum device_state -
1326 * @DEVICE_RETRY: need to retry the TUR
1327 * @DEVICE_ERROR: TUR return error, don't add device
1328 * @DEVICE_READY: device can be added
1329 *
1330 */
1331enum device_state{
1332 DEVICE_RETRY,
1333 DEVICE_ERROR,
1334 DEVICE_READY,
1335};
1336
Christoph Hellwige3094442006-02-16 13:25:36 +01001337static int
Moore, Eric52435432006-03-14 09:14:15 -07001338mptsas_sas_enclosure_pg0(MPT_ADAPTER *ioc, struct mptsas_enclosure *enclosure,
Christoph Hellwige3094442006-02-16 13:25:36 +01001339 u32 form, u32 form_specific)
1340{
1341 ConfigExtendedPageHeader_t hdr;
1342 CONFIGPARMS cfg;
1343 SasEnclosurePage0_t *buffer;
1344 dma_addr_t dma_handle;
1345 int error;
1346 __le64 le_identifier;
1347
1348 memset(&hdr, 0, sizeof(hdr));
1349 hdr.PageVersion = MPI_SASENCLOSURE0_PAGEVERSION;
1350 hdr.PageNumber = 0;
1351 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1352 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_ENCLOSURE;
1353
1354 cfg.cfghdr.ehdr = &hdr;
1355 cfg.physAddr = -1;
1356 cfg.pageAddr = form + form_specific;
1357 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1358 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301359 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwige3094442006-02-16 13:25:36 +01001360
1361 error = mpt_config(ioc, &cfg);
1362 if (error)
1363 goto out;
1364 if (!hdr.ExtPageLength) {
1365 error = -ENXIO;
1366 goto out;
1367 }
1368
1369 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1370 &dma_handle);
1371 if (!buffer) {
1372 error = -ENOMEM;
1373 goto out;
1374 }
1375
1376 cfg.physAddr = dma_handle;
1377 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1378
1379 error = mpt_config(ioc, &cfg);
1380 if (error)
1381 goto out_free_consistent;
1382
1383 /* save config data */
1384 memcpy(&le_identifier, &buffer->EnclosureLogicalID, sizeof(__le64));
1385 enclosure->enclosure_logical_id = le64_to_cpu(le_identifier);
1386 enclosure->enclosure_handle = le16_to_cpu(buffer->EnclosureHandle);
1387 enclosure->flags = le16_to_cpu(buffer->Flags);
1388 enclosure->num_slot = le16_to_cpu(buffer->NumSlots);
1389 enclosure->start_slot = le16_to_cpu(buffer->StartSlot);
1390 enclosure->start_id = buffer->StartTargetID;
1391 enclosure->start_channel = buffer->StartBus;
1392 enclosure->sep_id = buffer->SEPTargetID;
1393 enclosure->sep_channel = buffer->SEPBus;
1394
1395 out_free_consistent:
1396 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1397 buffer, dma_handle);
1398 out:
1399 return error;
1400}
Christoph Hellwigb5141122005-10-28 22:07:41 +02001401
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301402/**
1403 * mptsas_add_end_device - report a new end device to sas transport layer
1404 * @ioc: Pointer to MPT_ADAPTER structure
1405 * @phy_info: decribes attached device
1406 *
1407 * return (0) success (1) failure
1408 *
1409 **/
1410static int
1411mptsas_add_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1412{
1413 struct sas_rphy *rphy;
1414 struct sas_port *port;
1415 struct sas_identify identify;
1416 char *ds = NULL;
1417 u8 fw_id;
1418
1419 if (!phy_info) {
1420 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1421 "%s: exit at line=%d\n", ioc->name,
1422 __func__, __LINE__));
1423 return 1;
1424 }
1425
1426 fw_id = phy_info->attached.id;
1427
1428 if (mptsas_get_rphy(phy_info)) {
1429 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1430 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1431 __func__, fw_id, __LINE__));
1432 return 2;
1433 }
1434
1435 port = mptsas_get_port(phy_info);
1436 if (!port) {
1437 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1438 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1439 __func__, fw_id, __LINE__));
1440 return 3;
1441 }
1442
1443 if (phy_info->attached.device_info &
1444 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1445 ds = "ssp";
1446 if (phy_info->attached.device_info &
1447 MPI_SAS_DEVICE_INFO_STP_TARGET)
1448 ds = "stp";
1449 if (phy_info->attached.device_info &
1450 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1451 ds = "sata";
1452
1453 printk(MYIOC_s_INFO_FMT "attaching %s device: fw_channel %d, fw_id %d,"
1454 " phy %d, sas_addr 0x%llx\n", ioc->name, ds,
1455 phy_info->attached.channel, phy_info->attached.id,
1456 phy_info->attached.phy_id, (unsigned long long)
1457 phy_info->attached.sas_address);
1458
1459 mptsas_parse_device_info(&identify, &phy_info->attached);
1460 rphy = sas_end_device_alloc(port);
1461 if (!rphy) {
1462 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1463 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1464 __func__, fw_id, __LINE__));
1465 return 5; /* non-fatal: an rphy can be added later */
1466 }
1467
1468 rphy->identify = identify;
1469 if (sas_rphy_add(rphy)) {
1470 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1471 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1472 __func__, fw_id, __LINE__));
1473 sas_rphy_free(rphy);
1474 return 6;
1475 }
1476 mptsas_set_rphy(ioc, phy_info, rphy);
1477 return 0;
1478}
1479
1480/**
James Bottomleyfc847ab2009-06-09 23:01:01 +00001481 * mptsas_del_end_device - report a deleted end device to sas transport layer
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301482 * @ioc: Pointer to MPT_ADAPTER structure
1483 * @phy_info: decribes attached device
1484 *
1485 **/
1486static void
1487mptsas_del_end_device(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info)
1488{
1489 struct sas_rphy *rphy;
1490 struct sas_port *port;
1491 struct mptsas_portinfo *port_info;
1492 struct mptsas_phyinfo *phy_info_parent;
1493 int i;
1494 char *ds = NULL;
1495 u8 fw_id;
1496 u64 sas_address;
1497
1498 if (!phy_info)
1499 return;
1500
1501 fw_id = phy_info->attached.id;
1502 sas_address = phy_info->attached.sas_address;
1503
1504 if (!phy_info->port_details) {
1505 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1506 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1507 __func__, fw_id, __LINE__));
1508 return;
1509 }
1510 rphy = mptsas_get_rphy(phy_info);
1511 if (!rphy) {
1512 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1513 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1514 __func__, fw_id, __LINE__));
1515 return;
1516 }
1517
1518 if (phy_info->attached.device_info & MPI_SAS_DEVICE_INFO_SSP_INITIATOR
1519 || phy_info->attached.device_info
1520 & MPI_SAS_DEVICE_INFO_SMP_INITIATOR
1521 || phy_info->attached.device_info
1522 & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
1523 ds = "initiator";
1524 if (phy_info->attached.device_info &
1525 MPI_SAS_DEVICE_INFO_SSP_TARGET)
1526 ds = "ssp";
1527 if (phy_info->attached.device_info &
1528 MPI_SAS_DEVICE_INFO_STP_TARGET)
1529 ds = "stp";
1530 if (phy_info->attached.device_info &
1531 MPI_SAS_DEVICE_INFO_SATA_DEVICE)
1532 ds = "sata";
1533
1534 dev_printk(KERN_DEBUG, &rphy->dev, MYIOC_s_FMT
1535 "removing %s device: fw_channel %d, fw_id %d, phy %d,"
1536 "sas_addr 0x%llx\n", ioc->name, ds, phy_info->attached.channel,
1537 phy_info->attached.id, phy_info->attached.phy_id,
1538 (unsigned long long) sas_address);
1539
1540 port = mptsas_get_port(phy_info);
1541 if (!port) {
1542 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
1543 "%s: fw_id=%d exit at line=%d\n", ioc->name,
1544 __func__, fw_id, __LINE__));
1545 return;
1546 }
1547 port_info = phy_info->portinfo;
1548 phy_info_parent = port_info->phy_info;
1549 for (i = 0; i < port_info->num_phys; i++, phy_info_parent++) {
1550 if (!phy_info_parent->phy)
1551 continue;
1552 if (phy_info_parent->attached.sas_address !=
1553 sas_address)
1554 continue;
1555 dev_printk(KERN_DEBUG, &phy_info_parent->phy->dev,
1556 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n",
1557 ioc->name, phy_info_parent->phy_id,
1558 phy_info_parent->phy);
1559 sas_port_delete_phy(port, phy_info_parent->phy);
1560 }
1561
1562 dev_printk(KERN_DEBUG, &port->dev, MYIOC_s_FMT
1563 "delete port %d, sas_addr (0x%llx)\n", ioc->name,
1564 port->port_identifier, (unsigned long long)sas_address);
1565 sas_port_delete(port);
1566 mptsas_set_port(ioc, phy_info, NULL);
1567 mptsas_port_delete(ioc, phy_info->port_details);
1568}
1569
1570struct mptsas_phyinfo *
1571mptsas_refreshing_device_handles(MPT_ADAPTER *ioc,
1572 struct mptsas_devinfo *sas_device)
1573{
1574 struct mptsas_phyinfo *phy_info;
1575 struct mptsas_portinfo *port_info;
1576 int i;
1577
1578 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
1579 sas_device->sas_address);
1580 if (!phy_info)
1581 goto out;
1582 port_info = phy_info->portinfo;
1583 if (!port_info)
1584 goto out;
1585 mutex_lock(&ioc->sas_topology_mutex);
1586 for (i = 0; i < port_info->num_phys; i++) {
1587 if (port_info->phy_info[i].attached.sas_address !=
1588 sas_device->sas_address)
1589 continue;
1590 port_info->phy_info[i].attached.channel = sas_device->channel;
1591 port_info->phy_info[i].attached.id = sas_device->id;
1592 port_info->phy_info[i].attached.sas_address =
1593 sas_device->sas_address;
1594 port_info->phy_info[i].attached.handle = sas_device->handle;
1595 port_info->phy_info[i].attached.handle_parent =
1596 sas_device->handle_parent;
1597 port_info->phy_info[i].attached.handle_enclosure =
1598 sas_device->handle_enclosure;
1599 }
1600 mutex_unlock(&ioc->sas_topology_mutex);
1601 out:
1602 return phy_info;
1603}
1604
1605/**
1606 * mptsas_firmware_event_work - work thread for processing fw events
1607 * @work: work queue payload containing info describing the event
1608 * Context: user
1609 *
1610 */
1611static void
1612mptsas_firmware_event_work(struct work_struct *work)
1613{
1614 struct fw_event_work *fw_event =
1615 container_of(work, struct fw_event_work, work.work);
1616 MPT_ADAPTER *ioc = fw_event->ioc;
1617
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301618 /* special rescan topology handling */
1619 if (fw_event->event == -1) {
1620 if (ioc->in_rescan) {
1621 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
1622 "%s: rescan ignored as it is in progress\n",
1623 ioc->name, __func__));
1624 return;
1625 }
1626 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: rescan after "
1627 "reset\n", ioc->name, __func__));
1628 ioc->in_rescan = 1;
1629 mptsas_not_responding_devices(ioc);
1630 mptsas_scan_sas_topology(ioc);
1631 ioc->in_rescan = 0;
1632 mptsas_free_fw_event(ioc, fw_event);
Kashyap, Desai97660962009-09-02 11:46:33 +05301633 mptsas_fw_event_on(ioc);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05301634 return;
1635 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301636
1637 /* events handling turned off during host reset */
1638 if (ioc->fw_events_off) {
1639 mptsas_free_fw_event(ioc, fw_event);
1640 return;
1641 }
1642
1643 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "%s: fw_event=(0x%p), "
1644 "event = (0x%02x)\n", ioc->name, __func__, fw_event,
1645 (fw_event->event & 0xFF)));
1646
1647 switch (fw_event->event) {
1648 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
1649 mptsas_send_sas_event(fw_event);
1650 break;
1651 case MPI_EVENT_INTEGRATED_RAID:
1652 mptsas_send_raid_event(fw_event);
1653 break;
1654 case MPI_EVENT_IR2:
1655 mptsas_send_ir2_event(fw_event);
1656 break;
1657 case MPI_EVENT_PERSISTENT_TABLE_FULL:
1658 mptbase_sas_persist_operation(ioc,
1659 MPI_SAS_OP_CLEAR_NOT_PRESENT);
1660 mptsas_free_fw_event(ioc, fw_event);
1661 break;
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05301662 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
1663 mptsas_broadcast_primative_work(fw_event);
1664 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05301665 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
1666 mptsas_send_expander_event(fw_event);
1667 break;
1668 case MPI_EVENT_SAS_PHY_LINK_STATUS:
1669 mptsas_send_link_status_event(fw_event);
1670 break;
Kashyap, Desai57e98512009-05-29 16:55:09 +05301671 case MPI_EVENT_QUEUE_FULL:
1672 mptsas_handle_queue_full_event(fw_event);
1673 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301674 }
1675}
1676
1677
1678
James Bottomleyf013db32006-03-18 14:54:36 -06001679static int
1680mptsas_slave_configure(struct scsi_device *sdev)
1681{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301682 struct Scsi_Host *host = sdev->host;
1683 MPT_SCSI_HOST *hd = shost_priv(host);
1684 MPT_ADAPTER *ioc = hd->ioc;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301685 VirtDevice *vdevice = sdev->hostdata;
Moore, Eric3c0c25b2006-04-13 16:08:17 -06001686
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301687 if (vdevice->vtarget->deleted) {
1688 sdev_printk(KERN_INFO, sdev, "clearing deleted flag\n");
1689 vdevice->vtarget->deleted = 0;
1690 }
1691
1692 /*
1693 * RAID volumes placed beyond the last expected port.
1694 * Ignore sending sas mode pages in that case..
1695 */
1696 if (sdev->channel == MPTSAS_RAID_CHANNEL) {
1697 mptsas_add_device_component_starget_ir(ioc, scsi_target(sdev));
James Bottomleye8bf3942006-07-11 17:49:34 -04001698 goto out;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301699 }
James Bottomleyf013db32006-03-18 14:54:36 -06001700
James Bottomleye8bf3942006-07-11 17:49:34 -04001701 sas_read_port_mode_page(sdev);
1702
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301703 mptsas_add_device_component_starget(ioc, scsi_target(sdev));
1704
James Bottomleye8bf3942006-07-11 17:49:34 -04001705 out:
James Bottomleyf013db32006-03-18 14:54:36 -06001706 return mptscsih_slave_configure(sdev);
1707}
1708
Eric Moore547f9a22006-06-27 14:42:12 -06001709static int
1710mptsas_target_alloc(struct scsi_target *starget)
1711{
1712 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001713 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001714 VirtTarget *vtarget;
Eric Moore793955f2007-01-29 09:42:20 -07001715 u8 id, channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001716 struct sas_rphy *rphy;
1717 struct mptsas_portinfo *p;
1718 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001719 MPT_ADAPTER *ioc = hd->ioc;
Eric Moore547f9a22006-06-27 14:42:12 -06001720
1721 vtarget = kzalloc(sizeof(VirtTarget), GFP_KERNEL);
1722 if (!vtarget)
1723 return -ENOMEM;
1724
1725 vtarget->starget = starget;
Eric Mooree80b0022007-09-14 18:49:03 -06001726 vtarget->ioc_id = ioc->id;
Eric Moore793955f2007-01-29 09:42:20 -07001727 vtarget->tflags = MPT_TARGET_FLAGS_Q_YES;
1728 id = starget->id;
Eric Moore547f9a22006-06-27 14:42:12 -06001729 channel = 0;
1730
Eric Moore793955f2007-01-29 09:42:20 -07001731 /*
1732 * RAID volumes placed beyond the last expected port.
1733 */
1734 if (starget->channel == MPTSAS_RAID_CHANNEL) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05301735 if (!ioc->raid_data.pIocPg2) {
1736 kfree(vtarget);
1737 return -ENXIO;
1738 }
1739 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
1740 if (id == ioc->raid_data.pIocPg2->
1741 RaidVolume[i].VolumeID) {
1742 channel = ioc->raid_data.pIocPg2->
1743 RaidVolume[i].VolumeBus;
1744 }
1745 }
1746 vtarget->raidVolume = 1;
Eric Moore547f9a22006-06-27 14:42:12 -06001747 goto out;
Eric Moore793955f2007-01-29 09:42:20 -07001748 }
Eric Moore547f9a22006-06-27 14:42:12 -06001749
1750 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001751 mutex_lock(&ioc->sas_topology_mutex);
1752 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001753 for (i = 0; i < p->num_phys; i++) {
1754 if (p->phy_info[i].attached.sas_address !=
1755 rphy->identify.sas_address)
1756 continue;
Eric Moore793955f2007-01-29 09:42:20 -07001757 id = p->phy_info[i].attached.id;
Eric Moore547f9a22006-06-27 14:42:12 -06001758 channel = p->phy_info[i].attached.channel;
1759 mptsas_set_starget(&p->phy_info[i], starget);
1760
1761 /*
1762 * Exposing hidden raid components
1763 */
Eric Mooree80b0022007-09-14 18:49:03 -06001764 if (mptscsih_is_phys_disk(ioc, channel, id)) {
1765 id = mptscsih_raid_id_to_num(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001766 channel, id);
Eric Moore547f9a22006-06-27 14:42:12 -06001767 vtarget->tflags |=
1768 MPT_TARGET_FLAGS_RAID_COMPONENT;
Eric Mooreb506ade2007-01-29 09:45:37 -07001769 p->phy_info[i].attached.phys_disk_num = id;
Eric Moore547f9a22006-06-27 14:42:12 -06001770 }
Eric Mooree80b0022007-09-14 18:49:03 -06001771 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001772 goto out;
1773 }
1774 }
Eric Mooree80b0022007-09-14 18:49:03 -06001775 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001776
1777 kfree(vtarget);
1778 return -ENXIO;
1779
1780 out:
Eric Moore793955f2007-01-29 09:42:20 -07001781 vtarget->id = id;
1782 vtarget->channel = channel;
Eric Moore547f9a22006-06-27 14:42:12 -06001783 starget->hostdata = vtarget;
1784 return 0;
1785}
1786
1787static void
1788mptsas_target_destroy(struct scsi_target *starget)
1789{
1790 struct Scsi_Host *host = dev_to_shost(&starget->dev);
Eric Mooree7eae9f2007-09-29 10:15:59 -06001791 MPT_SCSI_HOST *hd = shost_priv(host);
Eric Moore547f9a22006-06-27 14:42:12 -06001792 struct sas_rphy *rphy;
1793 struct mptsas_portinfo *p;
1794 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301795 MPT_ADAPTER *ioc = hd->ioc;
1796 VirtTarget *vtarget;
Eric Moore547f9a22006-06-27 14:42:12 -06001797
1798 if (!starget->hostdata)
1799 return;
1800
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301801 vtarget = starget->hostdata;
1802
Kashyap, Desai57e98512009-05-29 16:55:09 +05301803 mptsas_del_device_component_by_os(ioc, starget->channel,
1804 starget->id);
1805
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301806
James Bottomleye8bf3942006-07-11 17:49:34 -04001807 if (starget->channel == MPTSAS_RAID_CHANNEL)
Eric Moore547f9a22006-06-27 14:42:12 -06001808 goto out;
1809
1810 rphy = dev_to_rphy(starget->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001811 list_for_each_entry(p, &ioc->sas_topology, list) {
Eric Moore547f9a22006-06-27 14:42:12 -06001812 for (i = 0; i < p->num_phys; i++) {
1813 if (p->phy_info[i].attached.sas_address !=
1814 rphy->identify.sas_address)
1815 continue;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301816
1817 starget_printk(KERN_INFO, starget, MYIOC_s_FMT
1818 "delete device: fw_channel %d, fw_id %d, phy %d, "
1819 "sas_addr 0x%llx\n", ioc->name,
1820 p->phy_info[i].attached.channel,
1821 p->phy_info[i].attached.id,
1822 p->phy_info[i].attached.phy_id, (unsigned long long)
1823 p->phy_info[i].attached.sas_address);
1824
Eric Moore547f9a22006-06-27 14:42:12 -06001825 mptsas_set_starget(&p->phy_info[i], NULL);
Eric Moore547f9a22006-06-27 14:42:12 -06001826 }
1827 }
1828
1829 out:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05301830 vtarget->starget = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06001831 kfree(starget->hostdata);
1832 starget->hostdata = NULL;
1833}
1834
1835
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001836static int
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001837mptsas_slave_alloc(struct scsi_device *sdev)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001838{
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001839 struct Scsi_Host *host = sdev->host;
Eric Mooree7eae9f2007-09-29 10:15:59 -06001840 MPT_SCSI_HOST *hd = shost_priv(host);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001841 struct sas_rphy *rphy;
1842 struct mptsas_portinfo *p;
Eric Moorea69de502007-09-14 18:48:19 -06001843 VirtDevice *vdevice;
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001844 struct scsi_target *starget;
Eric Moore547f9a22006-06-27 14:42:12 -06001845 int i;
Eric Mooree80b0022007-09-14 18:49:03 -06001846 MPT_ADAPTER *ioc = hd->ioc;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001847
Eric Moorea69de502007-09-14 18:48:19 -06001848 vdevice = kzalloc(sizeof(VirtDevice), GFP_KERNEL);
1849 if (!vdevice) {
Eric Moore547f9a22006-06-27 14:42:12 -06001850 printk(MYIOC_s_ERR_FMT "slave_alloc kzalloc(%zd) FAILED!\n",
Eric Mooree80b0022007-09-14 18:49:03 -06001851 ioc->name, sizeof(VirtDevice));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001852 return -ENOMEM;
1853 }
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001854 starget = scsi_target(sdev);
Eric Moorea69de502007-09-14 18:48:19 -06001855 vdevice->vtarget = starget->hostdata;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001856
James Bottomleye8bf3942006-07-11 17:49:34 -04001857 if (sdev->channel == MPTSAS_RAID_CHANNEL)
Moore, Eric816aa902006-01-13 16:25:20 -07001858 goto out;
Moore, Eric816aa902006-01-13 16:25:20 -07001859
Moore, Eric Deanc7c82982005-11-16 18:54:25 -07001860 rphy = dev_to_rphy(sdev->sdev_target->dev.parent);
Eric Mooree80b0022007-09-14 18:49:03 -06001861 mutex_lock(&ioc->sas_topology_mutex);
1862 list_for_each_entry(p, &ioc->sas_topology, list) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001863 for (i = 0; i < p->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06001864 if (p->phy_info[i].attached.sas_address !=
1865 rphy->identify.sas_address)
1866 continue;
Eric Moorea69de502007-09-14 18:48:19 -06001867 vdevice->lun = sdev->lun;
Eric Moore547f9a22006-06-27 14:42:12 -06001868 /*
1869 * Exposing hidden raid components
1870 */
Eric Mooree80b0022007-09-14 18:49:03 -06001871 if (mptscsih_is_phys_disk(ioc,
Eric Moore793955f2007-01-29 09:42:20 -07001872 p->phy_info[i].attached.channel,
1873 p->phy_info[i].attached.id))
Eric Moore547f9a22006-06-27 14:42:12 -06001874 sdev->no_uld_attach = 1;
Eric Mooree80b0022007-09-14 18:49:03 -06001875 mutex_unlock(&ioc->sas_topology_mutex);
Eric Moore547f9a22006-06-27 14:42:12 -06001876 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001877 }
1878 }
Eric Mooree80b0022007-09-14 18:49:03 -06001879 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001880
Eric Moorea69de502007-09-14 18:48:19 -06001881 kfree(vdevice);
Christoph Hellwig23f236e2006-01-30 19:00:43 +01001882 return -ENXIO;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001883
1884 out:
Eric Moorea69de502007-09-14 18:48:19 -06001885 vdevice->vtarget->num_luns++;
1886 sdev->hostdata = vdevice;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001887 return 0;
1888}
1889
Eric Moore547f9a22006-06-27 14:42:12 -06001890static int
1891mptsas_qcmd(struct scsi_cmnd *SCpnt, void (*done)(struct scsi_cmnd *))
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001892{
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301893 MPT_SCSI_HOST *hd;
1894 MPT_ADAPTER *ioc;
Eric Moorea69de502007-09-14 18:48:19 -06001895 VirtDevice *vdevice = SCpnt->device->hostdata;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001896
Eric Moorea69de502007-09-14 18:48:19 -06001897 if (!vdevice || !vdevice->vtarget || vdevice->vtarget->deleted) {
Eric Moore547f9a22006-06-27 14:42:12 -06001898 SCpnt->result = DID_NO_CONNECT << 16;
1899 done(SCpnt);
1900 return 0;
Moore, Eric7d3eecf2006-01-25 18:05:12 -07001901 }
Eric Moore547f9a22006-06-27 14:42:12 -06001902
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05301903 hd = shost_priv(SCpnt->device->host);
1904 ioc = hd->ioc;
1905
1906 if (ioc->sas_discovery_quiesce_io)
1907 return SCSI_MLQUEUE_HOST_BUSY;
1908
Kashyap, Desai64e155a2009-12-16 19:02:29 +05301909 if (ioc->debug_level & MPT_DEBUG_SCSI)
1910 scsi_print_command(SCpnt);
Eric Moore793955f2007-01-29 09:42:20 -07001911
Eric Moore547f9a22006-06-27 14:42:12 -06001912 return mptscsih_qcmd(SCpnt,done);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01001913}
1914
Eric Moore547f9a22006-06-27 14:42:12 -06001915
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001916static struct scsi_host_template mptsas_driver_template = {
Moore, Eric Deanf78496d2005-11-16 18:54:14 -07001917 .module = THIS_MODULE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001918 .proc_name = "mptsas",
1919 .proc_info = mptscsih_proc_info,
Kashyap, Desai568da762010-03-18 19:23:50 +05301920 .name = "MPT SAS Host",
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001921 .info = mptscsih_info,
Eric Moore547f9a22006-06-27 14:42:12 -06001922 .queuecommand = mptsas_qcmd,
1923 .target_alloc = mptsas_target_alloc,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001924 .slave_alloc = mptsas_slave_alloc,
James Bottomleyf013db32006-03-18 14:54:36 -06001925 .slave_configure = mptsas_slave_configure,
Eric Moore547f9a22006-06-27 14:42:12 -06001926 .target_destroy = mptsas_target_destroy,
1927 .slave_destroy = mptscsih_slave_destroy,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001928 .change_queue_depth = mptscsih_change_queue_depth,
1929 .eh_abort_handler = mptscsih_abort,
1930 .eh_device_reset_handler = mptscsih_dev_reset,
1931 .eh_bus_reset_handler = mptscsih_bus_reset,
1932 .eh_host_reset_handler = mptscsih_host_reset,
1933 .bios_param = mptscsih_bios_param,
Kashyap, Desai9d2e9d62009-08-05 12:48:44 +05301934 .can_queue = MPT_SAS_CAN_QUEUE,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001935 .this_id = -1,
1936 .sg_tablesize = MPT_SCSI_SG_DEPTH,
1937 .max_sectors = 8192,
1938 .cmd_per_lun = 7,
1939 .use_clustering = ENABLE_CLUSTERING,
Prakash, Sathyaedb90682007-07-17 14:39:14 +05301940 .shost_attrs = mptscsih_host_attrs,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02001941};
1942
Christoph Hellwigb5141122005-10-28 22:07:41 +02001943static int mptsas_get_linkerrors(struct sas_phy *phy)
1944{
1945 MPT_ADAPTER *ioc = phy_to_ioc(phy);
1946 ConfigExtendedPageHeader_t hdr;
1947 CONFIGPARMS cfg;
1948 SasPhyPage1_t *buffer;
1949 dma_addr_t dma_handle;
1950 int error;
1951
James Bottomleyf4ad7b52006-08-25 13:48:18 -05001952 /* FIXME: only have link errors on local phys */
1953 if (!scsi_is_sas_phy_local(phy))
1954 return -EINVAL;
1955
Christoph Hellwigb5141122005-10-28 22:07:41 +02001956 hdr.PageVersion = MPI_SASPHY1_PAGEVERSION;
1957 hdr.ExtPageLength = 0;
1958 hdr.PageNumber = 1 /* page number 1*/;
1959 hdr.Reserved1 = 0;
1960 hdr.Reserved2 = 0;
1961 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
1962 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
1963
1964 cfg.cfghdr.ehdr = &hdr;
1965 cfg.physAddr = -1;
1966 cfg.pageAddr = phy->identify.phy_identifier;
1967 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
1968 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05301969 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwigb5141122005-10-28 22:07:41 +02001970
1971 error = mpt_config(ioc, &cfg);
1972 if (error)
1973 return error;
1974 if (!hdr.ExtPageLength)
1975 return -ENXIO;
1976
1977 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
1978 &dma_handle);
1979 if (!buffer)
1980 return -ENOMEM;
1981
1982 cfg.physAddr = dma_handle;
1983 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
1984
1985 error = mpt_config(ioc, &cfg);
1986 if (error)
1987 goto out_free_consistent;
1988
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05301989 mptsas_print_phy_pg1(ioc, buffer);
Christoph Hellwigb5141122005-10-28 22:07:41 +02001990
1991 phy->invalid_dword_count = le32_to_cpu(buffer->InvalidDwordCount);
1992 phy->running_disparity_error_count =
1993 le32_to_cpu(buffer->RunningDisparityErrorCount);
1994 phy->loss_of_dword_sync_count =
1995 le32_to_cpu(buffer->LossDwordSynchCount);
1996 phy->phy_reset_problem_count =
1997 le32_to_cpu(buffer->PhyResetProblemCount);
1998
1999 out_free_consistent:
2000 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2001 buffer, dma_handle);
2002 return error;
2003}
2004
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002005static int mptsas_mgmt_done(MPT_ADAPTER *ioc, MPT_FRAME_HDR *req,
2006 MPT_FRAME_HDR *reply)
2007{
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302008 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_COMMAND_GOOD;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002009 if (reply != NULL) {
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302010 ioc->sas_mgmt.status |= MPT_MGMT_STATUS_RF_VALID;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002011 memcpy(ioc->sas_mgmt.reply, reply,
2012 min(ioc->reply_sz, 4 * reply->u.reply.MsgLength));
2013 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05302014
2015 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_PENDING) {
2016 ioc->sas_mgmt.status &= ~MPT_MGMT_STATUS_PENDING;
2017 complete(&ioc->sas_mgmt.done);
2018 return 1;
2019 }
2020 return 0;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002021}
2022
2023static int mptsas_phy_reset(struct sas_phy *phy, int hard_reset)
2024{
2025 MPT_ADAPTER *ioc = phy_to_ioc(phy);
2026 SasIoUnitControlRequest_t *req;
2027 SasIoUnitControlReply_t *reply;
2028 MPT_FRAME_HDR *mf;
2029 MPIHeader_t *hdr;
2030 unsigned long timeleft;
2031 int error = -ERESTARTSYS;
2032
James Bottomleyf4ad7b52006-08-25 13:48:18 -05002033 /* FIXME: fusion doesn't allow non-local phy reset */
2034 if (!scsi_is_sas_phy_local(phy))
2035 return -EINVAL;
2036
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002037 /* not implemented for expanders */
2038 if (phy->identify.target_port_protocols & SAS_PROTOCOL_SMP)
2039 return -ENXIO;
2040
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002041 if (mutex_lock_interruptible(&ioc->sas_mgmt.mutex))
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002042 goto out;
2043
2044 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2045 if (!mf) {
2046 error = -ENOMEM;
2047 goto out_unlock;
2048 }
2049
2050 hdr = (MPIHeader_t *) mf;
2051 req = (SasIoUnitControlRequest_t *)mf;
2052 memset(req, 0, sizeof(SasIoUnitControlRequest_t));
2053 req->Function = MPI_FUNCTION_SAS_IO_UNIT_CONTROL;
2054 req->MsgContext = hdr->MsgContext;
2055 req->Operation = hard_reset ?
2056 MPI_SAS_OP_PHY_HARD_RESET : MPI_SAS_OP_PHY_LINK_RESET;
2057 req->PhyNum = phy->identify.phy_identifier;
2058
Kashyap, Desai2f187862009-05-29 16:52:37 +05302059 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002060 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2061
2062 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done,
2063 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302064 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2065 error = -ETIME;
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002066 mpt_free_msg_frame(ioc, mf);
Kashyap, Desai568da762010-03-18 19:23:50 +05302067 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2068 goto out_unlock;
2069 if (!timeleft)
2070 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002071 goto out_unlock;
2072 }
2073
2074 /* a reply frame is expected */
2075 if ((ioc->sas_mgmt.status &
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302076 MPT_MGMT_STATUS_RF_VALID) == 0) {
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002077 error = -ENXIO;
2078 goto out_unlock;
2079 }
2080
2081 /* process the completed Reply Message Frame */
2082 reply = (SasIoUnitControlReply_t *)ioc->sas_mgmt.reply;
2083 if (reply->IOCStatus != MPI_IOCSTATUS_SUCCESS) {
Eric Moore29dd3602007-09-14 18:46:51 -06002084 printk(MYIOC_s_INFO_FMT "%s: IOCStatus=0x%X IOCLogInfo=0x%X\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002085 ioc->name, __func__, reply->IOCStatus, reply->IOCLogInfo);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002086 error = -ENXIO;
2087 goto out_unlock;
2088 }
2089
2090 error = 0;
2091
2092 out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302093 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01002094 mutex_unlock(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002095 out:
2096 return error;
2097}
Christoph Hellwigb5141122005-10-28 22:07:41 +02002098
Christoph Hellwige3094442006-02-16 13:25:36 +01002099static int
2100mptsas_get_enclosure_identifier(struct sas_rphy *rphy, u64 *identifier)
2101{
2102 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2103 int i, error;
2104 struct mptsas_portinfo *p;
2105 struct mptsas_enclosure enclosure_info;
2106 u64 enclosure_handle;
2107
2108 mutex_lock(&ioc->sas_topology_mutex);
2109 list_for_each_entry(p, &ioc->sas_topology, list) {
2110 for (i = 0; i < p->num_phys; i++) {
2111 if (p->phy_info[i].attached.sas_address ==
2112 rphy->identify.sas_address) {
2113 enclosure_handle = p->phy_info[i].
2114 attached.handle_enclosure;
2115 goto found_info;
2116 }
2117 }
2118 }
2119 mutex_unlock(&ioc->sas_topology_mutex);
2120 return -ENXIO;
2121
2122 found_info:
2123 mutex_unlock(&ioc->sas_topology_mutex);
2124 memset(&enclosure_info, 0, sizeof(struct mptsas_enclosure));
Moore, Eric52435432006-03-14 09:14:15 -07002125 error = mptsas_sas_enclosure_pg0(ioc, &enclosure_info,
Christoph Hellwige3094442006-02-16 13:25:36 +01002126 (MPI_SAS_ENCLOS_PGAD_FORM_HANDLE <<
2127 MPI_SAS_ENCLOS_PGAD_FORM_SHIFT), enclosure_handle);
2128 if (!error)
2129 *identifier = enclosure_info.enclosure_logical_id;
2130 return error;
2131}
2132
2133static int
2134mptsas_get_bay_identifier(struct sas_rphy *rphy)
2135{
2136 MPT_ADAPTER *ioc = rphy_to_ioc(rphy);
2137 struct mptsas_portinfo *p;
2138 int i, rc;
2139
2140 mutex_lock(&ioc->sas_topology_mutex);
2141 list_for_each_entry(p, &ioc->sas_topology, list) {
2142 for (i = 0; i < p->num_phys; i++) {
2143 if (p->phy_info[i].attached.sas_address ==
2144 rphy->identify.sas_address) {
2145 rc = p->phy_info[i].attached.slot;
2146 goto out;
2147 }
2148 }
2149 }
2150 rc = -ENXIO;
2151 out:
2152 mutex_unlock(&ioc->sas_topology_mutex);
2153 return rc;
2154}
2155
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002156static int mptsas_smp_handler(struct Scsi_Host *shost, struct sas_rphy *rphy,
2157 struct request *req)
2158{
2159 MPT_ADAPTER *ioc = ((MPT_SCSI_HOST *) shost->hostdata)->ioc;
2160 MPT_FRAME_HDR *mf;
2161 SmpPassthroughRequest_t *smpreq;
2162 struct request *rsp = req->next_rq;
2163 int ret;
2164 int flagsLength;
2165 unsigned long timeleft;
2166 char *psge;
2167 dma_addr_t dma_addr_in = 0;
2168 dma_addr_t dma_addr_out = 0;
2169 u64 sas_address = 0;
2170
2171 if (!rsp) {
Eric Moore29dd3602007-09-14 18:46:51 -06002172 printk(MYIOC_s_ERR_FMT "%s: the smp response space is missing\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002173 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002174 return -EINVAL;
2175 }
2176
2177 /* do we need to support multiple segments? */
2178 if (req->bio->bi_vcnt > 1 || rsp->bio->bi_vcnt > 1) {
Eric Moore29dd3602007-09-14 18:46:51 -06002179 printk(MYIOC_s_ERR_FMT "%s: multiple segments req %u %u, rsp %u %u\n",
Tejun Heob0790412009-05-07 22:24:42 +09002180 ioc->name, __func__, req->bio->bi_vcnt, blk_rq_bytes(req),
2181 rsp->bio->bi_vcnt, blk_rq_bytes(rsp));
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002182 return -EINVAL;
2183 }
2184
2185 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2186 if (ret)
2187 goto out;
2188
2189 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2190 if (!mf) {
2191 ret = -ENOMEM;
2192 goto out_unlock;
2193 }
2194
2195 smpreq = (SmpPassthroughRequest_t *)mf;
2196 memset(smpreq, 0, sizeof(*smpreq));
2197
Tejun Heob0790412009-05-07 22:24:42 +09002198 smpreq->RequestDataLength = cpu_to_le16(blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002199 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2200
2201 if (rphy)
2202 sas_address = rphy->identify.sas_address;
2203 else {
2204 struct mptsas_portinfo *port_info;
2205
2206 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05302207 port_info = ioc->hba_port_info;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002208 if (port_info && port_info->phy_info)
2209 sas_address =
2210 port_info->phy_info[0].phy->identify.sas_address;
2211 mutex_unlock(&ioc->sas_topology_mutex);
2212 }
2213
2214 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2215
2216 psge = (char *)
2217 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2218
2219 /* request */
2220 flagsLength = (MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2221 MPI_SGE_FLAGS_END_OF_BUFFER |
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302222 MPI_SGE_FLAGS_DIRECTION)
2223 << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002224 flagsLength |= (blk_rq_bytes(req) - 4);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002225
2226 dma_addr_out = pci_map_single(ioc->pcidev, bio_data(req->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002227 blk_rq_bytes(req), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002228 if (!dma_addr_out)
2229 goto put_mf;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302230 ioc->add_sge(psge, flagsLength, dma_addr_out);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302231 psge += ioc->SGE_size;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002232
2233 /* response */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302234 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2235 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2236 MPI_SGE_FLAGS_IOC_TO_HOST |
2237 MPI_SGE_FLAGS_END_OF_BUFFER;
2238
2239 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
Tejun Heob0790412009-05-07 22:24:42 +09002240 flagsLength |= blk_rq_bytes(rsp) + 4;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002241 dma_addr_in = pci_map_single(ioc->pcidev, bio_data(rsp->bio),
Tejun Heob0790412009-05-07 22:24:42 +09002242 blk_rq_bytes(rsp), PCI_DMA_BIDIRECTIONAL);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002243 if (!dma_addr_in)
2244 goto unmap;
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05302245 ioc->add_sge(psge, flagsLength, dma_addr_in);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002246
Kashyap, Desai2f187862009-05-29 16:52:37 +05302247 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002248 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2249
2250 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
Kashyap, Desai568da762010-03-18 19:23:50 +05302251 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2252 ret = -ETIME;
2253 mpt_free_msg_frame(ioc, mf);
2254 mf = NULL;
2255 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2256 goto unmap;
2257 if (!timeleft)
2258 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002259 goto unmap;
2260 }
2261 mf = NULL;
2262
Kashyap, Desaif0f09d32009-05-29 16:40:57 +05302263 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002264 SmpPassthroughReply_t *smprep;
2265
2266 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2267 memcpy(req->sense, smprep, sizeof(*smprep));
2268 req->sense_len = sizeof(*smprep);
Tejun Heo5f49f632009-05-19 18:33:05 +09002269 req->resid_len = 0;
2270 rsp->resid_len -= smprep->ResponseDataLength;
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002271 } else {
Kashyap, Desai2f187862009-05-29 16:52:37 +05302272 printk(MYIOC_s_ERR_FMT
2273 "%s: smp passthru reply failed to be returned\n",
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07002274 ioc->name, __func__);
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002275 ret = -ENXIO;
2276 }
2277unmap:
2278 if (dma_addr_out)
Tejun Heob0790412009-05-07 22:24:42 +09002279 pci_unmap_single(ioc->pcidev, dma_addr_out, blk_rq_bytes(req),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002280 PCI_DMA_BIDIRECTIONAL);
2281 if (dma_addr_in)
Tejun Heob0790412009-05-07 22:24:42 +09002282 pci_unmap_single(ioc->pcidev, dma_addr_in, blk_rq_bytes(rsp),
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002283 PCI_DMA_BIDIRECTIONAL);
2284put_mf:
2285 if (mf)
2286 mpt_free_msg_frame(ioc, mf);
2287out_unlock:
Kashyap, Desai2f187862009-05-29 16:52:37 +05302288 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002289 mutex_unlock(&ioc->sas_mgmt.mutex);
2290out:
2291 return ret;
2292}
2293
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002294static struct sas_function_template mptsas_transport_functions = {
Christoph Hellwigb5141122005-10-28 22:07:41 +02002295 .get_linkerrors = mptsas_get_linkerrors,
Christoph Hellwige3094442006-02-16 13:25:36 +01002296 .get_enclosure_identifier = mptsas_get_enclosure_identifier,
2297 .get_bay_identifier = mptsas_get_bay_identifier,
Christoph Hellwigda4fa652005-10-19 20:01:42 +02002298 .phy_reset = mptsas_phy_reset,
FUJITA Tomonori159e36f2007-07-30 11:10:07 -06002299 .smp_handler = mptsas_smp_handler,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002300};
2301
2302static struct scsi_transport_template *mptsas_transport_template;
2303
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002304static int
2305mptsas_sas_io_unit_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
2306{
2307 ConfigExtendedPageHeader_t hdr;
2308 CONFIGPARMS cfg;
2309 SasIOUnitPage0_t *buffer;
2310 dma_addr_t dma_handle;
2311 int error, i;
2312
2313 hdr.PageVersion = MPI_SASIOUNITPAGE0_PAGEVERSION;
2314 hdr.ExtPageLength = 0;
2315 hdr.PageNumber = 0;
2316 hdr.Reserved1 = 0;
2317 hdr.Reserved2 = 0;
2318 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2319 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2320
2321 cfg.cfghdr.ehdr = &hdr;
2322 cfg.physAddr = -1;
2323 cfg.pageAddr = 0;
2324 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2325 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302326 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002327
2328 error = mpt_config(ioc, &cfg);
2329 if (error)
2330 goto out;
2331 if (!hdr.ExtPageLength) {
2332 error = -ENXIO;
2333 goto out;
2334 }
2335
2336 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2337 &dma_handle);
2338 if (!buffer) {
2339 error = -ENOMEM;
2340 goto out;
2341 }
2342
2343 cfg.physAddr = dma_handle;
2344 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2345
2346 error = mpt_config(ioc, &cfg);
2347 if (error)
2348 goto out_free_consistent;
2349
2350 port_info->num_phys = buffer->NumPhys;
2351 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302352 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002353 if (!port_info->phy_info) {
2354 error = -ENOMEM;
2355 goto out_free_consistent;
2356 }
2357
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302358 ioc->nvdata_version_persistent =
2359 le16_to_cpu(buffer->NvdataVersionPersistent);
2360 ioc->nvdata_version_default =
2361 le16_to_cpu(buffer->NvdataVersionDefault);
2362
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002363 for (i = 0; i < port_info->num_phys; i++) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302364 mptsas_print_phy_data(ioc, &buffer->PhyData[i]);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002365 port_info->phy_info[i].phy_id = i;
2366 port_info->phy_info[i].port_id =
2367 buffer->PhyData[i].Port;
2368 port_info->phy_info[i].negotiated_link_rate =
2369 buffer->PhyData[i].NegotiatedLinkRate;
Eric Moore547f9a22006-06-27 14:42:12 -06002370 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002371 port_info->phy_info[i].handle =
2372 le16_to_cpu(buffer->PhyData[i].ControllerDevHandle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002373 }
2374
2375 out_free_consistent:
2376 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2377 buffer, dma_handle);
2378 out:
2379 return error;
2380}
2381
2382static int
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302383mptsas_sas_io_unit_pg1(MPT_ADAPTER *ioc)
2384{
2385 ConfigExtendedPageHeader_t hdr;
2386 CONFIGPARMS cfg;
2387 SasIOUnitPage1_t *buffer;
2388 dma_addr_t dma_handle;
2389 int error;
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302390 u8 device_missing_delay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302391
2392 memset(&hdr, 0, sizeof(ConfigExtendedPageHeader_t));
2393 memset(&cfg, 0, sizeof(CONFIGPARMS));
2394
2395 cfg.cfghdr.ehdr = &hdr;
2396 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai4b976502009-08-05 12:52:03 +05302397 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302398 cfg.cfghdr.ehdr->PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2399 cfg.cfghdr.ehdr->ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_IO_UNIT;
2400 cfg.cfghdr.ehdr->PageVersion = MPI_SASIOUNITPAGE1_PAGEVERSION;
2401 cfg.cfghdr.ehdr->PageNumber = 1;
2402
2403 error = mpt_config(ioc, &cfg);
2404 if (error)
2405 goto out;
2406 if (!hdr.ExtPageLength) {
2407 error = -ENXIO;
2408 goto out;
2409 }
2410
2411 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2412 &dma_handle);
2413 if (!buffer) {
2414 error = -ENOMEM;
2415 goto out;
2416 }
2417
2418 cfg.physAddr = dma_handle;
2419 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2420
2421 error = mpt_config(ioc, &cfg);
2422 if (error)
2423 goto out_free_consistent;
2424
2425 ioc->io_missing_delay =
2426 le16_to_cpu(buffer->IODeviceMissingDelay);
Kashyap, Desaiaca794d2010-06-17 14:39:25 +05302427 device_missing_delay = buffer->ReportDeviceMissingDelay;
Prakash, Sathyaedb90682007-07-17 14:39:14 +05302428 ioc->device_missing_delay = (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_UNIT_16) ?
2429 (device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK) * 16 :
2430 device_missing_delay & MPI_SAS_IOUNIT1_REPORT_MISSING_TIMEOUT_MASK;
2431
2432 out_free_consistent:
2433 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2434 buffer, dma_handle);
2435 out:
2436 return error;
2437}
2438
2439static int
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002440mptsas_sas_phy_pg0(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2441 u32 form, u32 form_specific)
2442{
2443 ConfigExtendedPageHeader_t hdr;
2444 CONFIGPARMS cfg;
2445 SasPhyPage0_t *buffer;
2446 dma_addr_t dma_handle;
2447 int error;
2448
2449 hdr.PageVersion = MPI_SASPHY0_PAGEVERSION;
2450 hdr.ExtPageLength = 0;
2451 hdr.PageNumber = 0;
2452 hdr.Reserved1 = 0;
2453 hdr.Reserved2 = 0;
2454 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2455 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_PHY;
2456
2457 cfg.cfghdr.ehdr = &hdr;
2458 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302459 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002460
2461 /* Get Phy Pg 0 for each Phy. */
2462 cfg.physAddr = -1;
2463 cfg.pageAddr = form + form_specific;
2464 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2465
2466 error = mpt_config(ioc, &cfg);
2467 if (error)
2468 goto out;
2469
2470 if (!hdr.ExtPageLength) {
2471 error = -ENXIO;
2472 goto out;
2473 }
2474
2475 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2476 &dma_handle);
2477 if (!buffer) {
2478 error = -ENOMEM;
2479 goto out;
2480 }
2481
2482 cfg.physAddr = dma_handle;
2483 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2484
2485 error = mpt_config(ioc, &cfg);
2486 if (error)
2487 goto out_free_consistent;
2488
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302489 mptsas_print_phy_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002490
2491 phy_info->hw_link_rate = buffer->HwLinkRate;
2492 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2493 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2494 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2495
2496 out_free_consistent:
2497 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2498 buffer, dma_handle);
2499 out:
2500 return error;
2501}
2502
2503static int
2504mptsas_sas_device_pg0(MPT_ADAPTER *ioc, struct mptsas_devinfo *device_info,
2505 u32 form, u32 form_specific)
2506{
2507 ConfigExtendedPageHeader_t hdr;
2508 CONFIGPARMS cfg;
2509 SasDevicePage0_t *buffer;
2510 dma_addr_t dma_handle;
2511 __le64 sas_address;
Moore, Ericbd23e942006-04-17 12:43:04 -06002512 int error=0;
2513
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002514 hdr.PageVersion = MPI_SASDEVICE0_PAGEVERSION;
2515 hdr.ExtPageLength = 0;
2516 hdr.PageNumber = 0;
2517 hdr.Reserved1 = 0;
2518 hdr.Reserved2 = 0;
2519 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2520 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_DEVICE;
2521
2522 cfg.cfghdr.ehdr = &hdr;
2523 cfg.pageAddr = form + form_specific;
2524 cfg.physAddr = -1;
2525 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2526 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302527 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002528
Moore, Ericdb9c9172006-03-14 09:14:18 -07002529 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002530 error = mpt_config(ioc, &cfg);
2531 if (error)
2532 goto out;
2533 if (!hdr.ExtPageLength) {
2534 error = -ENXIO;
2535 goto out;
2536 }
2537
2538 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2539 &dma_handle);
2540 if (!buffer) {
2541 error = -ENOMEM;
2542 goto out;
2543 }
2544
2545 cfg.physAddr = dma_handle;
2546 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2547
2548 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302549
2550 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2551 error = -ENODEV;
2552 goto out_free_consistent;
2553 }
2554
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002555 if (error)
2556 goto out_free_consistent;
2557
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302558 mptsas_print_device_pg0(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002559
Kashyap, Desai2f187862009-05-29 16:52:37 +05302560 memset(device_info, 0, sizeof(struct mptsas_devinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002561 device_info->handle = le16_to_cpu(buffer->DevHandle);
Moore, Ericc73787ee2006-01-26 16:20:06 -07002562 device_info->handle_parent = le16_to_cpu(buffer->ParentDevHandle);
Christoph Hellwige3094442006-02-16 13:25:36 +01002563 device_info->handle_enclosure =
2564 le16_to_cpu(buffer->EnclosureHandle);
2565 device_info->slot = le16_to_cpu(buffer->Slot);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002566 device_info->phy_id = buffer->PhyNum;
2567 device_info->port_id = buffer->PhysicalPort;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002568 device_info->id = buffer->TargetID;
Eric Mooreb506ade2007-01-29 09:45:37 -07002569 device_info->phys_disk_num = ~0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002570 device_info->channel = buffer->Bus;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002571 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
2572 device_info->sas_address = le64_to_cpu(sas_address);
2573 device_info->device_info =
2574 le32_to_cpu(buffer->DeviceInfo);
Kashyap, Desai51106ab2010-06-17 14:40:10 +05302575 device_info->flags = le16_to_cpu(buffer->Flags);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002576
2577 out_free_consistent:
2578 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2579 buffer, dma_handle);
2580 out:
2581 return error;
2582}
2583
2584static int
2585mptsas_sas_expander_pg0(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info,
2586 u32 form, u32 form_specific)
2587{
2588 ConfigExtendedPageHeader_t hdr;
2589 CONFIGPARMS cfg;
2590 SasExpanderPage0_t *buffer;
2591 dma_addr_t dma_handle;
Eric Moore547f9a22006-06-27 14:42:12 -06002592 int i, error;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302593 __le64 sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002594
Kashyap, Desai2f187862009-05-29 16:52:37 +05302595 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002596 hdr.PageVersion = MPI_SASEXPANDER0_PAGEVERSION;
2597 hdr.ExtPageLength = 0;
2598 hdr.PageNumber = 0;
2599 hdr.Reserved1 = 0;
2600 hdr.Reserved2 = 0;
2601 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2602 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2603
2604 cfg.cfghdr.ehdr = &hdr;
2605 cfg.physAddr = -1;
2606 cfg.pageAddr = form + form_specific;
2607 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2608 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302609 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002610
Moore, Ericdb9c9172006-03-14 09:14:18 -07002611 memset(port_info, 0, sizeof(struct mptsas_portinfo));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002612 error = mpt_config(ioc, &cfg);
2613 if (error)
2614 goto out;
2615
2616 if (!hdr.ExtPageLength) {
2617 error = -ENXIO;
2618 goto out;
2619 }
2620
2621 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2622 &dma_handle);
2623 if (!buffer) {
2624 error = -ENOMEM;
2625 goto out;
2626 }
2627
2628 cfg.physAddr = dma_handle;
2629 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2630
2631 error = mpt_config(ioc, &cfg);
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302632 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
Krzysztof Oledzki51f39ea2008-03-04 14:56:23 -08002633 error = -ENODEV;
2634 goto out_free_consistent;
2635 }
2636
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302637 if (error)
2638 goto out_free_consistent;
2639
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002640 /* save config data */
Kashyap, Desai2f187862009-05-29 16:52:37 +05302641 port_info->num_phys = (buffer->NumPhys) ? buffer->NumPhys : 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002642 port_info->phy_info = kcalloc(port_info->num_phys,
Kashyap, Desai2f187862009-05-29 16:52:37 +05302643 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002644 if (!port_info->phy_info) {
2645 error = -ENOMEM;
2646 goto out_free_consistent;
2647 }
2648
Kashyap, Desai2f187862009-05-29 16:52:37 +05302649 memcpy(&sas_address, &buffer->SASAddress, sizeof(__le64));
Eric Moore2ecce492007-01-29 09:47:08 -07002650 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06002651 port_info->phy_info[i].portinfo = port_info;
Eric Moore2ecce492007-01-29 09:47:08 -07002652 port_info->phy_info[i].handle =
2653 le16_to_cpu(buffer->DevHandle);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302654 port_info->phy_info[i].identify.sas_address =
2655 le64_to_cpu(sas_address);
2656 port_info->phy_info[i].identify.handle_parent =
2657 le16_to_cpu(buffer->ParentDevHandle);
Eric Moore2ecce492007-01-29 09:47:08 -07002658 }
Eric Moore547f9a22006-06-27 14:42:12 -06002659
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002660 out_free_consistent:
2661 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2662 buffer, dma_handle);
2663 out:
2664 return error;
2665}
2666
2667static int
2668mptsas_sas_expander_pg1(MPT_ADAPTER *ioc, struct mptsas_phyinfo *phy_info,
2669 u32 form, u32 form_specific)
2670{
2671 ConfigExtendedPageHeader_t hdr;
2672 CONFIGPARMS cfg;
2673 SasExpanderPage1_t *buffer;
2674 dma_addr_t dma_handle;
Moore, Ericbd23e942006-04-17 12:43:04 -06002675 int error=0;
2676
Kashyap, Desai2f187862009-05-29 16:52:37 +05302677 hdr.PageVersion = MPI_SASEXPANDER1_PAGEVERSION;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002678 hdr.ExtPageLength = 0;
2679 hdr.PageNumber = 1;
2680 hdr.Reserved1 = 0;
2681 hdr.Reserved2 = 0;
2682 hdr.PageType = MPI_CONFIG_PAGETYPE_EXTENDED;
2683 hdr.ExtPageType = MPI_CONFIG_EXTPAGETYPE_SAS_EXPANDER;
2684
2685 cfg.cfghdr.ehdr = &hdr;
2686 cfg.physAddr = -1;
2687 cfg.pageAddr = form + form_specific;
2688 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
2689 cfg.dir = 0; /* read */
Kashyap, Desai4b976502009-08-05 12:52:03 +05302690 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002691
2692 error = mpt_config(ioc, &cfg);
2693 if (error)
2694 goto out;
2695
2696 if (!hdr.ExtPageLength) {
2697 error = -ENXIO;
2698 goto out;
2699 }
2700
2701 buffer = pci_alloc_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2702 &dma_handle);
2703 if (!buffer) {
2704 error = -ENOMEM;
2705 goto out;
2706 }
2707
2708 cfg.physAddr = dma_handle;
2709 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
2710
2711 error = mpt_config(ioc, &cfg);
Kashyap, Desai2f187862009-05-29 16:52:37 +05302712
2713 if (error == MPI_IOCSTATUS_CONFIG_INVALID_PAGE) {
2714 error = -ENODEV;
Kashyap, Desai0cf0f232010-03-18 19:24:57 +05302715 goto out_free_consistent;
Kashyap, Desai2f187862009-05-29 16:52:37 +05302716 }
2717
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002718 if (error)
2719 goto out_free_consistent;
2720
2721
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05302722 mptsas_print_expander_pg1(ioc, buffer);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002723
2724 /* save config data */
Eric Moore024358e2005-10-21 20:56:36 +02002725 phy_info->phy_id = buffer->PhyIdentifier;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002726 phy_info->port_id = buffer->PhysicalPort;
2727 phy_info->negotiated_link_rate = buffer->NegotiatedLinkRate;
2728 phy_info->programmed_link_rate = buffer->ProgrammedLinkRate;
2729 phy_info->hw_link_rate = buffer->HwLinkRate;
2730 phy_info->identify.handle = le16_to_cpu(buffer->OwnerDevHandle);
2731 phy_info->attached.handle = le16_to_cpu(buffer->AttachedDevHandle);
2732
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002733 out_free_consistent:
2734 pci_free_consistent(ioc->pcidev, hdr.ExtPageLength * 4,
2735 buffer, dma_handle);
2736 out:
2737 return error;
2738}
2739
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302740struct rep_manu_request{
2741 u8 smp_frame_type;
2742 u8 function;
2743 u8 reserved;
2744 u8 request_length;
2745};
2746
2747struct rep_manu_reply{
2748 u8 smp_frame_type; /* 0x41 */
2749 u8 function; /* 0x01 */
2750 u8 function_result;
2751 u8 response_length;
2752 u16 expander_change_count;
2753 u8 reserved0[2];
2754 u8 sas_format:1;
2755 u8 reserved1:7;
2756 u8 reserved2[3];
2757 u8 vendor_id[SAS_EXPANDER_VENDOR_ID_LEN];
2758 u8 product_id[SAS_EXPANDER_PRODUCT_ID_LEN];
2759 u8 product_rev[SAS_EXPANDER_PRODUCT_REV_LEN];
2760 u8 component_vendor_id[SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN];
2761 u16 component_id;
2762 u8 component_revision_id;
2763 u8 reserved3;
2764 u8 vendor_specific[8];
2765};
2766
2767/**
2768 * mptsas_exp_repmanufacture_info -
2769 * @ioc: per adapter object
2770 * @sas_address: expander sas address
2771 * @edev: the sas_expander_device object
2772 *
2773 * Fills in the sas_expander_device object when SMP port is created.
2774 *
2775 * Returns 0 for success, non-zero for failure.
2776 */
2777static int
2778mptsas_exp_repmanufacture_info(MPT_ADAPTER *ioc,
2779 u64 sas_address, struct sas_expander_device *edev)
2780{
2781 MPT_FRAME_HDR *mf;
2782 SmpPassthroughRequest_t *smpreq;
2783 SmpPassthroughReply_t *smprep;
2784 struct rep_manu_reply *manufacture_reply;
2785 struct rep_manu_request *manufacture_request;
2786 int ret;
2787 int flagsLength;
2788 unsigned long timeleft;
2789 char *psge;
2790 unsigned long flags;
2791 void *data_out = NULL;
2792 dma_addr_t data_out_dma = 0;
2793 u32 sz;
2794
2795 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
2796 if (ioc->ioc_reset_in_progress) {
2797 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2798 printk(MYIOC_s_INFO_FMT "%s: host reset in progress!\n",
2799 __func__, ioc->name);
2800 return -EFAULT;
2801 }
2802 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
2803
2804 ret = mutex_lock_interruptible(&ioc->sas_mgmt.mutex);
2805 if (ret)
2806 goto out;
2807
2808 mf = mpt_get_msg_frame(mptsasMgmtCtx, ioc);
2809 if (!mf) {
2810 ret = -ENOMEM;
2811 goto out_unlock;
2812 }
2813
2814 smpreq = (SmpPassthroughRequest_t *)mf;
2815 memset(smpreq, 0, sizeof(*smpreq));
2816
2817 sz = sizeof(struct rep_manu_request) + sizeof(struct rep_manu_reply);
2818
2819 data_out = pci_alloc_consistent(ioc->pcidev, sz, &data_out_dma);
2820 if (!data_out) {
2821 printk(KERN_ERR "Memory allocation failure at %s:%d/%s()!\n",
2822 __FILE__, __LINE__, __func__);
2823 ret = -ENOMEM;
2824 goto put_mf;
2825 }
2826
2827 manufacture_request = data_out;
2828 manufacture_request->smp_frame_type = 0x40;
2829 manufacture_request->function = 1;
2830 manufacture_request->reserved = 0;
2831 manufacture_request->request_length = 0;
2832
2833 smpreq->Function = MPI_FUNCTION_SMP_PASSTHROUGH;
2834 smpreq->PhysicalPort = 0xFF;
2835 *((u64 *)&smpreq->SASAddress) = cpu_to_le64(sas_address);
2836 smpreq->RequestDataLength = sizeof(struct rep_manu_request);
2837
2838 psge = (char *)
2839 (((int *) mf) + (offsetof(SmpPassthroughRequest_t, SGL) / 4));
2840
2841 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2842 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2843 MPI_SGE_FLAGS_HOST_TO_IOC |
2844 MPI_SGE_FLAGS_END_OF_BUFFER;
2845 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2846 flagsLength |= sizeof(struct rep_manu_request);
2847
2848 ioc->add_sge(psge, flagsLength, data_out_dma);
2849 psge += ioc->SGE_size;
2850
2851 flagsLength = MPI_SGE_FLAGS_SIMPLE_ELEMENT |
2852 MPI_SGE_FLAGS_SYSTEM_ADDRESS |
2853 MPI_SGE_FLAGS_IOC_TO_HOST |
2854 MPI_SGE_FLAGS_END_OF_BUFFER;
2855 flagsLength = flagsLength << MPI_SGE_FLAGS_SHIFT;
2856 flagsLength |= sizeof(struct rep_manu_reply);
2857 ioc->add_sge(psge, flagsLength, data_out_dma +
2858 sizeof(struct rep_manu_request));
2859
2860 INITIALIZE_MGMT_STATUS(ioc->sas_mgmt.status)
2861 mpt_put_msg_frame(mptsasMgmtCtx, ioc, mf);
2862
2863 timeleft = wait_for_completion_timeout(&ioc->sas_mgmt.done, 10 * HZ);
2864 if (!(ioc->sas_mgmt.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
2865 ret = -ETIME;
2866 mpt_free_msg_frame(ioc, mf);
2867 mf = NULL;
2868 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_DID_IOCRESET)
2869 goto out_free;
2870 if (!timeleft)
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05302871 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05302872 goto out_free;
2873 }
2874
2875 mf = NULL;
2876
2877 if (ioc->sas_mgmt.status & MPT_MGMT_STATUS_RF_VALID) {
2878 u8 *tmp;
2879
2880 smprep = (SmpPassthroughReply_t *)ioc->sas_mgmt.reply;
2881 if (le16_to_cpu(smprep->ResponseDataLength) !=
2882 sizeof(struct rep_manu_reply))
2883 goto out_free;
2884
2885 manufacture_reply = data_out + sizeof(struct rep_manu_request);
2886 strncpy(edev->vendor_id, manufacture_reply->vendor_id,
2887 SAS_EXPANDER_VENDOR_ID_LEN);
2888 strncpy(edev->product_id, manufacture_reply->product_id,
2889 SAS_EXPANDER_PRODUCT_ID_LEN);
2890 strncpy(edev->product_rev, manufacture_reply->product_rev,
2891 SAS_EXPANDER_PRODUCT_REV_LEN);
2892 edev->level = manufacture_reply->sas_format;
2893 if (manufacture_reply->sas_format) {
2894 strncpy(edev->component_vendor_id,
2895 manufacture_reply->component_vendor_id,
2896 SAS_EXPANDER_COMPONENT_VENDOR_ID_LEN);
2897 tmp = (u8 *)&manufacture_reply->component_id;
2898 edev->component_id = tmp[0] << 8 | tmp[1];
2899 edev->component_revision_id =
2900 manufacture_reply->component_revision_id;
2901 }
2902 } else {
2903 printk(MYIOC_s_ERR_FMT
2904 "%s: smp passthru reply failed to be returned\n",
2905 ioc->name, __func__);
2906 ret = -ENXIO;
2907 }
2908out_free:
2909 if (data_out_dma)
2910 pci_free_consistent(ioc->pcidev, sz, data_out, data_out_dma);
2911put_mf:
2912 if (mf)
2913 mpt_free_msg_frame(ioc, mf);
2914out_unlock:
2915 CLEAR_MGMT_STATUS(ioc->sas_mgmt.status)
2916 mutex_unlock(&ioc->sas_mgmt.mutex);
2917out:
2918 return ret;
2919 }
2920
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002921static void
2922mptsas_parse_device_info(struct sas_identify *identify,
2923 struct mptsas_devinfo *device_info)
2924{
2925 u16 protocols;
2926
2927 identify->sas_address = device_info->sas_address;
2928 identify->phy_identifier = device_info->phy_id;
2929
2930 /*
2931 * Fill in Phy Initiator Port Protocol.
2932 * Bits 6:3, more than one bit can be set, fall through cases.
2933 */
2934 protocols = device_info->device_info & 0x78;
2935 identify->initiator_port_protocols = 0;
2936 if (protocols & MPI_SAS_DEVICE_INFO_SSP_INITIATOR)
2937 identify->initiator_port_protocols |= SAS_PROTOCOL_SSP;
2938 if (protocols & MPI_SAS_DEVICE_INFO_STP_INITIATOR)
2939 identify->initiator_port_protocols |= SAS_PROTOCOL_STP;
2940 if (protocols & MPI_SAS_DEVICE_INFO_SMP_INITIATOR)
2941 identify->initiator_port_protocols |= SAS_PROTOCOL_SMP;
2942 if (protocols & MPI_SAS_DEVICE_INFO_SATA_HOST)
2943 identify->initiator_port_protocols |= SAS_PROTOCOL_SATA;
2944
2945 /*
2946 * Fill in Phy Target Port Protocol.
2947 * Bits 10:7, more than one bit can be set, fall through cases.
2948 */
2949 protocols = device_info->device_info & 0x780;
2950 identify->target_port_protocols = 0;
2951 if (protocols & MPI_SAS_DEVICE_INFO_SSP_TARGET)
2952 identify->target_port_protocols |= SAS_PROTOCOL_SSP;
2953 if (protocols & MPI_SAS_DEVICE_INFO_STP_TARGET)
2954 identify->target_port_protocols |= SAS_PROTOCOL_STP;
2955 if (protocols & MPI_SAS_DEVICE_INFO_SMP_TARGET)
2956 identify->target_port_protocols |= SAS_PROTOCOL_SMP;
2957 if (protocols & MPI_SAS_DEVICE_INFO_SATA_DEVICE)
2958 identify->target_port_protocols |= SAS_PROTOCOL_SATA;
2959
2960 /*
2961 * Fill in Attached device type.
2962 */
2963 switch (device_info->device_info &
2964 MPI_SAS_DEVICE_INFO_MASK_DEVICE_TYPE) {
2965 case MPI_SAS_DEVICE_INFO_NO_DEVICE:
2966 identify->device_type = SAS_PHY_UNUSED;
2967 break;
2968 case MPI_SAS_DEVICE_INFO_END_DEVICE:
2969 identify->device_type = SAS_END_DEVICE;
2970 break;
2971 case MPI_SAS_DEVICE_INFO_EDGE_EXPANDER:
2972 identify->device_type = SAS_EDGE_EXPANDER_DEVICE;
2973 break;
2974 case MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER:
2975 identify->device_type = SAS_FANOUT_EXPANDER_DEVICE;
2976 break;
2977 }
2978}
2979
2980static int mptsas_probe_one_phy(struct device *dev,
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02002981 struct mptsas_phyinfo *phy_info, int index, int local)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002982{
Moore, Erice6b2d762006-03-14 09:14:24 -07002983 MPT_ADAPTER *ioc;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01002984 struct sas_phy *phy;
Eric Moore547f9a22006-06-27 14:42:12 -06002985 struct sas_port *port;
2986 int error = 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02002987
Eric Moore547f9a22006-06-27 14:42:12 -06002988 if (!dev) {
2989 error = -ENODEV;
2990 goto out;
2991 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002992
2993 if (!phy_info->phy) {
2994 phy = sas_phy_alloc(dev, index);
Eric Moore547f9a22006-06-27 14:42:12 -06002995 if (!phy) {
2996 error = -ENOMEM;
2997 goto out;
2998 }
Moore, Erice6b2d762006-03-14 09:14:24 -07002999 } else
3000 phy = phy_info->phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003001
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003002 mptsas_parse_device_info(&phy->identify, &phy_info->identify);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003003
3004 /*
3005 * Set Negotiated link rate.
3006 */
3007 switch (phy_info->negotiated_link_rate) {
3008 case MPI_SAS_IOUNIT0_RATE_PHY_DISABLED:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003009 phy->negotiated_linkrate = SAS_PHY_DISABLED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003010 break;
3011 case MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003012 phy->negotiated_linkrate = SAS_LINK_RATE_FAILED;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003013 break;
3014 case MPI_SAS_IOUNIT0_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003015 phy->negotiated_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003016 break;
3017 case MPI_SAS_IOUNIT0_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003018 phy->negotiated_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003019 break;
3020 case MPI_SAS_IOUNIT0_RATE_SATA_OOB_COMPLETE:
3021 case MPI_SAS_IOUNIT0_RATE_UNKNOWN:
3022 default:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003023 phy->negotiated_linkrate = SAS_LINK_RATE_UNKNOWN;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003024 break;
3025 }
3026
3027 /*
3028 * Set Max hardware link rate.
3029 */
3030 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3031 case MPI_SAS_PHY0_HWRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003032 phy->maximum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003033 break;
3034 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003035 phy->maximum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003036 break;
3037 default:
3038 break;
3039 }
3040
3041 /*
3042 * Set Max programmed link rate.
3043 */
3044 switch (phy_info->programmed_link_rate &
3045 MPI_SAS_PHY0_PRATE_MAX_RATE_MASK) {
3046 case MPI_SAS_PHY0_PRATE_MAX_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003047 phy->maximum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003048 break;
3049 case MPI_SAS_PHY0_PRATE_MAX_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003050 phy->maximum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003051 break;
3052 default:
3053 break;
3054 }
3055
3056 /*
3057 * Set Min hardware link rate.
3058 */
3059 switch (phy_info->hw_link_rate & MPI_SAS_PHY0_HWRATE_MIN_RATE_MASK) {
3060 case MPI_SAS_PHY0_HWRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003061 phy->minimum_linkrate_hw = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003062 break;
3063 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003064 phy->minimum_linkrate_hw = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003065 break;
3066 default:
3067 break;
3068 }
3069
3070 /*
3071 * Set Min programmed link rate.
3072 */
3073 switch (phy_info->programmed_link_rate &
3074 MPI_SAS_PHY0_PRATE_MIN_RATE_MASK) {
3075 case MPI_SAS_PHY0_PRATE_MIN_RATE_1_5:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003076 phy->minimum_linkrate = SAS_LINK_RATE_1_5_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003077 break;
3078 case MPI_SAS_PHY0_PRATE_MIN_RATE_3_0:
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003079 phy->minimum_linkrate = SAS_LINK_RATE_3_0_GBPS;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003080 break;
3081 default:
3082 break;
3083 }
3084
Moore, Erice6b2d762006-03-14 09:14:24 -07003085 if (!phy_info->phy) {
Christoph Hellwigac01bbb2005-10-19 20:01:17 +02003086
Moore, Erice6b2d762006-03-14 09:14:24 -07003087 error = sas_phy_add(phy);
3088 if (error) {
3089 sas_phy_free(phy);
Eric Moore547f9a22006-06-27 14:42:12 -06003090 goto out;
Moore, Erice6b2d762006-03-14 09:14:24 -07003091 }
3092 phy_info->phy = phy;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003093 }
3094
Eric Moore547f9a22006-06-27 14:42:12 -06003095 if (!phy_info->attached.handle ||
3096 !phy_info->port_details)
3097 goto out;
3098
3099 port = mptsas_get_port(phy_info);
3100 ioc = phy_to_ioc(phy_info->phy);
3101
3102 if (phy_info->sas_port_add_phy) {
3103
3104 if (!port) {
Eric Mooredc22f162006-07-06 11:23:14 -06003105 port = sas_port_alloc_num(dev);
Eric Moore547f9a22006-06-27 14:42:12 -06003106 if (!port) {
3107 error = -ENOMEM;
3108 goto out;
3109 }
3110 error = sas_port_add(port);
3111 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303112 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003113 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003114 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003115 goto out;
3116 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303117 mptsas_set_port(ioc, phy_info, port);
Kashyap, Desai2f187862009-05-29 16:52:37 +05303118 devtprintk(ioc, dev_printk(KERN_DEBUG, &port->dev,
3119 MYIOC_s_FMT "add port %d, sas_addr (0x%llx)\n",
3120 ioc->name, port->port_identifier,
3121 (unsigned long long)phy_info->
3122 attached.sas_address));
Eric Moore547f9a22006-06-27 14:42:12 -06003123 }
Kashyap, Desai2f187862009-05-29 16:52:37 +05303124 dsaswideprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3125 "sas_port_add_phy: phy_id=%d\n",
3126 ioc->name, phy_info->phy_id));
Eric Moore547f9a22006-06-27 14:42:12 -06003127 sas_port_add_phy(port, phy_info->phy);
3128 phy_info->sas_port_add_phy = 0;
Kashyap, Desai2f187862009-05-29 16:52:37 +05303129 devtprintk(ioc, dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3130 MYIOC_s_FMT "add phy %d, phy-obj (0x%p)\n", ioc->name,
3131 phy_info->phy_id, phy_info->phy));
Eric Moore547f9a22006-06-27 14:42:12 -06003132 }
Eric Moore547f9a22006-06-27 14:42:12 -06003133 if (!mptsas_get_rphy(phy_info) && port && !port->rphy) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003134
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003135 struct sas_rphy *rphy;
James Bottomley2686de22006-06-30 12:54:02 -05003136 struct device *parent;
James Bottomleyf013db32006-03-18 14:54:36 -06003137 struct sas_identify identify;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003138
James Bottomley2686de22006-06-30 12:54:02 -05003139 parent = dev->parent->parent;
Moore, Erice6b2d762006-03-14 09:14:24 -07003140 /*
3141 * Let the hotplug_work thread handle processing
3142 * the adding/removing of devices that occur
3143 * after start of day.
3144 */
Kashyap, Desai2f187862009-05-29 16:52:37 +05303145 if (mptsas_is_end_device(&phy_info->attached) &&
3146 phy_info->attached.handle_parent) {
3147 goto out;
3148 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003149
James Bottomleyf013db32006-03-18 14:54:36 -06003150 mptsas_parse_device_info(&identify, &phy_info->attached);
James Bottomley2686de22006-06-30 12:54:02 -05003151 if (scsi_is_host_device(parent)) {
3152 struct mptsas_portinfo *port_info;
3153 int i;
3154
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303155 port_info = ioc->hba_port_info;
James Bottomley2686de22006-06-30 12:54:02 -05003156
3157 for (i = 0; i < port_info->num_phys; i++)
3158 if (port_info->phy_info[i].identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003159 identify.sas_address) {
3160 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003161 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003162 }
James Bottomley2686de22006-06-30 12:54:02 -05003163
3164 } else if (scsi_is_sas_rphy(parent)) {
3165 struct sas_rphy *parent_rphy = dev_to_rphy(parent);
3166 if (identify.sas_address ==
James Bottomley0c269e62006-07-12 09:51:04 -04003167 parent_rphy->identify.sas_address) {
3168 sas_port_mark_backlink(port);
James Bottomley2686de22006-06-30 12:54:02 -05003169 goto out;
James Bottomley0c269e62006-07-12 09:51:04 -04003170 }
James Bottomley2686de22006-06-30 12:54:02 -05003171 }
3172
James Bottomleyf013db32006-03-18 14:54:36 -06003173 switch (identify.device_type) {
3174 case SAS_END_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003175 rphy = sas_end_device_alloc(port);
James Bottomleyf013db32006-03-18 14:54:36 -06003176 break;
3177 case SAS_EDGE_EXPANDER_DEVICE:
3178 case SAS_FANOUT_EXPANDER_DEVICE:
Eric Moore547f9a22006-06-27 14:42:12 -06003179 rphy = sas_expander_alloc(port, identify.device_type);
James Bottomleyf013db32006-03-18 14:54:36 -06003180 break;
3181 default:
3182 rphy = NULL;
3183 break;
3184 }
Eric Moore547f9a22006-06-27 14:42:12 -06003185 if (!rphy) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303186 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003187 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003188 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003189 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003190 }
3191
Eric Moore547f9a22006-06-27 14:42:12 -06003192 rphy->identify = identify;
3193 error = sas_rphy_add(rphy);
3194 if (error) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303195 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Eric Moore547f9a22006-06-27 14:42:12 -06003196 "%s: exit at line=%d\n", ioc->name,
Harvey Harrisoncadbd4a2008-07-03 23:47:27 -07003197 __func__, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06003198 sas_rphy_free(rphy);
3199 goto out;
3200 }
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05303201 mptsas_set_rphy(ioc, phy_info, rphy);
Kashyap, Desaie0f553a2009-12-16 19:01:58 +05303202 if (identify.device_type == SAS_EDGE_EXPANDER_DEVICE ||
3203 identify.device_type == SAS_FANOUT_EXPANDER_DEVICE)
3204 mptsas_exp_repmanufacture_info(ioc,
3205 identify.sas_address,
3206 rphy_to_expander_device(rphy));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003207 }
3208
Eric Moore547f9a22006-06-27 14:42:12 -06003209 out:
3210 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003211}
3212
3213static int
Moore, Erice6b2d762006-03-14 09:14:24 -07003214mptsas_probe_hba_phys(MPT_ADAPTER *ioc)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003215{
Moore, Erice6b2d762006-03-14 09:14:24 -07003216 struct mptsas_portinfo *port_info, *hba;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003217 int error = -ENOMEM, i;
3218
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303219 hba = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
Moore, Erice6b2d762006-03-14 09:14:24 -07003220 if (! hba)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003221 goto out;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003222
Moore, Erice6b2d762006-03-14 09:14:24 -07003223 error = mptsas_sas_io_unit_pg0(ioc, hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003224 if (error)
3225 goto out_free_port_info;
3226
Prakash, Sathyaedb90682007-07-17 14:39:14 +05303227 mptsas_sas_io_unit_pg1(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003228 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303229 port_info = ioc->hba_port_info;
Moore, Erice6b2d762006-03-14 09:14:24 -07003230 if (!port_info) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303231 ioc->hba_port_info = port_info = hba;
3232 ioc->hba_port_num_phy = port_info->num_phys;
Moore, Erice6b2d762006-03-14 09:14:24 -07003233 list_add_tail(&port_info->list, &ioc->sas_topology);
3234 } else {
Eric Moore2ecce492007-01-29 09:47:08 -07003235 for (i = 0; i < hba->num_phys; i++) {
Moore, Erice6b2d762006-03-14 09:14:24 -07003236 port_info->phy_info[i].negotiated_link_rate =
3237 hba->phy_info[i].negotiated_link_rate;
Eric Moore2ecce492007-01-29 09:47:08 -07003238 port_info->phy_info[i].handle =
3239 hba->phy_info[i].handle;
3240 port_info->phy_info[i].port_id =
3241 hba->phy_info[i].port_id;
3242 }
Eric Moore547f9a22006-06-27 14:42:12 -06003243 kfree(hba->phy_info);
Moore, Erice6b2d762006-03-14 09:14:24 -07003244 kfree(hba);
3245 hba = NULL;
3246 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01003247 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303248#if defined(CPQ_CIM)
3249 ioc->num_ports = port_info->num_phys;
3250#endif
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003251 for (i = 0; i < port_info->num_phys; i++) {
3252 mptsas_sas_phy_pg0(ioc, &port_info->phy_info[i],
3253 (MPI_SAS_PHY_PGAD_FORM_PHY_NUMBER <<
3254 MPI_SAS_PHY_PGAD_FORM_SHIFT), i);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303255 port_info->phy_info[i].identify.handle =
3256 port_info->phy_info[i].handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003257 mptsas_sas_device_pg0(ioc, &port_info->phy_info[i].identify,
Eric Moore2ecce492007-01-29 09:47:08 -07003258 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3259 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303260 port_info->phy_info[i].identify.handle);
3261 if (!ioc->hba_port_sas_addr)
3262 ioc->hba_port_sas_addr =
3263 port_info->phy_info[i].identify.sas_address;
Eric Moore024358e2005-10-21 20:56:36 +02003264 port_info->phy_info[i].identify.phy_id =
Eric Moore2ecce492007-01-29 09:47:08 -07003265 port_info->phy_info[i].phy_id = i;
Eric Moore547f9a22006-06-27 14:42:12 -06003266 if (port_info->phy_info[i].attached.handle)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003267 mptsas_sas_device_pg0(ioc,
3268 &port_info->phy_info[i].attached,
3269 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3270 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3271 port_info->phy_info[i].attached.handle);
Eric Moore547f9a22006-06-27 14:42:12 -06003272 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003273
Eric Moore547f9a22006-06-27 14:42:12 -06003274 mptsas_setup_wide_ports(ioc, port_info);
3275
3276 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003277 mptsas_probe_one_phy(&ioc->sh->shost_gendev,
Moore, Erice6b2d762006-03-14 09:14:24 -07003278 &port_info->phy_info[i], ioc->sas_index, 1);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003279
3280 return 0;
3281
3282 out_free_port_info:
Eric Moore547f9a22006-06-27 14:42:12 -06003283 kfree(hba);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003284 out:
3285 return error;
3286}
3287
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303288static void
3289mptsas_expander_refresh(MPT_ADAPTER *ioc, struct mptsas_portinfo *port_info)
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003290{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303291 struct mptsas_portinfo *parent;
3292 struct device *parent_dev;
3293 struct sas_rphy *rphy;
3294 int i;
3295 u64 sas_address; /* expander sas address */
3296 u32 handle;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003297
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303298 handle = port_info->phy_info[0].handle;
3299 sas_address = port_info->phy_info[0].identify.sas_address;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003300 for (i = 0; i < port_info->num_phys; i++) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003301 mptsas_sas_expander_pg1(ioc, &port_info->phy_info[i],
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303302 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE_PHY_NUM <<
3303 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), (i << 16) + handle);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003304
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303305 mptsas_sas_device_pg0(ioc,
3306 &port_info->phy_info[i].identify,
3307 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3308 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3309 port_info->phy_info[i].identify.handle);
3310 port_info->phy_info[i].identify.phy_id =
3311 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003312
3313 if (port_info->phy_info[i].attached.handle) {
3314 mptsas_sas_device_pg0(ioc,
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303315 &port_info->phy_info[i].attached,
3316 (MPI_SAS_DEVICE_PGAD_FORM_HANDLE <<
3317 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3318 port_info->phy_info[i].attached.handle);
Moore, Ericdb9c9172006-03-14 09:14:18 -07003319 port_info->phy_info[i].attached.phy_id =
3320 port_info->phy_info[i].phy_id;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003321 }
Eric Moore547f9a22006-06-27 14:42:12 -06003322 }
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003323
Moore, Erice6b2d762006-03-14 09:14:24 -07003324 mutex_lock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303325 parent = mptsas_find_portinfo_by_handle(ioc,
3326 port_info->phy_info[0].identify.handle_parent);
3327 if (!parent) {
3328 mutex_unlock(&ioc->sas_topology_mutex);
3329 return;
3330 }
3331 for (i = 0, parent_dev = NULL; i < parent->num_phys && !parent_dev;
3332 i++) {
3333 if (parent->phy_info[i].attached.sas_address == sas_address) {
3334 rphy = mptsas_get_rphy(&parent->phy_info[i]);
3335 parent_dev = &rphy->dev;
Moore, Erice6b2d762006-03-14 09:14:24 -07003336 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003337 }
3338 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303339
3340 mptsas_setup_wide_ports(ioc, port_info);
3341 for (i = 0; i < port_info->num_phys; i++, ioc->sas_index++)
3342 mptsas_probe_one_phy(parent_dev, &port_info->phy_info[i],
3343 ioc->sas_index, 0);
3344}
3345
3346static void
3347mptsas_expander_event_add(MPT_ADAPTER *ioc,
3348 MpiEventDataSasExpanderStatusChange_t *expander_data)
3349{
3350 struct mptsas_portinfo *port_info;
3351 int i;
3352 __le64 sas_address;
3353
3354 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3355 if (!port_info)
3356 BUG();
3357 port_info->num_phys = (expander_data->NumPhys) ?
3358 expander_data->NumPhys : 1;
3359 port_info->phy_info = kcalloc(port_info->num_phys,
3360 sizeof(struct mptsas_phyinfo), GFP_KERNEL);
3361 if (!port_info->phy_info)
3362 BUG();
3363 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
3364 for (i = 0; i < port_info->num_phys; i++) {
3365 port_info->phy_info[i].portinfo = port_info;
3366 port_info->phy_info[i].handle =
3367 le16_to_cpu(expander_data->DevHandle);
3368 port_info->phy_info[i].identify.sas_address =
3369 le64_to_cpu(sas_address);
3370 port_info->phy_info[i].identify.handle_parent =
3371 le16_to_cpu(expander_data->ParentDevHandle);
3372 }
3373
3374 mutex_lock(&ioc->sas_topology_mutex);
3375 list_add_tail(&port_info->list, &ioc->sas_topology);
3376 mutex_unlock(&ioc->sas_topology_mutex);
3377
3378 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3379 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3380 (unsigned long long)sas_address);
3381
3382 mptsas_expander_refresh(ioc, port_info);
3383}
3384
3385/**
3386 * mptsas_delete_expander_siblings - remove siblings attached to expander
3387 * @ioc: Pointer to MPT_ADAPTER structure
3388 * @parent: the parent port_info object
3389 * @expander: the expander port_info object
3390 **/
3391static void
3392mptsas_delete_expander_siblings(MPT_ADAPTER *ioc, struct mptsas_portinfo
3393 *parent, struct mptsas_portinfo *expander)
3394{
3395 struct mptsas_phyinfo *phy_info;
3396 struct mptsas_portinfo *port_info;
3397 struct sas_rphy *rphy;
3398 int i;
3399
3400 phy_info = expander->phy_info;
3401 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3402 rphy = mptsas_get_rphy(phy_info);
3403 if (!rphy)
3404 continue;
3405 if (rphy->identify.device_type == SAS_END_DEVICE)
3406 mptsas_del_end_device(ioc, phy_info);
3407 }
3408
3409 phy_info = expander->phy_info;
3410 for (i = 0; i < expander->num_phys; i++, phy_info++) {
3411 rphy = mptsas_get_rphy(phy_info);
3412 if (!rphy)
3413 continue;
3414 if (rphy->identify.device_type ==
3415 MPI_SAS_DEVICE_INFO_EDGE_EXPANDER ||
3416 rphy->identify.device_type ==
3417 MPI_SAS_DEVICE_INFO_FANOUT_EXPANDER) {
3418 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3419 rphy->identify.sas_address);
3420 if (!port_info)
3421 continue;
3422 if (port_info == parent) /* backlink rphy */
3423 continue;
3424 /*
3425 Delete this expander even if the expdevpage is exists
3426 because the parent expander is already deleted
3427 */
3428 mptsas_expander_delete(ioc, port_info, 1);
3429 }
3430 }
3431}
3432
3433
3434/**
3435 * mptsas_expander_delete - remove this expander
3436 * @ioc: Pointer to MPT_ADAPTER structure
3437 * @port_info: expander port_info struct
3438 * @force: Flag to forcefully delete the expander
3439 *
3440 **/
3441
3442static void mptsas_expander_delete(MPT_ADAPTER *ioc,
3443 struct mptsas_portinfo *port_info, u8 force)
3444{
3445
3446 struct mptsas_portinfo *parent;
3447 int i;
3448 u64 expander_sas_address;
3449 struct mptsas_phyinfo *phy_info;
3450 struct mptsas_portinfo buffer;
3451 struct mptsas_portinfo_details *port_details;
3452 struct sas_port *port;
3453
3454 if (!port_info)
3455 return;
3456
3457 /* see if expander is still there before deleting */
3458 mptsas_sas_expander_pg0(ioc, &buffer,
3459 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3460 MPI_SAS_EXPAND_PGAD_FORM_SHIFT),
3461 port_info->phy_info[0].identify.handle);
3462
3463 if (buffer.num_phys) {
3464 kfree(buffer.phy_info);
3465 if (!force)
3466 return;
3467 }
3468
3469
3470 /*
3471 * Obtain the port_info instance to the parent port
3472 */
3473 port_details = NULL;
3474 expander_sas_address =
3475 port_info->phy_info[0].identify.sas_address;
3476 parent = mptsas_find_portinfo_by_handle(ioc,
3477 port_info->phy_info[0].identify.handle_parent);
3478 mptsas_delete_expander_siblings(ioc, parent, port_info);
3479 if (!parent)
3480 goto out;
3481
3482 /*
3483 * Delete rphys in the parent that point
3484 * to this expander.
3485 */
3486 phy_info = parent->phy_info;
3487 port = NULL;
3488 for (i = 0; i < parent->num_phys; i++, phy_info++) {
3489 if (!phy_info->phy)
3490 continue;
3491 if (phy_info->attached.sas_address !=
3492 expander_sas_address)
3493 continue;
3494 if (!port) {
3495 port = mptsas_get_port(phy_info);
3496 port_details = phy_info->port_details;
3497 }
3498 dev_printk(KERN_DEBUG, &phy_info->phy->dev,
3499 MYIOC_s_FMT "delete phy %d, phy-obj (0x%p)\n", ioc->name,
3500 phy_info->phy_id, phy_info->phy);
3501 sas_port_delete_phy(port, phy_info->phy);
3502 }
3503 if (port) {
3504 dev_printk(KERN_DEBUG, &port->dev,
3505 MYIOC_s_FMT "delete port %d, sas_addr (0x%llx)\n",
3506 ioc->name, port->port_identifier,
3507 (unsigned long long)expander_sas_address);
3508 sas_port_delete(port);
3509 mptsas_port_delete(ioc, port_details);
3510 }
3511 out:
3512
3513 printk(MYIOC_s_INFO_FMT "delete expander: num_phys %d, "
3514 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3515 (unsigned long long)expander_sas_address);
3516
3517 /*
3518 * free link
3519 */
3520 list_del(&port_info->list);
3521 kfree(port_info->phy_info);
3522 kfree(port_info);
3523}
3524
3525
3526/**
3527 * mptsas_send_expander_event - expanders events
3528 * @ioc: Pointer to MPT_ADAPTER structure
3529 * @expander_data: event data
3530 *
3531 *
3532 * This function handles adding, removing, and refreshing
3533 * device handles within the expander objects.
3534 */
3535static void
3536mptsas_send_expander_event(struct fw_event_work *fw_event)
3537{
3538 MPT_ADAPTER *ioc;
3539 MpiEventDataSasExpanderStatusChange_t *expander_data;
3540 struct mptsas_portinfo *port_info;
3541 __le64 sas_address;
3542 int i;
3543
3544 ioc = fw_event->ioc;
3545 expander_data = (MpiEventDataSasExpanderStatusChange_t *)
3546 fw_event->event_data;
3547 memcpy(&sas_address, &expander_data->SASAddress, sizeof(__le64));
Kashyap, Desaif44fd182009-09-02 11:44:19 +05303548 sas_address = le64_to_cpu(sas_address);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303549 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3550
3551 if (expander_data->ReasonCode == MPI_EVENT_SAS_EXP_RC_ADDED) {
3552 if (port_info) {
3553 for (i = 0; i < port_info->num_phys; i++) {
3554 port_info->phy_info[i].portinfo = port_info;
3555 port_info->phy_info[i].handle =
3556 le16_to_cpu(expander_data->DevHandle);
3557 port_info->phy_info[i].identify.sas_address =
3558 le64_to_cpu(sas_address);
3559 port_info->phy_info[i].identify.handle_parent =
3560 le16_to_cpu(expander_data->ParentDevHandle);
3561 }
3562 mptsas_expander_refresh(ioc, port_info);
3563 } else if (!port_info && expander_data->NumPhys)
3564 mptsas_expander_event_add(ioc, expander_data);
3565 } else if (expander_data->ReasonCode ==
3566 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING)
3567 mptsas_expander_delete(ioc, port_info, 0);
3568
3569 mptsas_free_fw_event(ioc, fw_event);
3570}
3571
3572
3573/**
3574 * mptsas_expander_add -
3575 * @ioc: Pointer to MPT_ADAPTER structure
3576 * @handle:
3577 *
3578 */
3579struct mptsas_portinfo *
3580mptsas_expander_add(MPT_ADAPTER *ioc, u16 handle)
3581{
3582 struct mptsas_portinfo buffer, *port_info;
3583 int i;
3584
3585 if ((mptsas_sas_expander_pg0(ioc, &buffer,
3586 (MPI_SAS_EXPAND_PGAD_FORM_HANDLE <<
3587 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)))
3588 return NULL;
3589
3590 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_ATOMIC);
3591 if (!port_info) {
3592 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3593 "%s: exit at line=%d\n", ioc->name,
3594 __func__, __LINE__));
3595 return NULL;
3596 }
3597 port_info->num_phys = buffer.num_phys;
3598 port_info->phy_info = buffer.phy_info;
3599 for (i = 0; i < port_info->num_phys; i++)
3600 port_info->phy_info[i].portinfo = port_info;
3601 mutex_lock(&ioc->sas_topology_mutex);
3602 list_add_tail(&port_info->list, &ioc->sas_topology);
3603 mutex_unlock(&ioc->sas_topology_mutex);
3604 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3605 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3606 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3607 mptsas_expander_refresh(ioc, port_info);
3608 return port_info;
3609}
3610
3611static void
3612mptsas_send_link_status_event(struct fw_event_work *fw_event)
3613{
3614 MPT_ADAPTER *ioc;
3615 MpiEventDataSasPhyLinkStatus_t *link_data;
3616 struct mptsas_portinfo *port_info;
3617 struct mptsas_phyinfo *phy_info = NULL;
3618 __le64 sas_address;
3619 u8 phy_num;
3620 u8 link_rate;
3621
3622 ioc = fw_event->ioc;
3623 link_data = (MpiEventDataSasPhyLinkStatus_t *)fw_event->event_data;
3624
3625 memcpy(&sas_address, &link_data->SASAddress, sizeof(__le64));
3626 sas_address = le64_to_cpu(sas_address);
3627 link_rate = link_data->LinkRates >> 4;
3628 phy_num = link_data->PhyNum;
3629
3630 port_info = mptsas_find_portinfo_by_sas_address(ioc, sas_address);
3631 if (port_info) {
3632 phy_info = &port_info->phy_info[phy_num];
3633 if (phy_info)
3634 phy_info->negotiated_link_rate = link_rate;
3635 }
3636
3637 if (link_rate == MPI_SAS_IOUNIT0_RATE_1_5 ||
3638 link_rate == MPI_SAS_IOUNIT0_RATE_3_0) {
3639
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303640 if (!port_info) {
3641 if (ioc->old_sas_discovery_protocal) {
3642 port_info = mptsas_expander_add(ioc,
3643 le16_to_cpu(link_data->DevHandle));
3644 if (port_info)
3645 goto out;
3646 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303647 goto out;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303648 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303649
3650 if (port_info == ioc->hba_port_info)
3651 mptsas_probe_hba_phys(ioc);
3652 else
3653 mptsas_expander_refresh(ioc, port_info);
3654 } else if (phy_info && phy_info->phy) {
3655 if (link_rate == MPI_SAS_IOUNIT0_RATE_PHY_DISABLED)
3656 phy_info->phy->negotiated_linkrate =
3657 SAS_PHY_DISABLED;
3658 else if (link_rate ==
3659 MPI_SAS_IOUNIT0_RATE_FAILED_SPEED_NEGOTIATION)
3660 phy_info->phy->negotiated_linkrate =
3661 SAS_LINK_RATE_FAILED;
3662 else
3663 phy_info->phy->negotiated_linkrate =
3664 SAS_LINK_RATE_UNKNOWN;
3665 }
3666 out:
3667 mptsas_free_fw_event(ioc, fw_event);
3668}
3669
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303670static void
3671mptsas_not_responding_devices(MPT_ADAPTER *ioc)
3672{
3673 struct mptsas_portinfo buffer, *port_info;
3674 struct mptsas_device_info *sas_info;
3675 struct mptsas_devinfo sas_device;
3676 u32 handle;
3677 VirtTarget *vtarget = NULL;
3678 struct mptsas_phyinfo *phy_info;
3679 u8 found_expander;
3680 int retval, retry_count;
3681 unsigned long flags;
3682
3683 mpt_findImVolumes(ioc);
3684
3685 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3686 if (ioc->ioc_reset_in_progress) {
3687 dfailprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3688 "%s: exiting due to a parallel reset \n", ioc->name,
3689 __func__));
3690 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3691 return;
3692 }
3693 spin_unlock_irqrestore(&ioc->taskmgmt_lock, flags);
3694
3695 /* devices, logical volumes */
3696 mutex_lock(&ioc->sas_device_info_mutex);
3697 redo_device_scan:
3698 list_for_each_entry(sas_info, &ioc->sas_device_info_list, list) {
Kashyap, Desai57e98512009-05-29 16:55:09 +05303699 if (sas_info->is_cached)
3700 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303701 if (!sas_info->is_logical_volume) {
3702 sas_device.handle = 0;
3703 retry_count = 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303704retry_page:
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303705 retval = mptsas_sas_device_pg0(ioc, &sas_device,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303706 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID
3707 << MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
3708 (sas_info->fw.channel << 8) +
3709 sas_info->fw.id);
3710
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303711 if (sas_device.handle)
3712 continue;
3713 if (retval == -EBUSY) {
3714 spin_lock_irqsave(&ioc->taskmgmt_lock, flags);
3715 if (ioc->ioc_reset_in_progress) {
3716 dfailprintk(ioc,
3717 printk(MYIOC_s_DEBUG_FMT
3718 "%s: exiting due to reset\n",
3719 ioc->name, __func__));
3720 spin_unlock_irqrestore
3721 (&ioc->taskmgmt_lock, flags);
3722 mutex_unlock(&ioc->
3723 sas_device_info_mutex);
3724 return;
3725 }
3726 spin_unlock_irqrestore(&ioc->taskmgmt_lock,
3727 flags);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303728 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303729
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303730 if (retval && (retval != -ENODEV)) {
3731 if (retry_count < 10) {
3732 retry_count++;
3733 goto retry_page;
3734 } else {
3735 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
3736 "%s: Config page retry exceeded retry "
3737 "count deleting device 0x%llx\n",
3738 ioc->name, __func__,
3739 sas_info->sas_address));
3740 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303741 }
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303742
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303743 /* delete device */
3744 vtarget = mptsas_find_vtarget(ioc,
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303745 sas_info->fw.channel, sas_info->fw.id);
Kashyap, Desaia7938b02009-05-29 16:53:56 +05303746
3747 if (vtarget)
3748 vtarget->deleted = 1;
3749
3750 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
3751 sas_info->sas_address);
3752
3753 if (phy_info) {
3754 mptsas_del_end_device(ioc, phy_info);
3755 goto redo_device_scan;
3756 }
3757 } else
3758 mptsas_volume_delete(ioc, sas_info->fw.id);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303759 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003760 mutex_unlock(&ioc->sas_device_info_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303761
3762 /* expanders */
3763 mutex_lock(&ioc->sas_topology_mutex);
3764 redo_expander_scan:
3765 list_for_each_entry(port_info, &ioc->sas_topology, list) {
3766
3767 if (port_info->phy_info &&
3768 (!(port_info->phy_info[0].identify.device_info &
3769 MPI_SAS_DEVICE_INFO_SMP_TARGET)))
3770 continue;
3771 found_expander = 0;
3772 handle = 0xFFFF;
3773 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3774 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3775 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle) &&
3776 !found_expander) {
3777
3778 handle = buffer.phy_info[0].handle;
3779 if (buffer.phy_info[0].identify.sas_address ==
3780 port_info->phy_info[0].identify.sas_address) {
3781 found_expander = 1;
3782 }
3783 kfree(buffer.phy_info);
3784 }
3785
3786 if (!found_expander) {
3787 mptsas_expander_delete(ioc, port_info, 0);
3788 goto redo_expander_scan;
3789 }
3790 }
Jiri Slaby129dd982009-06-21 23:59:01 +02003791 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05303792}
3793
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303794/**
3795 * mptsas_probe_expanders - adding expanders
3796 * @ioc: Pointer to MPT_ADAPTER structure
3797 *
3798 **/
3799static void
3800mptsas_probe_expanders(MPT_ADAPTER *ioc)
3801{
3802 struct mptsas_portinfo buffer, *port_info;
3803 u32 handle;
3804 int i;
3805
3806 handle = 0xFFFF;
3807 while (!mptsas_sas_expander_pg0(ioc, &buffer,
3808 (MPI_SAS_EXPAND_PGAD_FORM_GET_NEXT_HANDLE <<
3809 MPI_SAS_EXPAND_PGAD_FORM_SHIFT), handle)) {
3810
3811 handle = buffer.phy_info[0].handle;
3812 port_info = mptsas_find_portinfo_by_sas_address(ioc,
3813 buffer.phy_info[0].identify.sas_address);
3814
3815 if (port_info) {
3816 /* refreshing handles */
3817 for (i = 0; i < buffer.num_phys; i++) {
3818 port_info->phy_info[i].handle = handle;
3819 port_info->phy_info[i].identify.handle_parent =
3820 buffer.phy_info[0].identify.handle_parent;
3821 }
3822 mptsas_expander_refresh(ioc, port_info);
3823 kfree(buffer.phy_info);
3824 continue;
3825 }
3826
3827 port_info = kzalloc(sizeof(struct mptsas_portinfo), GFP_KERNEL);
3828 if (!port_info) {
3829 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
3830 "%s: exit at line=%d\n", ioc->name,
3831 __func__, __LINE__));
3832 return;
3833 }
3834 port_info->num_phys = buffer.num_phys;
3835 port_info->phy_info = buffer.phy_info;
3836 for (i = 0; i < port_info->num_phys; i++)
3837 port_info->phy_info[i].portinfo = port_info;
3838 mutex_lock(&ioc->sas_topology_mutex);
3839 list_add_tail(&port_info->list, &ioc->sas_topology);
3840 mutex_unlock(&ioc->sas_topology_mutex);
3841 printk(MYIOC_s_INFO_FMT "add expander: num_phys %d, "
3842 "sas_addr (0x%llx)\n", ioc->name, port_info->num_phys,
3843 (unsigned long long)buffer.phy_info[0].identify.sas_address);
3844 mptsas_expander_refresh(ioc, port_info);
3845 }
3846}
3847
3848static void
3849mptsas_probe_devices(MPT_ADAPTER *ioc)
3850{
3851 u16 handle;
3852 struct mptsas_devinfo sas_device;
3853 struct mptsas_phyinfo *phy_info;
3854
3855 handle = 0xFFFF;
3856 while (!(mptsas_sas_device_pg0(ioc, &sas_device,
3857 MPI_SAS_DEVICE_PGAD_FORM_GET_NEXT_HANDLE, handle))) {
3858
3859 handle = sas_device.handle;
3860
3861 if ((sas_device.device_info &
3862 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
3863 MPI_SAS_DEVICE_INFO_STP_TARGET |
3864 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0)
3865 continue;
3866
Kashyap, Desai51106ab2010-06-17 14:40:10 +05303867 /* If there is no FW B_T mapping for this device then continue
3868 * */
3869 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
3870 || !(sas_device.flags &
3871 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
3872 continue;
3873
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303874 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
3875 if (!phy_info)
3876 continue;
3877
3878 if (mptsas_get_rphy(phy_info))
3879 continue;
3880
3881 mptsas_add_end_device(ioc, phy_info);
3882 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003883}
3884
Kashyap, Desai2f187862009-05-29 16:52:37 +05303885/**
3886 * mptsas_scan_sas_topology -
3887 * @ioc: Pointer to MPT_ADAPTER structure
3888 * @sas_address:
3889 *
3890 **/
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003891static void
3892mptsas_scan_sas_topology(MPT_ADAPTER *ioc)
3893{
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303894 struct scsi_device *sdev;
Moore, Ericf44e5462006-03-14 09:14:21 -07003895 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02003896
Moore, Erice6b2d762006-03-14 09:14:24 -07003897 mptsas_probe_hba_phys(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303898 mptsas_probe_expanders(ioc);
3899 mptsas_probe_devices(ioc);
3900
Moore, Ericf44e5462006-03-14 09:14:21 -07003901 /*
3902 Reporting RAID volumes.
3903 */
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303904 if (!ioc->ir_firmware || !ioc->raid_data.pIocPg2 ||
3905 !ioc->raid_data.pIocPg2->NumActiveVolumes)
3906 return;
Eric Moore793955f2007-01-29 09:42:20 -07003907 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
Kashyap, Desaif9c34022009-05-29 16:49:36 +05303908 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
3909 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3910 if (sdev) {
3911 scsi_device_put(sdev);
3912 continue;
3913 }
3914 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
3915 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
3916 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID);
James Bottomleye8bf3942006-07-11 17:49:34 -04003917 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
Moore, Ericf44e5462006-03-14 09:14:21 -07003918 ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID, 0);
3919 }
Moore, Erice6b2d762006-03-14 09:14:24 -07003920}
3921
Kashyap, Desai57e98512009-05-29 16:55:09 +05303922
3923static void
3924mptsas_handle_queue_full_event(struct fw_event_work *fw_event)
3925{
3926 MPT_ADAPTER *ioc;
3927 EventDataQueueFull_t *qfull_data;
3928 struct mptsas_device_info *sas_info;
3929 struct scsi_device *sdev;
3930 int depth;
3931 int id = -1;
3932 int channel = -1;
3933 int fw_id, fw_channel;
3934 u16 current_depth;
3935
3936
3937 ioc = fw_event->ioc;
3938 qfull_data = (EventDataQueueFull_t *)fw_event->event_data;
3939 fw_id = qfull_data->TargetID;
3940 fw_channel = qfull_data->Bus;
3941 current_depth = le16_to_cpu(qfull_data->CurrentDepth);
3942
3943 /* if hidden raid component, look for the volume id */
3944 mutex_lock(&ioc->sas_device_info_mutex);
3945 if (mptscsih_is_phys_disk(ioc, fw_channel, fw_id)) {
3946 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3947 list) {
3948 if (sas_info->is_cached ||
3949 sas_info->is_logical_volume)
3950 continue;
3951 if (sas_info->is_hidden_raid_component &&
3952 (sas_info->fw.channel == fw_channel &&
3953 sas_info->fw.id == fw_id)) {
3954 id = sas_info->volume_id;
3955 channel = MPTSAS_RAID_CHANNEL;
3956 goto out;
3957 }
3958 }
3959 } else {
3960 list_for_each_entry(sas_info, &ioc->sas_device_info_list,
3961 list) {
3962 if (sas_info->is_cached ||
3963 sas_info->is_hidden_raid_component ||
3964 sas_info->is_logical_volume)
3965 continue;
3966 if (sas_info->fw.channel == fw_channel &&
3967 sas_info->fw.id == fw_id) {
3968 id = sas_info->os.id;
3969 channel = sas_info->os.channel;
3970 goto out;
3971 }
3972 }
3973
3974 }
3975
3976 out:
3977 mutex_unlock(&ioc->sas_device_info_mutex);
3978
3979 if (id != -1) {
3980 shost_for_each_device(sdev, ioc->sh) {
3981 if (sdev->id == id && sdev->channel == channel) {
3982 if (current_depth > sdev->queue_depth) {
3983 sdev_printk(KERN_INFO, sdev,
3984 "strange observation, the queue "
3985 "depth is (%d) meanwhile fw queue "
3986 "depth (%d)\n", sdev->queue_depth,
3987 current_depth);
3988 continue;
3989 }
3990 depth = scsi_track_queue_full(sdev,
3991 current_depth - 1);
3992 if (depth > 0)
3993 sdev_printk(KERN_INFO, sdev,
3994 "Queue depth reduced to (%d)\n",
3995 depth);
3996 else if (depth < 0)
3997 sdev_printk(KERN_INFO, sdev,
3998 "Tagged Command Queueing is being "
3999 "disabled\n");
4000 else if (depth == 0)
4001 sdev_printk(KERN_INFO, sdev,
4002 "Queue depth not changed yet\n");
4003 }
4004 }
4005 }
4006
4007 mptsas_free_fw_event(ioc, fw_event);
4008}
4009
4010
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004011static struct mptsas_phyinfo *
Eric Moore547f9a22006-06-27 14:42:12 -06004012mptsas_find_phyinfo_by_sas_address(MPT_ADAPTER *ioc, u64 sas_address)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004013{
4014 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004015 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06004016 int i;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004017
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004018 mutex_lock(&ioc->sas_topology_mutex);
4019 list_for_each_entry(port_info, &ioc->sas_topology, list) {
4020 for (i = 0; i < port_info->num_phys; i++) {
Eric Moore547f9a22006-06-27 14:42:12 -06004021 if (!mptsas_is_end_device(
4022 &port_info->phy_info[i].attached))
4023 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004024 if (port_info->phy_info[i].attached.sas_address
4025 != sas_address)
4026 continue;
Eric Moore547f9a22006-06-27 14:42:12 -06004027 phy_info = &port_info->phy_info[i];
4028 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004029 }
4030 }
4031 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004032 return phy_info;
4033}
4034
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304035/**
4036 * mptsas_find_phyinfo_by_phys_disk_num -
4037 * @ioc: Pointer to MPT_ADAPTER structure
4038 * @phys_disk_num:
4039 * @channel:
4040 * @id:
4041 *
4042 **/
Eric Mooreb506ade2007-01-29 09:45:37 -07004043static struct mptsas_phyinfo *
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304044mptsas_find_phyinfo_by_phys_disk_num(MPT_ADAPTER *ioc, u8 phys_disk_num,
4045 u8 channel, u8 id)
Eric Mooreb506ade2007-01-29 09:45:37 -07004046{
Eric Mooreb506ade2007-01-29 09:45:37 -07004047 struct mptsas_phyinfo *phy_info = NULL;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304048 struct mptsas_portinfo *port_info;
4049 RaidPhysDiskPage1_t *phys_disk = NULL;
4050 int num_paths;
4051 u64 sas_address = 0;
Eric Mooreb506ade2007-01-29 09:45:37 -07004052 int i;
4053
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304054 phy_info = NULL;
4055 if (!ioc->raid_data.pIocPg3)
4056 return NULL;
4057 /* dual port support */
4058 num_paths = mpt_raid_phys_disk_get_num_paths(ioc, phys_disk_num);
4059 if (!num_paths)
4060 goto out;
4061 phys_disk = kzalloc(offsetof(RaidPhysDiskPage1_t, Path) +
4062 (num_paths * sizeof(RAID_PHYS_DISK1_PATH)), GFP_KERNEL);
4063 if (!phys_disk)
4064 goto out;
4065 mpt_raid_phys_disk_pg1(ioc, phys_disk_num, phys_disk);
4066 for (i = 0; i < num_paths; i++) {
4067 if ((phys_disk->Path[i].Flags & 1) != 0)
4068 /* entry no longer valid */
4069 continue;
4070 if ((id == phys_disk->Path[i].PhysDiskID) &&
4071 (channel == phys_disk->Path[i].PhysDiskBus)) {
4072 memcpy(&sas_address, &phys_disk->Path[i].WWID,
4073 sizeof(u64));
4074 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4075 sas_address);
4076 goto out;
4077 }
4078 }
4079
4080 out:
4081 kfree(phys_disk);
4082 if (phy_info)
4083 return phy_info;
4084
4085 /*
4086 * Extra code to handle RAID0 case, where the sas_address is not updated
4087 * in phys_disk_page_1 when hotswapped
4088 */
Eric Mooreb506ade2007-01-29 09:45:37 -07004089 mutex_lock(&ioc->sas_topology_mutex);
4090 list_for_each_entry(port_info, &ioc->sas_topology, list) {
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304091 for (i = 0; i < port_info->num_phys && !phy_info; i++) {
Eric Mooreb506ade2007-01-29 09:45:37 -07004092 if (!mptsas_is_end_device(
4093 &port_info->phy_info[i].attached))
4094 continue;
4095 if (port_info->phy_info[i].attached.phys_disk_num == ~0)
4096 continue;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304097 if ((port_info->phy_info[i].attached.phys_disk_num ==
4098 phys_disk_num) &&
4099 (port_info->phy_info[i].attached.id == id) &&
4100 (port_info->phy_info[i].attached.channel ==
4101 channel))
4102 phy_info = &port_info->phy_info[i];
Eric Moore547f9a22006-06-27 14:42:12 -06004103 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004104 }
4105 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004106 return phy_info;
4107}
4108
4109static void
Moore, Ericf44e5462006-03-14 09:14:21 -07004110mptsas_reprobe_lun(struct scsi_device *sdev, void *data)
4111{
Eric Mooref99be432007-01-04 20:46:54 -07004112 int rc;
4113
Moore, Ericf44e5462006-03-14 09:14:21 -07004114 sdev->no_uld_attach = data ? 1 : 0;
Eric Mooref99be432007-01-04 20:46:54 -07004115 rc = scsi_device_reprobe(sdev);
Moore, Ericf44e5462006-03-14 09:14:21 -07004116}
4117
4118static void
4119mptsas_reprobe_target(struct scsi_target *starget, int uld_attach)
4120{
4121 starget_for_each_device(starget, uld_attach ? (void *)1 : NULL,
4122 mptsas_reprobe_lun);
4123}
4124
Eric Mooreb506ade2007-01-29 09:45:37 -07004125static void
4126mptsas_adding_inactive_raid_components(MPT_ADAPTER *ioc, u8 channel, u8 id)
4127{
4128 CONFIGPARMS cfg;
4129 ConfigPageHeader_t hdr;
4130 dma_addr_t dma_handle;
4131 pRaidVolumePage0_t buffer = NULL;
4132 RaidPhysDiskPage0_t phys_disk;
4133 int i;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304134 struct mptsas_phyinfo *phy_info;
4135 struct mptsas_devinfo sas_device;
Eric Mooreb506ade2007-01-29 09:45:37 -07004136
4137 memset(&cfg, 0 , sizeof(CONFIGPARMS));
4138 memset(&hdr, 0 , sizeof(ConfigPageHeader_t));
4139 hdr.PageType = MPI_CONFIG_PAGETYPE_RAID_VOLUME;
4140 cfg.pageAddr = (channel << 8) + id;
4141 cfg.cfghdr.hdr = &hdr;
4142 cfg.action = MPI_CONFIG_ACTION_PAGE_HEADER;
Kashyap, Desai568da762010-03-18 19:23:50 +05304143 cfg.timeout = SAS_CONFIG_PAGE_TIMEOUT;
Eric Mooreb506ade2007-01-29 09:45:37 -07004144
4145 if (mpt_config(ioc, &cfg) != 0)
4146 goto out;
4147
4148 if (!hdr.PageLength)
4149 goto out;
4150
4151 buffer = pci_alloc_consistent(ioc->pcidev, hdr.PageLength * 4,
4152 &dma_handle);
4153
4154 if (!buffer)
4155 goto out;
4156
4157 cfg.physAddr = dma_handle;
4158 cfg.action = MPI_CONFIG_ACTION_PAGE_READ_CURRENT;
4159
4160 if (mpt_config(ioc, &cfg) != 0)
4161 goto out;
4162
4163 if (!(buffer->VolumeStatus.Flags &
4164 MPI_RAIDVOL0_STATUS_FLAG_VOLUME_INACTIVE))
4165 goto out;
4166
4167 if (!buffer->NumPhysDisks)
4168 goto out;
4169
4170 for (i = 0; i < buffer->NumPhysDisks; i++) {
4171
4172 if (mpt_raid_phys_disk_pg0(ioc,
4173 buffer->PhysDisk[i].PhysDiskNum, &phys_disk) != 0)
4174 continue;
4175
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304176 if (mptsas_sas_device_pg0(ioc, &sas_device,
4177 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4178 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4179 (phys_disk.PhysDiskBus << 8) +
4180 phys_disk.PhysDiskID))
4181 continue;
Eric Mooreb506ade2007-01-29 09:45:37 -07004182
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304183 /* If there is no FW B_T mapping for this device then continue
4184 * */
4185 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4186 || !(sas_device.flags &
4187 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4188 continue;
4189
4190
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304191 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4192 sas_device.sas_address);
4193 mptsas_add_end_device(ioc, phy_info);
Eric Mooreb506ade2007-01-29 09:45:37 -07004194 }
4195
4196 out:
4197 if (buffer)
4198 pci_free_consistent(ioc->pcidev, hdr.PageLength * 4, buffer,
4199 dma_handle);
4200}
Moore, Erice6b2d762006-03-14 09:14:24 -07004201/*
4202 * Work queue thread to handle SAS hotplug events
4203 */
Moore, Ericf44e5462006-03-14 09:14:21 -07004204static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304205mptsas_hotplug_work(MPT_ADAPTER *ioc, struct fw_event_work *fw_event,
4206 struct mptsas_hotplug_event *hot_plug_info)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004207{
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004208 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004209 struct scsi_target * starget;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004210 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004211 VirtTarget *vtarget;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304212 int i;
Eric Moore547f9a22006-06-27 14:42:12 -06004213
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304214 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004215
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304216 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004217
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304218 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004219 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004220
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304221 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4222 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4223 hot_plug_info->id) {
4224 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4225 "to add hidden disk - target_id matchs "
4226 "volume_id\n", ioc->name);
4227 mptsas_free_fw_event(ioc, fw_event);
4228 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004229 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004230 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304231 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004232
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004233 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304234 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4235 mptsas_sas_device_pg0(ioc, &sas_device,
4236 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4237 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4238 (hot_plug_info->channel << 8) +
4239 hot_plug_info->id);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004240
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304241 /* If there is no FW B_T mapping for this device then break
4242 * */
4243 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4244 || !(sas_device.flags &
4245 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4246 break;
4247
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304248 if (!sas_device.handle)
4249 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004250
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304251 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
4252 if (!phy_info)
4253 break;
4254
4255 if (mptsas_get_rphy(phy_info))
4256 break;
4257
4258 mptsas_add_end_device(ioc, phy_info);
4259 break;
4260
4261 case MPTSAS_DEL_DEVICE:
4262 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4263 hot_plug_info->sas_address);
4264 mptsas_del_end_device(ioc, phy_info);
4265 break;
4266
4267 case MPTSAS_DEL_PHYSDISK:
4268
4269 mpt_findImVolumes(ioc);
4270
4271 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304272 ioc, hot_plug_info->phys_disk_num,
4273 hot_plug_info->channel,
4274 hot_plug_info->id);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304275 mptsas_del_end_device(ioc, phy_info);
4276 break;
4277
4278 case MPTSAS_ADD_PHYSDISK_REPROBE:
4279
Christoph Hellwige3094442006-02-16 13:25:36 +01004280 if (mptsas_sas_device_pg0(ioc, &sas_device,
4281 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004282 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304283 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4284 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4285 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4286 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004287 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004288 }
4289
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304290 /* If there is no FW B_T mapping for this device then break
4291 * */
4292 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4293 || !(sas_device.flags &
4294 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4295 break;
4296
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304297 phy_info = mptsas_find_phyinfo_by_sas_address(
4298 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004299
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304300 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304301 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304302 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4303 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004304 break;
4305 }
4306
4307 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304308 if (!starget) {
4309 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4310 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4311 __func__, hot_plug_info->id, __LINE__));
4312 break;
4313 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004314
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304315 vtarget = starget->hostdata;
4316 if (!vtarget) {
4317 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4318 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4319 __func__, hot_plug_info->id, __LINE__));
4320 break;
4321 }
Eric Moore547f9a22006-06-27 14:42:12 -06004322
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304323 mpt_findImVolumes(ioc);
4324
4325 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4326 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4327 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4328 hot_plug_info->phys_disk_num, (unsigned long long)
4329 sas_device.sas_address);
4330
4331 vtarget->id = hot_plug_info->phys_disk_num;
4332 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4333 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4334 mptsas_reprobe_target(starget, 1);
4335 break;
4336
4337 case MPTSAS_DEL_PHYSDISK_REPROBE:
4338
4339 if (mptsas_sas_device_pg0(ioc, &sas_device,
4340 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4341 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4342 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304343 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304344 "%s: fw_id=%d exit at line=%d\n",
4345 ioc->name, __func__,
4346 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004347 break;
4348 }
4349
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304350 /* If there is no FW B_T mapping for this device then break
4351 * */
4352 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4353 || !(sas_device.flags &
4354 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4355 break;
4356
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304357 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4358 sas_device.sas_address);
4359 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304360 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304361 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4362 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004363 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004364 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004365
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304366 starget = mptsas_get_starget(phy_info);
4367 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304368 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304369 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4370 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004371 break;
4372 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004373
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304374 vtarget = starget->hostdata;
4375 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304376 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304377 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4378 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004379 break;
4380 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304381
4382 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4383 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4384 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4385 __func__, hot_plug_info->id, __LINE__));
4386 break;
4387 }
4388
4389 mpt_findImVolumes(ioc);
4390
4391 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4392 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4393 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4394 hot_plug_info->phys_disk_num, (unsigned long long)
4395 sas_device.sas_address);
4396
4397 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4398 vtarget->id = hot_plug_info->id;
4399 phy_info->attached.phys_disk_num = ~0;
4400 mptsas_reprobe_target(starget, 0);
4401 mptsas_add_device_component_by_fw(ioc,
4402 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004403 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304404
Moore, Ericc73787ee2006-01-26 16:20:06 -07004405 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304406
Moore, Ericc73787ee2006-01-26 16:20:06 -07004407 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304408 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4409 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4410 hot_plug_info->id);
4411 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4412 hot_plug_info->id, 0);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004413 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304414
Moore, Ericc73787ee2006-01-26 16:20:06 -07004415 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304416
Moore, Ericc73787ee2006-01-26 16:20:06 -07004417 mpt_findImVolumes(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304418 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4419 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4420 hot_plug_info->id);
4421 scsi_remove_device(hot_plug_info->sdev);
4422 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004423 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304424
Eric Mooreb506ade2007-01-29 09:45:37 -07004425 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304426
4427 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004428 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304429 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004430 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304431
Moore, Ericbd23e942006-04-17 12:43:04 -06004432 default:
4433 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004434 }
4435
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304436 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004437}
4438
4439static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304440mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004441{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304442 MPT_ADAPTER *ioc;
4443 struct mptsas_hotplug_event hot_plug_info;
4444 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4445 u32 device_info;
4446 u64 sas_address;
4447
4448 ioc = fw_event->ioc;
4449 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4450 fw_event->event_data;
4451 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004452
4453 if ((device_info &
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304454 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4455 MPI_SAS_DEVICE_INFO_STP_TARGET |
4456 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4457 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004458 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304459 }
4460
4461 if (sas_event_data->ReasonCode ==
4462 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4463 mptbase_sas_persist_operation(ioc,
4464 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4465 mptsas_free_fw_event(ioc, fw_event);
4466 return;
4467 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004468
Moore, Eric4b766472006-03-14 09:14:12 -07004469 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004470 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004471 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304472 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4473 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4474 hot_plug_info.channel = sas_event_data->Bus;
4475 hot_plug_info.id = sas_event_data->TargetID;
4476 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004477 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304478 sizeof(u64));
4479 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4480 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004481 if (sas_event_data->ReasonCode &
4482 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304483 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004484 else
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304485 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4486 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004487 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304488
Moore, Eric4b766472006-03-14 09:14:12 -07004489 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304490 mptbase_sas_persist_operation(ioc,
4491 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4492 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004493 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304494
Moore, Eric4b766472006-03-14 09:14:12 -07004495 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304496 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004497 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304498 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004499 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304500 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004501 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004502 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004503}
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304504
Moore, Ericc73787ee2006-01-26 16:20:06 -07004505static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304506mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787ee2006-01-26 16:20:06 -07004507{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304508 MPT_ADAPTER *ioc;
4509 EVENT_DATA_RAID *raid_event_data;
4510 struct mptsas_hotplug_event hot_plug_info;
4511 int status;
4512 int state;
4513 struct scsi_device *sdev = NULL;
4514 VirtDevice *vdevice = NULL;
4515 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004516
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304517 ioc = fw_event->ioc;
4518 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4519 status = le32_to_cpu(raid_event_data->SettingsStatus);
4520 state = (status >> 8) & 0xff;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004521
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304522 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4523 hot_plug_info.id = raid_event_data->VolumeID;
4524 hot_plug_info.channel = raid_event_data->VolumeBus;
4525 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4526
4527 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4528 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4529 raid_event_data->ReasonCode ==
4530 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4531 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4532 hot_plug_info.id, 0);
4533 hot_plug_info.sdev = sdev;
4534 if (sdev)
4535 vdevice = sdev->hostdata;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004536 }
4537
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304538 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4539 "ReasonCode=%02x\n", ioc->name, __func__,
4540 raid_event_data->ReasonCode));
Moore, Ericc73787ee2006-01-26 16:20:06 -07004541
4542 switch (raid_event_data->ReasonCode) {
4543 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304544 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004545 break;
4546 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304547 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004548 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004549 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4550 switch (state) {
4551 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004552 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304553 mpt_raid_phys_disk_pg0(ioc,
4554 raid_event_data->PhysDiskNum, &phys_disk);
4555 hot_plug_info.id = phys_disk.PhysDiskID;
4556 hot_plug_info.channel = phys_disk.PhysDiskBus;
4557 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004558 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304559 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004560 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004561 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4562 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4563 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304564 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004565 break;
4566 default:
4567 break;
4568 }
4569 break;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004570 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304571 if (!sdev)
4572 break;
4573 vdevice->vtarget->deleted = 1; /* block IO */
4574 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004575 break;
4576 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304577 if (sdev) {
4578 scsi_device_put(sdev);
4579 break;
4580 }
4581 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787ee2006-01-26 16:20:06 -07004582 break;
4583 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304584 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4585 if (!sdev)
4586 break;
4587 vdevice->vtarget->deleted = 1; /* block IO */
4588 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4589 break;
4590 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004591 switch (state) {
4592 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4593 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304594 if (!sdev)
4595 break;
4596 vdevice->vtarget->deleted = 1; /* block IO */
4597 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004598 break;
4599 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4600 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304601 if (sdev) {
4602 scsi_device_put(sdev);
4603 break;
4604 }
4605 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004606 break;
4607 default:
4608 break;
4609 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004610 break;
4611 default:
4612 break;
4613 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304614
4615 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4616 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4617 else
4618 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787ee2006-01-26 16:20:06 -07004619}
4620
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304621/**
4622 * mptsas_issue_tm - send mptsas internal tm request
4623 * @ioc: Pointer to MPT_ADAPTER structure
4624 * @type: Task Management type
4625 * @channel: channel number for task management
4626 * @id: Logical Target ID for reset (if appropriate)
4627 * @lun: Logical unit for reset (if appropriate)
4628 * @task_context: Context for the task to be aborted
4629 * @timeout: timeout for task management control
4630 *
4631 * return 0 on success and -1 on failure:
4632 *
4633 */
4634static int
4635mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4636 int task_context, ulong timeout, u8 *issue_reset)
4637{
4638 MPT_FRAME_HDR *mf;
4639 SCSITaskMgmt_t *pScsiTm;
4640 int retval;
4641 unsigned long timeleft;
4642
4643 *issue_reset = 0;
4644 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4645 if (mf == NULL) {
4646 retval = -1; /* return failure */
4647 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4648 "msg frames!!\n", ioc->name));
4649 goto out;
4650 }
4651
4652 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4653 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4654 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4655 type, timeout, channel, id, (unsigned long long)lun,
4656 task_context));
4657
4658 pScsiTm = (SCSITaskMgmt_t *) mf;
4659 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4660 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4661 pScsiTm->TaskType = type;
4662 pScsiTm->MsgFlags = 0;
4663 pScsiTm->TargetID = id;
4664 pScsiTm->Bus = channel;
4665 pScsiTm->ChainOffset = 0;
4666 pScsiTm->Reserved = 0;
4667 pScsiTm->Reserved1 = 0;
4668 pScsiTm->TaskMsgContext = task_context;
4669 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4670
4671 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4672 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4673 retval = 0;
4674 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4675
4676 /* Now wait for the command to complete */
4677 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4678 timeout*HZ);
4679 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4680 retval = -1; /* return failure */
4681 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4682 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4683 mpt_free_msg_frame(ioc, mf);
4684 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4685 goto out;
4686 *issue_reset = 1;
4687 goto out;
4688 }
4689
4690 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4691 retval = -1; /* return failure */
4692 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4693 "TaskMgmt request: failed with no reply\n", ioc->name));
4694 goto out;
4695 }
4696
4697 out:
4698 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4699 return retval;
4700}
4701
4702/**
4703 * mptsas_broadcast_primative_work - Handle broadcast primitives
4704 * @work: work queue payload containing info describing the event
4705 *
4706 * this will be handled in workqueue context.
4707 */
4708static void
4709mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4710{
4711 MPT_ADAPTER *ioc = fw_event->ioc;
4712 MPT_FRAME_HDR *mf;
4713 VirtDevice *vdevice;
4714 int ii;
4715 struct scsi_cmnd *sc;
4716 SCSITaskMgmtReply_t *pScsiTmReply;
4717 u8 issue_reset;
4718 int task_context;
4719 u8 channel, id;
4720 int lun;
4721 u32 termination_count;
4722 u32 query_count;
4723
4724 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4725 "%s - enter\n", ioc->name, __func__));
4726
4727 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4728 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4729 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4730 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4731 return;
4732 }
4733
4734 issue_reset = 0;
4735 termination_count = 0;
4736 query_count = 0;
4737 mpt_findImVolumes(ioc);
4738 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4739
4740 for (ii = 0; ii < ioc->req_depth; ii++) {
4741 if (ioc->fw_events_off)
4742 goto out;
4743 sc = mptscsih_get_scsi_lookup(ioc, ii);
4744 if (!sc)
4745 continue;
4746 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4747 if (!mf)
4748 continue;
4749 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4750 vdevice = sc->device->hostdata;
4751 if (!vdevice || !vdevice->vtarget)
4752 continue;
4753 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4754 continue; /* skip hidden raid components */
4755 if (vdevice->vtarget->raidVolume)
4756 continue; /* skip hidden raid components */
4757 channel = vdevice->vtarget->channel;
4758 id = vdevice->vtarget->id;
4759 lun = vdevice->lun;
4760 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4761 channel, id, (u64)lun, task_context, 30, &issue_reset))
4762 goto out;
4763 query_count++;
4764 termination_count +=
4765 le32_to_cpu(pScsiTmReply->TerminationCount);
4766 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4767 (pScsiTmReply->ResponseCode ==
4768 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4769 pScsiTmReply->ResponseCode ==
4770 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4771 continue;
4772 if (mptsas_issue_tm(ioc,
4773 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4774 channel, id, (u64)lun, 0, 30, &issue_reset))
4775 goto out;
4776 termination_count +=
4777 le32_to_cpu(pScsiTmReply->TerminationCount);
4778 }
4779
4780 out:
4781 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4782 "%s - exit, query_count = %d termination_count = %d\n",
4783 ioc->name, __func__, query_count, termination_count));
4784
4785 ioc->broadcast_aen_busy = 0;
4786 mpt_clear_taskmgmt_in_progress_flag(ioc);
4787 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4788
4789 if (issue_reset) {
4790 printk(MYIOC_s_WARN_FMT "Issuing Reset from %s!!\n",
4791 ioc->name, __func__);
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304792 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304793 }
4794 mptsas_free_fw_event(ioc, fw_event);
4795}
4796
Eric Mooreb506ade2007-01-29 09:45:37 -07004797/*
4798 * mptsas_send_ir2_event - handle exposing hidden disk when
4799 * an inactive raid volume is added
4800 *
4801 * @ioc: Pointer to MPT_ADAPTER structure
4802 * @ir2_data
4803 *
4804 */
4805static void
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304806mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004807{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304808 MPT_ADAPTER *ioc;
4809 struct mptsas_hotplug_event hot_plug_info;
4810 MPI_EVENT_DATA_IR2 *ir2_data;
4811 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304812 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004813
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304814 ioc = fw_event->ioc;
4815 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4816 reasonCode = ir2_data->ReasonCode;
4817
4818 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4819 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4820
4821 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4822 hot_plug_info.id = ir2_data->TargetID;
4823 hot_plug_info.channel = ir2_data->Bus;
4824 switch (reasonCode) {
4825 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4826 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4827 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304828 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4829 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4830 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4831 break;
4832 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4833 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4834 mpt_raid_phys_disk_pg0(ioc,
4835 ir2_data->PhysDiskNum, &phys_disk);
4836 hot_plug_info.id = phys_disk.PhysDiskID;
4837 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4838 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304839 default:
4840 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004841 return;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304842 }
4843 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4844}
Moore, Erice6b2d762006-03-14 09:14:24 -07004845
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004846static int
4847mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4848{
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304849 u32 event = le32_to_cpu(reply->Event);
4850 int sz, event_data_sz;
4851 struct fw_event_work *fw_event;
4852 unsigned long delay;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004853
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304854 if (ioc->bus_type != SAS)
4855 return 0;
4856
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304857 /* events turned off due to host reset or driver unloading */
4858 if (ioc->fw_events_off)
4859 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004860
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304861 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004862 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304863 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4864 {
4865 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4866 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4867 if (broadcast_event_data->Primitive !=
4868 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4869 return 0;
4870 if (ioc->broadcast_aen_busy)
4871 return 0;
4872 ioc->broadcast_aen_busy = 1;
4873 break;
4874 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004875 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304876 {
4877 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4878 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4879
4880 if (sas_event_data->ReasonCode ==
4881 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4882 mptsas_target_reset_queue(ioc, sas_event_data);
4883 return 0;
4884 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004885 break;
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304886 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304887 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4888 {
4889 MpiEventDataSasExpanderStatusChange_t *expander_data =
4890 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4891
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304892 if (ioc->old_sas_discovery_protocal)
4893 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304894
4895 if (expander_data->ReasonCode ==
4896 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4897 ioc->device_missing_delay)
4898 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004899 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304900 }
4901 case MPI_EVENT_SAS_DISCOVERY:
4902 {
4903 u32 discovery_status;
4904 EventDataSasDiscovery_t *discovery_data =
4905 (EventDataSasDiscovery_t *)reply->Data;
4906
4907 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4908 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304909 if (ioc->old_sas_discovery_protocal && !discovery_status)
4910 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304911 return 0;
4912 }
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304913 case MPI_EVENT_INTEGRATED_RAID:
4914 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004915 case MPI_EVENT_IR2:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304916 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4917 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004918 break;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004919 default:
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304920 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004921 }
Moore, Ericc73787ee2006-01-26 16:20:06 -07004922
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304923 event_data_sz = ((reply->MsgLength * 4) -
4924 offsetof(EventNotificationReply_t, Data));
4925 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4926 fw_event = kzalloc(sz, GFP_ATOMIC);
4927 if (!fw_event) {
4928 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4929 __func__, __LINE__);
4930 return 0;
4931 }
4932 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4933 fw_event->event = event;
4934 fw_event->ioc = ioc;
4935 mptsas_add_fw_event(ioc, fw_event, delay);
4936 return 0;
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01004937}
4938
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304939/* Delete a volume when no longer listed in ioc pg2
4940 */
4941static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4942{
4943 struct scsi_device *sdev;
4944 int i;
4945
4946 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4947 if (!sdev)
4948 return;
4949 if (!ioc->raid_data.pIocPg2)
4950 goto out;
4951 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4952 goto out;
4953 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4954 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4955 goto release_sdev;
4956 out:
4957 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4958 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4959 scsi_remove_device(sdev);
4960 release_sdev:
4961 scsi_device_put(sdev);
4962}
4963
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004964static int
4965mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4966{
4967 struct Scsi_Host *sh;
4968 MPT_SCSI_HOST *hd;
4969 MPT_ADAPTER *ioc;
4970 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01004971 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004972 int numSGE = 0;
4973 int scale;
4974 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004975 int error=0;
4976 int r;
4977
4978 r = mpt_attach(pdev,id);
4979 if (r)
4980 return r;
4981
4982 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05304983 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004984 ioc->DoneCtx = mptsasDoneCtx;
4985 ioc->TaskCtx = mptsasTaskCtx;
4986 ioc->InternalCtx = mptsasInternalCtx;
Kashyap, Desaib68bf092010-06-17 14:40:56 +05304987 ioc->schedule_target_reset = &mptsas_schedule_target_reset;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004988 /* Added sanity check on readiness of the MPT adapter.
4989 */
4990 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
4991 printk(MYIOC_s_WARN_FMT
4992 "Skipping because it's not operational!\n",
4993 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07004994 error = -ENODEV;
4995 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004996 }
4997
4998 if (!ioc->active) {
4999 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
5000 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005001 error = -ENODEV;
5002 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005003 }
5004
5005 /* Sanity check - ensure at least 1 port is INITIATOR capable
5006 */
5007 ioc_cap = 0;
5008 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
5009 if (ioc->pfacts[ii].ProtocolFlags &
5010 MPI_PORTFACTS_PROTOCOL_INITIATOR)
5011 ioc_cap++;
5012 }
5013
5014 if (!ioc_cap) {
5015 printk(MYIOC_s_WARN_FMT
5016 "Skipping ioc=%p because SCSI Initiator mode "
5017 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005018 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005019 }
5020
5021 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
5022 if (!sh) {
5023 printk(MYIOC_s_WARN_FMT
5024 "Unable to register controller with SCSI subsystem\n",
5025 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005026 error = -1;
5027 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005028 }
5029
5030 spin_lock_irqsave(&ioc->FreeQlock, flags);
5031
5032 /* Attach the SCSI Host to the IOC structure
5033 */
5034 ioc->sh = sh;
5035
5036 sh->io_port = 0;
5037 sh->n_io_port = 0;
5038 sh->irq = 0;
5039
5040 /* set 16 byte cdb's */
5041 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05305042 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5043 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07005044 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005045 sh->transportt = mptsas_transport_template;
5046
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005047 /* Required entry.
5048 */
5049 sh->unique_id = ioc->id;
5050
5051 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005052 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07005053 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01005054 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005055 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005056
5057 /* Verify that we won't exceed the maximum
5058 * number of chain buffers
5059 * We can optimize: ZZ = req_sz/sizeof(SGE)
5060 * For 32bit SGE's:
5061 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5062 * + (req_sz - 64)/sizeof(SGE)
5063 * A slightly different algorithm is required for
5064 * 64bit SGEs.
5065 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305066 scale = ioc->req_sz/ioc->SGE_size;
5067 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005068 numSGE = (scale - 1) *
5069 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305070 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005071 } else {
5072 numSGE = 1 + (scale - 1) *
5073 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305074 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005075 }
5076
5077 if (numSGE < sh->sg_tablesize) {
5078 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305079 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005080 "Resetting sg_tablesize to %d from %d\n",
5081 ioc->name, numSGE, sh->sg_tablesize));
5082 sh->sg_tablesize = numSGE;
5083 }
5084
Eric Mooree7eae9f2007-09-29 10:15:59 -06005085 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005086 hd->ioc = ioc;
5087
5088 /* SCSI needs scsi_cmnd lookup table!
5089 * (with size equal to req_depth*PtrSz!)
5090 */
Eric Mooree8206382007-09-29 10:16:53 -06005091 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5092 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005093 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005094 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005095 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005096 }
Eric Mooree8206382007-09-29 10:16:53 -06005097 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005098
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305099 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005100 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005101
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005102 ioc->sas_data.ptClear = mpt_pt_clear;
5103
Eric Mooredf9e0622007-01-29 09:46:21 -07005104 hd->last_queue_full = 0;
5105 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305106 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5107 mutex_init(&ioc->sas_device_info_mutex);
5108
Eric Mooredf9e0622007-01-29 09:46:21 -07005109 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5110
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005111 if (ioc->sas_data.ptClear==1) {
5112 mptbase_sas_persist_operation(
5113 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5114 }
5115
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005116 error = scsi_add_host(sh, &ioc->pcidev->dev);
5117 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005118 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5119 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005120 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005121 }
5122
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305123 /* older firmware doesn't support expander events */
5124 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5125 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005126 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305127 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005128 return 0;
5129
Eric Moore547f9a22006-06-27 14:42:12 -06005130 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005131
5132 mptscsih_remove(pdev);
5133 return error;
5134}
5135
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305136void
5137mptsas_shutdown(struct pci_dev *pdev)
5138{
5139 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5140
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305141 mptsas_fw_event_off(ioc);
5142 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305143}
5144
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005145static void __devexit mptsas_remove(struct pci_dev *pdev)
5146{
5147 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5148 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005149 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005150
Kashyap, Desai48959f12010-03-18 19:18:30 +05305151 if (!ioc->sh) {
5152 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5153 mpt_detach(pdev);
5154 return;
5155 }
5156
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305157 mptsas_shutdown(pdev);
5158
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305159 mptsas_del_device_components(ioc);
5160
Eric Mooreb506ade2007-01-29 09:45:37 -07005161 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005162 sas_remove_host(ioc->sh);
5163
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005164 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005165 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5166 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005167 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305168 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb0822c2009-05-29 16:47:26 +05305169
Eric Moore547f9a22006-06-27 14:42:12 -06005170 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005171 kfree(p);
5172 }
Christoph Hellwig9a28f49a2006-01-13 18:04:41 +01005173 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305174 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005175 mptscsih_remove(pdev);
5176}
5177
5178static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005179 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005180 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005181 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005182 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005183 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005184 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005185 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005186 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005187 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005188 PCI_ANY_ID, PCI_ANY_ID },
5189 {0} /* Terminating entry */
5190};
5191MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5192
5193
5194static struct pci_driver mptsas_driver = {
5195 .name = "mptsas",
5196 .id_table = mptsas_pci_table,
5197 .probe = mptsas_probe,
5198 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305199 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005200#ifdef CONFIG_PM
5201 .suspend = mptscsih_suspend,
5202 .resume = mptscsih_resume,
5203#endif
5204};
5205
5206static int __init
5207mptsas_init(void)
5208{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305209 int error;
5210
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005211 show_mptmod_ver(my_NAME, my_VERSION);
5212
5213 mptsas_transport_template =
5214 sas_attach_transport(&mptsas_transport_functions);
5215 if (!mptsas_transport_template)
5216 return -ENODEV;
5217
5218 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305219 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005220 mptsasInternalCtx =
5221 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005222 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305223 mptsasDeviceResetCtx =
5224 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005225
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305226 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5227 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005228
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305229 error = pci_register_driver(&mptsas_driver);
5230 if (error)
5231 sas_release_transport(mptsas_transport_template);
5232
5233 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005234}
5235
5236static void __exit
5237mptsas_exit(void)
5238{
5239 pci_unregister_driver(&mptsas_driver);
5240 sas_release_transport(mptsas_transport_template);
5241
5242 mpt_reset_deregister(mptsasDoneCtx);
5243 mpt_event_deregister(mptsasDoneCtx);
5244
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005245 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005246 mpt_deregister(mptsasInternalCtx);
5247 mpt_deregister(mptsasTaskCtx);
5248 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305249 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005250}
5251
5252module_init(mptsas_init);
5253module_exit(mptsas_exit);