blob: f705a235300e1ef70b742db736e5b213b02b9bd1 [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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-05-29 16:47:26 +0530352 }
Kashyap, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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);
Kei Tokunaga3e84beb2010-04-07 19:17:24 +09001264 if (!ioc->fw_events_off)
Kashyap, Desai3eb08222009-05-29 16:47:26 +05301265 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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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, Ericc73787e2006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-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 Hellwig9a28f492006-01-13 18:04:41 +01004013{
4014 struct mptsas_portinfo *port_info;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004015 struct mptsas_phyinfo *phy_info = NULL;
Eric Moore547f9a22006-06-27 14:42:12 -06004016 int i;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004017
Christoph Hellwig9a28f492006-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 Hellwig9a28f492006-01-13 18:04:41 +01004029 }
4030 }
4031 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-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 Hellwig9a28f492006-01-13 18:04:41 +01004104 }
4105 mutex_unlock(&ioc->sas_topology_mutex);
Christoph Hellwig9a28f492006-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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, Desai3eb08222009-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 Hellwig9a28f492006-01-13 18:04:41 +01004207{
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004208 struct mptsas_phyinfo *phy_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004209 struct scsi_target * starget;
Moore, Ericc73787e2006-01-26 16:20:06 -07004210 struct mptsas_devinfo sas_device;
Moore, Ericf44e5462006-03-14 09:14:21 -07004211 VirtTarget *vtarget;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304212 int i;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304213 struct mptsas_portinfo *port_info;
Eric Moore547f9a22006-06-27 14:42:12 -06004214
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304215 switch (hot_plug_info->event_type) {
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004216
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304217 case MPTSAS_ADD_PHYSDISK:
Eric Mooreb506ade2007-01-29 09:45:37 -07004218
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304219 if (!ioc->raid_data.pIocPg2)
Eric Mooreb506ade2007-01-29 09:45:37 -07004220 break;
Eric Mooreb506ade2007-01-29 09:45:37 -07004221
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304222 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++) {
4223 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID ==
4224 hot_plug_info->id) {
4225 printk(MYIOC_s_WARN_FMT "firmware bug: unable "
4226 "to add hidden disk - target_id matchs "
4227 "volume_id\n", ioc->name);
4228 mptsas_free_fw_event(ioc, fw_event);
4229 return;
Moore, Ericf44e5462006-03-14 09:14:21 -07004230 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004231 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304232 mpt_findImVolumes(ioc);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004233
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004234 case MPTSAS_ADD_DEVICE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304235 memset(&sas_device, 0, sizeof(struct mptsas_devinfo));
4236 mptsas_sas_device_pg0(ioc, &sas_device,
4237 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4238 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4239 (hot_plug_info->channel << 8) +
4240 hot_plug_info->id);
Moore, Ericc73787e2006-01-26 16:20:06 -07004241
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304242 /* If there is no FW B_T mapping for this device then break
4243 * */
4244 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4245 || !(sas_device.flags &
4246 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4247 break;
4248
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304249 if (!sas_device.handle)
4250 return;
Moore, Ericbd23e942006-04-17 12:43:04 -06004251
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304252 phy_info = mptsas_refreshing_device_handles(ioc, &sas_device);
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304253 /* Only For SATA Device ADD */
4254 if (!phy_info && (sas_device.device_info &
4255 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) {
4256 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4257 "%s %d SATA HOT PLUG: "
4258 "parent handle of device %x\n", ioc->name,
4259 __func__, __LINE__, sas_device.handle_parent));
4260 port_info = mptsas_find_portinfo_by_handle(ioc,
4261 sas_device.handle_parent);
4262
4263 if (port_info == ioc->hba_port_info)
4264 mptsas_probe_hba_phys(ioc);
4265 else if (port_info)
4266 mptsas_expander_refresh(ioc, port_info);
4267 else {
4268 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4269 "%s %d port info is NULL\n",
4270 ioc->name, __func__, __LINE__));
4271 break;
4272 }
4273 phy_info = mptsas_refreshing_device_handles
4274 (ioc, &sas_device);
4275 }
4276
4277 if (!phy_info) {
4278 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4279 "%s %d phy info is NULL\n",
4280 ioc->name, __func__, __LINE__));
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304281 break;
Kashyap, Desaicc7e9f5f2010-06-17 14:41:48 +05304282 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304283
4284 if (mptsas_get_rphy(phy_info))
4285 break;
4286
4287 mptsas_add_end_device(ioc, phy_info);
4288 break;
4289
4290 case MPTSAS_DEL_DEVICE:
4291 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4292 hot_plug_info->sas_address);
4293 mptsas_del_end_device(ioc, phy_info);
4294 break;
4295
4296 case MPTSAS_DEL_PHYSDISK:
4297
4298 mpt_findImVolumes(ioc);
4299
4300 phy_info = mptsas_find_phyinfo_by_phys_disk_num(
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304301 ioc, hot_plug_info->phys_disk_num,
4302 hot_plug_info->channel,
4303 hot_plug_info->id);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304304 mptsas_del_end_device(ioc, phy_info);
4305 break;
4306
4307 case MPTSAS_ADD_PHYSDISK_REPROBE:
4308
Christoph Hellwige3094442006-02-16 13:25:36 +01004309 if (mptsas_sas_device_pg0(ioc, &sas_device,
4310 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
Eric Mooreb506ade2007-01-29 09:45:37 -07004311 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304312 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
4313 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4314 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4315 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwige3094442006-02-16 13:25:36 +01004316 break;
Moore, Erice6b2d762006-03-14 09:14:24 -07004317 }
4318
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304319 /* If there is no FW B_T mapping for this device then break
4320 * */
4321 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4322 || !(sas_device.flags &
4323 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4324 break;
4325
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304326 phy_info = mptsas_find_phyinfo_by_sas_address(
4327 ioc, sas_device.sas_address);
Moore, Ericf44e5462006-03-14 09:14:21 -07004328
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304329 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304330 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304331 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4332 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004333 break;
4334 }
4335
4336 starget = mptsas_get_starget(phy_info);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304337 if (!starget) {
4338 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4339 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4340 __func__, hot_plug_info->id, __LINE__));
4341 break;
4342 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004343
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304344 vtarget = starget->hostdata;
4345 if (!vtarget) {
4346 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4347 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4348 __func__, hot_plug_info->id, __LINE__));
4349 break;
4350 }
Eric Moore547f9a22006-06-27 14:42:12 -06004351
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304352 mpt_findImVolumes(ioc);
4353
4354 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Hidding: "
4355 "fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4356 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4357 hot_plug_info->phys_disk_num, (unsigned long long)
4358 sas_device.sas_address);
4359
4360 vtarget->id = hot_plug_info->phys_disk_num;
4361 vtarget->tflags |= MPT_TARGET_FLAGS_RAID_COMPONENT;
4362 phy_info->attached.phys_disk_num = hot_plug_info->phys_disk_num;
4363 mptsas_reprobe_target(starget, 1);
4364 break;
4365
4366 case MPTSAS_DEL_PHYSDISK_REPROBE:
4367
4368 if (mptsas_sas_device_pg0(ioc, &sas_device,
4369 (MPI_SAS_DEVICE_PGAD_FORM_BUS_TARGET_ID <<
4370 MPI_SAS_DEVICE_PGAD_FORM_SHIFT),
4371 (hot_plug_info->channel << 8) + hot_plug_info->id)) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304372 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304373 "%s: fw_id=%d exit at line=%d\n",
4374 ioc->name, __func__,
4375 hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004376 break;
4377 }
4378
Kashyap, Desai51106ab2010-06-17 14:40:10 +05304379 /* If there is no FW B_T mapping for this device then break
4380 * */
4381 if (!(sas_device.flags & MPI_SAS_DEVICE0_FLAGS_DEVICE_PRESENT)
4382 || !(sas_device.flags &
4383 MPI_SAS_DEVICE0_FLAGS_DEVICE_MAPPED))
4384 break;
4385
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304386 phy_info = mptsas_find_phyinfo_by_sas_address(ioc,
4387 sas_device.sas_address);
4388 if (!phy_info) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304389 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304390 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4391 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004392 break;
Eric Moore547f9a22006-06-27 14:42:12 -06004393 }
Eric Mooreb506ade2007-01-29 09:45:37 -07004394
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304395 starget = mptsas_get_starget(phy_info);
4396 if (!starget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304397 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304398 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4399 __func__, hot_plug_info->id, __LINE__));
Eric Moore547f9a22006-06-27 14:42:12 -06004400 break;
4401 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004402
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304403 vtarget = starget->hostdata;
4404 if (!vtarget) {
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05304405 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304406 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4407 __func__, hot_plug_info->id, __LINE__));
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004408 break;
4409 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304410
4411 if (!(vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)) {
4412 dfailprintk(ioc, printk(MYIOC_s_ERR_FMT
4413 "%s: fw_id=%d exit at line=%d\n", ioc->name,
4414 __func__, hot_plug_info->id, __LINE__));
4415 break;
4416 }
4417
4418 mpt_findImVolumes(ioc);
4419
4420 starget_printk(KERN_INFO, starget, MYIOC_s_FMT "RAID Exposing:"
4421 " fw_channel=%d, fw_id=%d, physdsk %d, sas_addr 0x%llx\n",
4422 ioc->name, hot_plug_info->channel, hot_plug_info->id,
4423 hot_plug_info->phys_disk_num, (unsigned long long)
4424 sas_device.sas_address);
4425
4426 vtarget->tflags &= ~MPT_TARGET_FLAGS_RAID_COMPONENT;
4427 vtarget->id = hot_plug_info->id;
4428 phy_info->attached.phys_disk_num = ~0;
4429 mptsas_reprobe_target(starget, 0);
4430 mptsas_add_device_component_by_fw(ioc,
4431 hot_plug_info->channel, hot_plug_info->id);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004432 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304433
Moore, Ericc73787e2006-01-26 16:20:06 -07004434 case MPTSAS_ADD_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304435
Moore, Ericc73787e2006-01-26 16:20:06 -07004436 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304437 printk(MYIOC_s_INFO_FMT "attaching raid volume, channel %d, "
4438 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4439 hot_plug_info->id);
4440 scsi_add_device(ioc->sh, MPTSAS_RAID_CHANNEL,
4441 hot_plug_info->id, 0);
Moore, Ericc73787e2006-01-26 16:20:06 -07004442 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304443
Moore, Ericc73787e2006-01-26 16:20:06 -07004444 case MPTSAS_DEL_RAID:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304445
Moore, Ericc73787e2006-01-26 16:20:06 -07004446 mpt_findImVolumes(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304447 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4448 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL,
4449 hot_plug_info->id);
4450 scsi_remove_device(hot_plug_info->sdev);
4451 scsi_device_put(hot_plug_info->sdev);
Moore, Ericc73787e2006-01-26 16:20:06 -07004452 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304453
Eric Mooreb506ade2007-01-29 09:45:37 -07004454 case MPTSAS_ADD_INACTIVE_VOLUME:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304455
4456 mpt_findImVolumes(ioc);
Eric Mooreb506ade2007-01-29 09:45:37 -07004457 mptsas_adding_inactive_raid_components(ioc,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304458 hot_plug_info->channel, hot_plug_info->id);
Eric Mooreb506ade2007-01-29 09:45:37 -07004459 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304460
Moore, Ericbd23e942006-04-17 12:43:04 -06004461 default:
4462 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004463 }
4464
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304465 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004466}
4467
4468static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304469mptsas_send_sas_event(struct fw_event_work *fw_event)
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004470{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304471 MPT_ADAPTER *ioc;
4472 struct mptsas_hotplug_event hot_plug_info;
4473 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data;
4474 u32 device_info;
4475 u64 sas_address;
4476
4477 ioc = fw_event->ioc;
4478 sas_event_data = (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)
4479 fw_event->event_data;
4480 device_info = le32_to_cpu(sas_event_data->DeviceInfo);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004481
4482 if ((device_info &
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304483 (MPI_SAS_DEVICE_INFO_SSP_TARGET |
4484 MPI_SAS_DEVICE_INFO_STP_TARGET |
4485 MPI_SAS_DEVICE_INFO_SATA_DEVICE)) == 0) {
4486 mptsas_free_fw_event(ioc, fw_event);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004487 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304488 }
4489
4490 if (sas_event_data->ReasonCode ==
4491 MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED) {
4492 mptbase_sas_persist_operation(ioc,
4493 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4494 mptsas_free_fw_event(ioc, fw_event);
4495 return;
4496 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004497
Moore, Eric4b766472006-03-14 09:14:12 -07004498 switch (sas_event_data->ReasonCode) {
Moore, Eric4b766472006-03-14 09:14:12 -07004499 case MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING:
Eric Mooredf9e0622007-01-29 09:46:21 -07004500 case MPI_EVENT_SAS_DEV_STAT_RC_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304501 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4502 hot_plug_info.handle = le16_to_cpu(sas_event_data->DevHandle);
4503 hot_plug_info.channel = sas_event_data->Bus;
4504 hot_plug_info.id = sas_event_data->TargetID;
4505 hot_plug_info.phy_id = sas_event_data->PhyNum;
Moore, Eric4b766472006-03-14 09:14:12 -07004506 memcpy(&sas_address, &sas_event_data->SASAddress,
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304507 sizeof(u64));
4508 hot_plug_info.sas_address = le64_to_cpu(sas_address);
4509 hot_plug_info.device_info = device_info;
Moore, Eric4b766472006-03-14 09:14:12 -07004510 if (sas_event_data->ReasonCode &
4511 MPI_EVENT_SAS_DEV_STAT_RC_ADDED)
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304512 hot_plug_info.event_type = MPTSAS_ADD_DEVICE;
Moore, Eric4b766472006-03-14 09:14:12 -07004513 else
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304514 hot_plug_info.event_type = MPTSAS_DEL_DEVICE;
4515 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
Moore, Eric4b766472006-03-14 09:14:12 -07004516 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304517
Moore, Eric4b766472006-03-14 09:14:12 -07004518 case MPI_EVENT_SAS_DEV_STAT_RC_NO_PERSIST_ADDED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304519 mptbase_sas_persist_operation(ioc,
4520 MPI_SAS_OP_CLEAR_NOT_PRESENT);
4521 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004522 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304523
Moore, Eric4b766472006-03-14 09:14:12 -07004524 case MPI_EVENT_SAS_DEV_STAT_RC_SMART_DATA:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304525 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004526 case MPI_EVENT_SAS_DEV_STAT_RC_INTERNAL_DEVICE_RESET:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304527 /* TODO */
Moore, Eric4b766472006-03-14 09:14:12 -07004528 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304529 mptsas_free_fw_event(ioc, fw_event);
Moore, Eric4b766472006-03-14 09:14:12 -07004530 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004531 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004532}
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304533
Moore, Ericc73787e2006-01-26 16:20:06 -07004534static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304535mptsas_send_raid_event(struct fw_event_work *fw_event)
Moore, Ericc73787e2006-01-26 16:20:06 -07004536{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304537 MPT_ADAPTER *ioc;
4538 EVENT_DATA_RAID *raid_event_data;
4539 struct mptsas_hotplug_event hot_plug_info;
4540 int status;
4541 int state;
4542 struct scsi_device *sdev = NULL;
4543 VirtDevice *vdevice = NULL;
4544 RaidPhysDiskPage0_t phys_disk;
Moore, Ericc73787e2006-01-26 16:20:06 -07004545
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304546 ioc = fw_event->ioc;
4547 raid_event_data = (EVENT_DATA_RAID *)fw_event->event_data;
4548 status = le32_to_cpu(raid_event_data->SettingsStatus);
4549 state = (status >> 8) & 0xff;
Moore, Ericc73787e2006-01-26 16:20:06 -07004550
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304551 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4552 hot_plug_info.id = raid_event_data->VolumeID;
4553 hot_plug_info.channel = raid_event_data->VolumeBus;
4554 hot_plug_info.phys_disk_num = raid_event_data->PhysDiskNum;
4555
4556 if (raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_DELETED ||
4557 raid_event_data->ReasonCode == MPI_EVENT_RAID_RC_VOLUME_CREATED ||
4558 raid_event_data->ReasonCode ==
4559 MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED) {
4560 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL,
4561 hot_plug_info.id, 0);
4562 hot_plug_info.sdev = sdev;
4563 if (sdev)
4564 vdevice = sdev->hostdata;
Moore, Ericc73787e2006-01-26 16:20:06 -07004565 }
4566
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304567 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4568 "ReasonCode=%02x\n", ioc->name, __func__,
4569 raid_event_data->ReasonCode));
Moore, Ericc73787e2006-01-26 16:20:06 -07004570
4571 switch (raid_event_data->ReasonCode) {
4572 case MPI_EVENT_RAID_RC_PHYSDISK_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304573 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004574 break;
4575 case MPI_EVENT_RAID_RC_PHYSDISK_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304576 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK_REPROBE;
Moore, Ericc73787e2006-01-26 16:20:06 -07004577 break;
Moore, Ericbd23e942006-04-17 12:43:04 -06004578 case MPI_EVENT_RAID_RC_PHYSDISK_STATUS_CHANGED:
4579 switch (state) {
4580 case MPI_PD_STATE_ONLINE:
Eric Mooreb506ade2007-01-29 09:45:37 -07004581 case MPI_PD_STATE_NOT_COMPATIBLE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304582 mpt_raid_phys_disk_pg0(ioc,
4583 raid_event_data->PhysDiskNum, &phys_disk);
4584 hot_plug_info.id = phys_disk.PhysDiskID;
4585 hot_plug_info.channel = phys_disk.PhysDiskBus;
4586 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004587 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304588 case MPI_PD_STATE_FAILED:
Moore, Ericbd23e942006-04-17 12:43:04 -06004589 case MPI_PD_STATE_MISSING:
Moore, Ericbd23e942006-04-17 12:43:04 -06004590 case MPI_PD_STATE_OFFLINE_AT_HOST_REQUEST:
4591 case MPI_PD_STATE_FAILED_AT_HOST_REQUEST:
4592 case MPI_PD_STATE_OFFLINE_FOR_ANOTHER_REASON:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304593 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
Moore, Ericbd23e942006-04-17 12:43:04 -06004594 break;
4595 default:
4596 break;
4597 }
4598 break;
Moore, Ericc73787e2006-01-26 16:20:06 -07004599 case MPI_EVENT_RAID_RC_VOLUME_DELETED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304600 if (!sdev)
4601 break;
4602 vdevice->vtarget->deleted = 1; /* block IO */
4603 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004604 break;
4605 case MPI_EVENT_RAID_RC_VOLUME_CREATED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304606 if (sdev) {
4607 scsi_device_put(sdev);
4608 break;
4609 }
4610 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericc73787e2006-01-26 16:20:06 -07004611 break;
4612 case MPI_EVENT_RAID_RC_VOLUME_STATUS_CHANGED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304613 if (!(status & MPI_RAIDVOL0_STATUS_FLAG_ENABLED)) {
4614 if (!sdev)
4615 break;
4616 vdevice->vtarget->deleted = 1; /* block IO */
4617 hot_plug_info.event_type = MPTSAS_DEL_RAID;
4618 break;
4619 }
Moore, Ericbd23e942006-04-17 12:43:04 -06004620 switch (state) {
4621 case MPI_RAIDVOL0_STATUS_STATE_FAILED:
4622 case MPI_RAIDVOL0_STATUS_STATE_MISSING:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304623 if (!sdev)
4624 break;
4625 vdevice->vtarget->deleted = 1; /* block IO */
4626 hot_plug_info.event_type = MPTSAS_DEL_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004627 break;
4628 case MPI_RAIDVOL0_STATUS_STATE_OPTIMAL:
4629 case MPI_RAIDVOL0_STATUS_STATE_DEGRADED:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304630 if (sdev) {
4631 scsi_device_put(sdev);
4632 break;
4633 }
4634 hot_plug_info.event_type = MPTSAS_ADD_RAID;
Moore, Ericbd23e942006-04-17 12:43:04 -06004635 break;
4636 default:
4637 break;
4638 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004639 break;
4640 default:
4641 break;
4642 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304643
4644 if (hot_plug_info.event_type != MPTSAS_IGNORE_EVENT)
4645 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4646 else
4647 mptsas_free_fw_event(ioc, fw_event);
Moore, Ericc73787e2006-01-26 16:20:06 -07004648}
4649
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304650/**
4651 * mptsas_issue_tm - send mptsas internal tm request
4652 * @ioc: Pointer to MPT_ADAPTER structure
4653 * @type: Task Management type
4654 * @channel: channel number for task management
4655 * @id: Logical Target ID for reset (if appropriate)
4656 * @lun: Logical unit for reset (if appropriate)
4657 * @task_context: Context for the task to be aborted
4658 * @timeout: timeout for task management control
4659 *
4660 * return 0 on success and -1 on failure:
4661 *
4662 */
4663static int
4664mptsas_issue_tm(MPT_ADAPTER *ioc, u8 type, u8 channel, u8 id, u64 lun,
4665 int task_context, ulong timeout, u8 *issue_reset)
4666{
4667 MPT_FRAME_HDR *mf;
4668 SCSITaskMgmt_t *pScsiTm;
4669 int retval;
4670 unsigned long timeleft;
4671
4672 *issue_reset = 0;
4673 mf = mpt_get_msg_frame(mptsasDeviceResetCtx, ioc);
4674 if (mf == NULL) {
4675 retval = -1; /* return failure */
4676 dtmprintk(ioc, printk(MYIOC_s_WARN_FMT "TaskMgmt request: no "
4677 "msg frames!!\n", ioc->name));
4678 goto out;
4679 }
4680
4681 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT "TaskMgmt request: mr = %p, "
4682 "task_type = 0x%02X,\n\t timeout = %ld, fw_channel = %d, "
4683 "fw_id = %d, lun = %lld,\n\t task_context = 0x%x\n", ioc->name, mf,
4684 type, timeout, channel, id, (unsigned long long)lun,
4685 task_context));
4686
4687 pScsiTm = (SCSITaskMgmt_t *) mf;
4688 memset(pScsiTm, 0, sizeof(SCSITaskMgmt_t));
4689 pScsiTm->Function = MPI_FUNCTION_SCSI_TASK_MGMT;
4690 pScsiTm->TaskType = type;
4691 pScsiTm->MsgFlags = 0;
4692 pScsiTm->TargetID = id;
4693 pScsiTm->Bus = channel;
4694 pScsiTm->ChainOffset = 0;
4695 pScsiTm->Reserved = 0;
4696 pScsiTm->Reserved1 = 0;
4697 pScsiTm->TaskMsgContext = task_context;
4698 int_to_scsilun(lun, (struct scsi_lun *)pScsiTm->LUN);
4699
4700 INITIALIZE_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4701 CLEAR_MGMT_STATUS(ioc->internal_cmds.status)
4702 retval = 0;
4703 mpt_put_msg_frame_hi_pri(mptsasDeviceResetCtx, ioc, mf);
4704
4705 /* Now wait for the command to complete */
4706 timeleft = wait_for_completion_timeout(&ioc->taskmgmt_cmds.done,
4707 timeout*HZ);
4708 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_COMMAND_GOOD)) {
4709 retval = -1; /* return failure */
4710 dtmprintk(ioc, printk(MYIOC_s_ERR_FMT
4711 "TaskMgmt request: TIMED OUT!(mr=%p)\n", ioc->name, mf));
4712 mpt_free_msg_frame(ioc, mf);
4713 if (ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_DID_IOCRESET)
4714 goto out;
4715 *issue_reset = 1;
4716 goto out;
4717 }
4718
4719 if (!(ioc->taskmgmt_cmds.status & MPT_MGMT_STATUS_RF_VALID)) {
4720 retval = -1; /* return failure */
4721 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4722 "TaskMgmt request: failed with no reply\n", ioc->name));
4723 goto out;
4724 }
4725
4726 out:
4727 CLEAR_MGMT_STATUS(ioc->taskmgmt_cmds.status)
4728 return retval;
4729}
4730
4731/**
4732 * mptsas_broadcast_primative_work - Handle broadcast primitives
4733 * @work: work queue payload containing info describing the event
4734 *
4735 * this will be handled in workqueue context.
4736 */
4737static void
4738mptsas_broadcast_primative_work(struct fw_event_work *fw_event)
4739{
4740 MPT_ADAPTER *ioc = fw_event->ioc;
4741 MPT_FRAME_HDR *mf;
4742 VirtDevice *vdevice;
4743 int ii;
4744 struct scsi_cmnd *sc;
4745 SCSITaskMgmtReply_t *pScsiTmReply;
4746 u8 issue_reset;
4747 int task_context;
4748 u8 channel, id;
4749 int lun;
4750 u32 termination_count;
4751 u32 query_count;
4752
4753 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4754 "%s - enter\n", ioc->name, __func__));
4755
4756 mutex_lock(&ioc->taskmgmt_cmds.mutex);
4757 if (mpt_set_taskmgmt_in_progress_flag(ioc) != 0) {
4758 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4759 mptsas_requeue_fw_event(ioc, fw_event, 1000);
4760 return;
4761 }
4762
4763 issue_reset = 0;
4764 termination_count = 0;
4765 query_count = 0;
4766 mpt_findImVolumes(ioc);
4767 pScsiTmReply = (SCSITaskMgmtReply_t *) ioc->taskmgmt_cmds.reply;
4768
4769 for (ii = 0; ii < ioc->req_depth; ii++) {
4770 if (ioc->fw_events_off)
4771 goto out;
4772 sc = mptscsih_get_scsi_lookup(ioc, ii);
4773 if (!sc)
4774 continue;
4775 mf = MPT_INDEX_2_MFPTR(ioc, ii);
4776 if (!mf)
4777 continue;
4778 task_context = mf->u.frame.hwhdr.msgctxu.MsgContext;
4779 vdevice = sc->device->hostdata;
4780 if (!vdevice || !vdevice->vtarget)
4781 continue;
4782 if (vdevice->vtarget->tflags & MPT_TARGET_FLAGS_RAID_COMPONENT)
4783 continue; /* skip hidden raid components */
4784 if (vdevice->vtarget->raidVolume)
4785 continue; /* skip hidden raid components */
4786 channel = vdevice->vtarget->channel;
4787 id = vdevice->vtarget->id;
4788 lun = vdevice->lun;
4789 if (mptsas_issue_tm(ioc, MPI_SCSITASKMGMT_TASKTYPE_QUERY_TASK,
4790 channel, id, (u64)lun, task_context, 30, &issue_reset))
4791 goto out;
4792 query_count++;
4793 termination_count +=
4794 le32_to_cpu(pScsiTmReply->TerminationCount);
4795 if ((pScsiTmReply->IOCStatus == MPI_IOCSTATUS_SUCCESS) &&
4796 (pScsiTmReply->ResponseCode ==
4797 MPI_SCSITASKMGMT_RSP_TM_SUCCEEDED ||
4798 pScsiTmReply->ResponseCode ==
4799 MPI_SCSITASKMGMT_RSP_IO_QUEUED_ON_IOC))
4800 continue;
4801 if (mptsas_issue_tm(ioc,
4802 MPI_SCSITASKMGMT_TASKTYPE_ABRT_TASK_SET,
4803 channel, id, (u64)lun, 0, 30, &issue_reset))
4804 goto out;
4805 termination_count +=
4806 le32_to_cpu(pScsiTmReply->TerminationCount);
4807 }
4808
4809 out:
4810 dtmprintk(ioc, printk(MYIOC_s_DEBUG_FMT
4811 "%s - exit, query_count = %d termination_count = %d\n",
4812 ioc->name, __func__, query_count, termination_count));
4813
4814 ioc->broadcast_aen_busy = 0;
4815 mpt_clear_taskmgmt_in_progress_flag(ioc);
4816 mutex_unlock(&ioc->taskmgmt_cmds.mutex);
4817
4818 if (issue_reset) {
Kei Tokunaga97009a22010-06-22 19:01:51 +09004819 printk(MYIOC_s_WARN_FMT
4820 "Issuing Reset from %s!! doorbell=0x%08x\n",
4821 ioc->name, __func__, mpt_GetIocState(ioc, 0));
Kashyap, Desaid0f698c2010-03-18 19:12:17 +05304822 mpt_Soft_Hard_ResetHandler(ioc, CAN_SLEEP);
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304823 }
4824 mptsas_free_fw_event(ioc, fw_event);
4825}
4826
Eric Mooreb506ade2007-01-29 09:45:37 -07004827/*
4828 * mptsas_send_ir2_event - handle exposing hidden disk when
4829 * an inactive raid volume is added
4830 *
4831 * @ioc: Pointer to MPT_ADAPTER structure
4832 * @ir2_data
4833 *
4834 */
4835static void
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304836mptsas_send_ir2_event(struct fw_event_work *fw_event)
Eric Mooreb506ade2007-01-29 09:45:37 -07004837{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304838 MPT_ADAPTER *ioc;
4839 struct mptsas_hotplug_event hot_plug_info;
4840 MPI_EVENT_DATA_IR2 *ir2_data;
4841 u8 reasonCode;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304842 RaidPhysDiskPage0_t phys_disk;
Eric Mooreb506ade2007-01-29 09:45:37 -07004843
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304844 ioc = fw_event->ioc;
4845 ir2_data = (MPI_EVENT_DATA_IR2 *)fw_event->event_data;
4846 reasonCode = ir2_data->ReasonCode;
4847
4848 devtprintk(ioc, printk(MYIOC_s_DEBUG_FMT "Entering %s: "
4849 "ReasonCode=%02x\n", ioc->name, __func__, reasonCode));
4850
4851 memset(&hot_plug_info, 0, sizeof(struct mptsas_hotplug_event));
4852 hot_plug_info.id = ir2_data->TargetID;
4853 hot_plug_info.channel = ir2_data->Bus;
4854 switch (reasonCode) {
4855 case MPI_EVENT_IR2_RC_FOREIGN_CFG_DETECTED:
4856 hot_plug_info.event_type = MPTSAS_ADD_INACTIVE_VOLUME;
4857 break;
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304858 case MPI_EVENT_IR2_RC_DUAL_PORT_REMOVED:
4859 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4860 hot_plug_info.event_type = MPTSAS_DEL_PHYSDISK;
4861 break;
4862 case MPI_EVENT_IR2_RC_DUAL_PORT_ADDED:
4863 hot_plug_info.phys_disk_num = ir2_data->PhysDiskNum;
4864 mpt_raid_phys_disk_pg0(ioc,
4865 ir2_data->PhysDiskNum, &phys_disk);
4866 hot_plug_info.id = phys_disk.PhysDiskID;
4867 hot_plug_info.event_type = MPTSAS_ADD_PHYSDISK;
4868 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304869 default:
4870 mptsas_free_fw_event(ioc, fw_event);
Eric Mooreb506ade2007-01-29 09:45:37 -07004871 return;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304872 }
4873 mptsas_hotplug_work(ioc, fw_event, &hot_plug_info);
4874}
Moore, Erice6b2d762006-03-14 09:14:24 -07004875
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004876static int
4877mptsas_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *reply)
4878{
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304879 u32 event = le32_to_cpu(reply->Event);
4880 int sz, event_data_sz;
4881 struct fw_event_work *fw_event;
4882 unsigned long delay;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004883
Kashyap, Desaiffb7fef2010-03-18 19:20:38 +05304884 if (ioc->bus_type != SAS)
4885 return 0;
4886
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304887 /* events turned off due to host reset or driver unloading */
4888 if (ioc->fw_events_off)
4889 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004890
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304891 delay = msecs_to_jiffies(1);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004892 switch (event) {
Kashyap, Desaidb7051b2009-05-29 16:56:59 +05304893 case MPI_EVENT_SAS_BROADCAST_PRIMITIVE:
4894 {
4895 EVENT_DATA_SAS_BROADCAST_PRIMITIVE *broadcast_event_data =
4896 (EVENT_DATA_SAS_BROADCAST_PRIMITIVE *)reply->Data;
4897 if (broadcast_event_data->Primitive !=
4898 MPI_EVENT_PRIMITIVE_ASYNCHRONOUS_EVENT)
4899 return 0;
4900 if (ioc->broadcast_aen_busy)
4901 return 0;
4902 ioc->broadcast_aen_busy = 1;
4903 break;
4904 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004905 case MPI_EVENT_SAS_DEVICE_STATUS_CHANGE:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304906 {
4907 EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *sas_event_data =
4908 (EVENT_DATA_SAS_DEVICE_STATUS_CHANGE *)reply->Data;
4909
4910 if (sas_event_data->ReasonCode ==
4911 MPI_EVENT_SAS_DEV_STAT_RC_NOT_RESPONDING) {
4912 mptsas_target_reset_queue(ioc, sas_event_data);
4913 return 0;
4914 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004915 break;
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304916 }
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304917 case MPI_EVENT_SAS_EXPANDER_STATUS_CHANGE:
4918 {
4919 MpiEventDataSasExpanderStatusChange_t *expander_data =
4920 (MpiEventDataSasExpanderStatusChange_t *)reply->Data;
4921
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304922 if (ioc->old_sas_discovery_protocal)
4923 return 0;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304924
4925 if (expander_data->ReasonCode ==
4926 MPI_EVENT_SAS_EXP_RC_NOT_RESPONDING &&
4927 ioc->device_missing_delay)
4928 delay = HZ * ioc->device_missing_delay;
Moore, Erice6b2d762006-03-14 09:14:24 -07004929 break;
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304930 }
4931 case MPI_EVENT_SAS_DISCOVERY:
4932 {
4933 u32 discovery_status;
4934 EventDataSasDiscovery_t *discovery_data =
4935 (EventDataSasDiscovery_t *)reply->Data;
4936
4937 discovery_status = le32_to_cpu(discovery_data->DiscoveryStatus);
4938 ioc->sas_discovery_quiesce_io = discovery_status ? 1 : 0;
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05304939 if (ioc->old_sas_discovery_protocal && !discovery_status)
4940 mptsas_queue_rescan(ioc);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05304941 return 0;
4942 }
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304943 case MPI_EVENT_INTEGRATED_RAID:
4944 case MPI_EVENT_PERSISTENT_TABLE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004945 case MPI_EVENT_IR2:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304946 case MPI_EVENT_SAS_PHY_LINK_STATUS:
4947 case MPI_EVENT_QUEUE_FULL:
Eric Mooreb506ade2007-01-29 09:45:37 -07004948 break;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004949 default:
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304950 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004951 }
Moore, Ericc73787e2006-01-26 16:20:06 -07004952
Kashyap, Desai3eb08222009-05-29 16:47:26 +05304953 event_data_sz = ((reply->MsgLength * 4) -
4954 offsetof(EventNotificationReply_t, Data));
4955 sz = offsetof(struct fw_event_work, event_data) + event_data_sz;
4956 fw_event = kzalloc(sz, GFP_ATOMIC);
4957 if (!fw_event) {
4958 printk(MYIOC_s_WARN_FMT "%s: failed at (line=%d)\n", ioc->name,
4959 __func__, __LINE__);
4960 return 0;
4961 }
4962 memcpy(fw_event->event_data, reply->Data, event_data_sz);
4963 fw_event->event = event;
4964 fw_event->ioc = ioc;
4965 mptsas_add_fw_event(ioc, fw_event, delay);
4966 return 0;
Christoph Hellwig9a28f492006-01-13 18:04:41 +01004967}
4968
Kashyap, Desaia7938b02009-05-29 16:53:56 +05304969/* Delete a volume when no longer listed in ioc pg2
4970 */
4971static void mptsas_volume_delete(MPT_ADAPTER *ioc, u8 id)
4972{
4973 struct scsi_device *sdev;
4974 int i;
4975
4976 sdev = scsi_device_lookup(ioc->sh, MPTSAS_RAID_CHANNEL, id, 0);
4977 if (!sdev)
4978 return;
4979 if (!ioc->raid_data.pIocPg2)
4980 goto out;
4981 if (!ioc->raid_data.pIocPg2->NumActiveVolumes)
4982 goto out;
4983 for (i = 0; i < ioc->raid_data.pIocPg2->NumActiveVolumes; i++)
4984 if (ioc->raid_data.pIocPg2->RaidVolume[i].VolumeID == id)
4985 goto release_sdev;
4986 out:
4987 printk(MYIOC_s_INFO_FMT "removing raid volume, channel %d, "
4988 "id %d\n", ioc->name, MPTSAS_RAID_CHANNEL, id);
4989 scsi_remove_device(sdev);
4990 release_sdev:
4991 scsi_device_put(sdev);
4992}
4993
Christoph Hellwig0c33b272005-09-09 16:27:19 +02004994static int
4995mptsas_probe(struct pci_dev *pdev, const struct pci_device_id *id)
4996{
4997 struct Scsi_Host *sh;
4998 MPT_SCSI_HOST *hd;
4999 MPT_ADAPTER *ioc;
5000 unsigned long flags;
Christoph Hellwig1ca00bb2006-01-13 18:27:50 +01005001 int ii;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005002 int numSGE = 0;
5003 int scale;
5004 int ioc_cap;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005005 int error=0;
5006 int r;
5007
5008 r = mpt_attach(pdev,id);
5009 if (r)
5010 return r;
5011
5012 ioc = pci_get_drvdata(pdev);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305013 mptsas_fw_event_off(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005014 ioc->DoneCtx = mptsasDoneCtx;
5015 ioc->TaskCtx = mptsasTaskCtx;
5016 ioc->InternalCtx = mptsasInternalCtx;
Kashyap, Desaib68bf092010-06-17 14:40:56 +05305017 ioc->schedule_target_reset = &mptsas_schedule_target_reset;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005018 /* Added sanity check on readiness of the MPT adapter.
5019 */
5020 if (ioc->last_state != MPI_IOC_STATE_OPERATIONAL) {
5021 printk(MYIOC_s_WARN_FMT
5022 "Skipping because it's not operational!\n",
5023 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005024 error = -ENODEV;
5025 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005026 }
5027
5028 if (!ioc->active) {
5029 printk(MYIOC_s_WARN_FMT "Skipping because it's disabled!\n",
5030 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005031 error = -ENODEV;
5032 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005033 }
5034
5035 /* Sanity check - ensure at least 1 port is INITIATOR capable
5036 */
5037 ioc_cap = 0;
5038 for (ii = 0; ii < ioc->facts.NumberOfPorts; ii++) {
5039 if (ioc->pfacts[ii].ProtocolFlags &
5040 MPI_PORTFACTS_PROTOCOL_INITIATOR)
5041 ioc_cap++;
5042 }
5043
5044 if (!ioc_cap) {
5045 printk(MYIOC_s_WARN_FMT
5046 "Skipping ioc=%p because SCSI Initiator mode "
5047 "is NOT enabled!\n", ioc->name, ioc);
Moore, Eric Dean466544d2005-09-14 18:09:10 -06005048 return 0;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005049 }
5050
5051 sh = scsi_host_alloc(&mptsas_driver_template, sizeof(MPT_SCSI_HOST));
5052 if (!sh) {
5053 printk(MYIOC_s_WARN_FMT
5054 "Unable to register controller with SCSI subsystem\n",
5055 ioc->name);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005056 error = -1;
5057 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005058 }
5059
5060 spin_lock_irqsave(&ioc->FreeQlock, flags);
5061
5062 /* Attach the SCSI Host to the IOC structure
5063 */
5064 ioc->sh = sh;
5065
5066 sh->io_port = 0;
5067 sh->n_io_port = 0;
5068 sh->irq = 0;
5069
5070 /* set 16 byte cdb's */
5071 sh->max_cmd_len = 16;
Kashyap, Desai79a3ec12009-08-05 12:52:58 +05305072 sh->can_queue = min_t(int, ioc->req_depth - 10, sh->can_queue);
5073 sh->max_id = -1;
Eric Moore793955f2007-01-29 09:42:20 -07005074 sh->max_lun = max_lun;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005075 sh->transportt = mptsas_transport_template;
5076
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005077 /* Required entry.
5078 */
5079 sh->unique_id = ioc->id;
5080
5081 INIT_LIST_HEAD(&ioc->sas_topology);
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005082 mutex_init(&ioc->sas_topology_mutex);
Moore, Erice6b2d762006-03-14 09:14:24 -07005083 mutex_init(&ioc->sas_discovery_mutex);
Christoph Hellwigeeb846c2006-01-13 18:27:11 +01005084 mutex_init(&ioc->sas_mgmt.mutex);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005085 init_completion(&ioc->sas_mgmt.done);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005086
5087 /* Verify that we won't exceed the maximum
5088 * number of chain buffers
5089 * We can optimize: ZZ = req_sz/sizeof(SGE)
5090 * For 32bit SGE's:
5091 * numSGE = 1 + (ZZ-1)*(maxChain -1) + ZZ
5092 * + (req_sz - 64)/sizeof(SGE)
5093 * A slightly different algorithm is required for
5094 * 64bit SGEs.
5095 */
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305096 scale = ioc->req_sz/ioc->SGE_size;
5097 if (ioc->sg_addr_size == sizeof(u64)) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005098 numSGE = (scale - 1) *
5099 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305100 (ioc->req_sz - 60) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005101 } else {
5102 numSGE = 1 + (scale - 1) *
5103 (ioc->facts.MaxChainDepth-1) + scale +
Kashyap, Desai14d0f0b2009-05-29 16:37:04 +05305104 (ioc->req_sz - 64) / ioc->SGE_size;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005105 }
5106
5107 if (numSGE < sh->sg_tablesize) {
5108 /* Reset this value */
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305109 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005110 "Resetting sg_tablesize to %d from %d\n",
5111 ioc->name, numSGE, sh->sg_tablesize));
5112 sh->sg_tablesize = numSGE;
5113 }
5114
Eric Mooree7eae9f2007-09-29 10:15:59 -06005115 hd = shost_priv(sh);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005116 hd->ioc = ioc;
5117
5118 /* SCSI needs scsi_cmnd lookup table!
5119 * (with size equal to req_depth*PtrSz!)
5120 */
Eric Mooree8206382007-09-29 10:16:53 -06005121 ioc->ScsiLookup = kcalloc(ioc->req_depth, sizeof(void *), GFP_ATOMIC);
5122 if (!ioc->ScsiLookup) {
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005123 error = -ENOMEM;
Eric Moorebc6e0892007-09-29 10:16:28 -06005124 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005125 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005126 }
Eric Mooree8206382007-09-29 10:16:53 -06005127 spin_lock_init(&ioc->scsi_lookup_lock);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005128
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305129 dprintk(ioc, printk(MYIOC_s_DEBUG_FMT "ScsiLookup @ %p\n",
Eric Mooree8206382007-09-29 10:16:53 -06005130 ioc->name, ioc->ScsiLookup));
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005131
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005132 ioc->sas_data.ptClear = mpt_pt_clear;
5133
Eric Mooredf9e0622007-01-29 09:46:21 -07005134 hd->last_queue_full = 0;
5135 INIT_LIST_HEAD(&hd->target_reset_list);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305136 INIT_LIST_HEAD(&ioc->sas_device_info_list);
5137 mutex_init(&ioc->sas_device_info_mutex);
5138
Eric Mooredf9e0622007-01-29 09:46:21 -07005139 spin_unlock_irqrestore(&ioc->FreeQlock, flags);
5140
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005141 if (ioc->sas_data.ptClear==1) {
5142 mptbase_sas_persist_operation(
5143 ioc, MPI_SAS_OP_CLEAR_ALL_PERSISTENT);
5144 }
5145
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005146 error = scsi_add_host(sh, &ioc->pcidev->dev);
5147 if (error) {
Eric Moore29dd3602007-09-14 18:46:51 -06005148 dprintk(ioc, printk(MYIOC_s_ERR_FMT
5149 "scsi_add_host failed\n", ioc->name));
Moore, Eric Dean7acec1e2005-11-16 18:54:17 -07005150 goto out_mptsas_probe;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005151 }
5152
Kashyap, Desaieedf92b2009-05-29 16:51:32 +05305153 /* older firmware doesn't support expander events */
5154 if ((ioc->facts.HeaderVersion >> 8) < 0xE)
5155 ioc->old_sas_discovery_protocal = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005156 mptsas_scan_sas_topology(ioc);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305157 mptsas_fw_event_on(ioc);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005158 return 0;
5159
Eric Moore547f9a22006-06-27 14:42:12 -06005160 out_mptsas_probe:
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005161
5162 mptscsih_remove(pdev);
5163 return error;
5164}
5165
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305166void
5167mptsas_shutdown(struct pci_dev *pdev)
5168{
5169 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5170
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305171 mptsas_fw_event_off(ioc);
5172 mptsas_cleanup_fw_event_q(ioc);
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305173}
5174
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005175static void __devexit mptsas_remove(struct pci_dev *pdev)
5176{
5177 MPT_ADAPTER *ioc = pci_get_drvdata(pdev);
5178 struct mptsas_portinfo *p, *n;
Eric Moore547f9a22006-06-27 14:42:12 -06005179 int i;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005180
Kashyap, Desai48959f12010-03-18 19:18:30 +05305181 if (!ioc->sh) {
5182 printk(MYIOC_s_INFO_FMT "IOC is in Target mode\n", ioc->name);
5183 mpt_detach(pdev);
5184 return;
5185 }
5186
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305187 mptsas_shutdown(pdev);
5188
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305189 mptsas_del_device_components(ioc);
5190
Eric Mooreb506ade2007-01-29 09:45:37 -07005191 ioc->sas_discovery_ignore_events = 1;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005192 sas_remove_host(ioc->sh);
5193
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005194 mutex_lock(&ioc->sas_topology_mutex);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005195 list_for_each_entry_safe(p, n, &ioc->sas_topology, list) {
5196 list_del(&p->list);
Eric Moore547f9a22006-06-27 14:42:12 -06005197 for (i = 0 ; i < p->num_phys ; i++)
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305198 mptsas_port_delete(ioc, p->phy_info[i].port_details);
Kashyap, Desai3eb08222009-05-29 16:47:26 +05305199
Eric Moore547f9a22006-06-27 14:42:12 -06005200 kfree(p->phy_info);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005201 kfree(p);
5202 }
Christoph Hellwig9a28f492006-01-13 18:04:41 +01005203 mutex_unlock(&ioc->sas_topology_mutex);
Kashyap, Desaif9c34022009-05-29 16:49:36 +05305204 ioc->hba_port_info = NULL;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005205 mptscsih_remove(pdev);
5206}
5207
5208static struct pci_device_id mptsas_pci_table[] = {
Eric Moore87cf8982006-06-27 16:09:26 -06005209 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005210 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005211 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005212 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005213 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1064E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005214 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005215 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1068E,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005216 PCI_ANY_ID, PCI_ANY_ID },
Eric Moore87cf8982006-06-27 16:09:26 -06005217 { PCI_VENDOR_ID_LSI_LOGIC, MPI_MANUFACTPAGE_DEVID_SAS1078,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005218 PCI_ANY_ID, PCI_ANY_ID },
5219 {0} /* Terminating entry */
5220};
5221MODULE_DEVICE_TABLE(pci, mptsas_pci_table);
5222
5223
5224static struct pci_driver mptsas_driver = {
5225 .name = "mptsas",
5226 .id_table = mptsas_pci_table,
5227 .probe = mptsas_probe,
5228 .remove = __devexit_p(mptsas_remove),
Kashyap, Desai7b5a65b2009-05-29 16:38:14 +05305229 .shutdown = mptsas_shutdown,
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005230#ifdef CONFIG_PM
5231 .suspend = mptscsih_suspend,
5232 .resume = mptscsih_resume,
5233#endif
5234};
5235
5236static int __init
5237mptsas_init(void)
5238{
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305239 int error;
5240
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005241 show_mptmod_ver(my_NAME, my_VERSION);
5242
5243 mptsas_transport_template =
5244 sas_attach_transport(&mptsas_transport_functions);
5245 if (!mptsas_transport_template)
5246 return -ENODEV;
5247
5248 mptsasDoneCtx = mpt_register(mptscsih_io_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305249 mptsasTaskCtx = mpt_register(mptscsih_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005250 mptsasInternalCtx =
5251 mpt_register(mptscsih_scandv_complete, MPTSAS_DRIVER);
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005252 mptsasMgmtCtx = mpt_register(mptsas_mgmt_done, MPTSAS_DRIVER);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305253 mptsasDeviceResetCtx =
5254 mpt_register(mptsas_taskmgmt_complete, MPTSAS_DRIVER);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005255
Prakash, Sathyad6ecdd62007-07-24 15:47:41 +05305256 mpt_event_register(mptsasDoneCtx, mptsas_event_process);
5257 mpt_reset_register(mptsasDoneCtx, mptsas_ioc_reset);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005258
Prakash, Sathya57ce21b2007-07-02 17:04:10 +05305259 error = pci_register_driver(&mptsas_driver);
5260 if (error)
5261 sas_release_transport(mptsas_transport_template);
5262
5263 return error;
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005264}
5265
5266static void __exit
5267mptsas_exit(void)
5268{
5269 pci_unregister_driver(&mptsas_driver);
5270 sas_release_transport(mptsas_transport_template);
5271
5272 mpt_reset_deregister(mptsasDoneCtx);
5273 mpt_event_deregister(mptsasDoneCtx);
5274
Christoph Hellwigda4fa652005-10-19 20:01:42 +02005275 mpt_deregister(mptsasMgmtCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005276 mpt_deregister(mptsasInternalCtx);
5277 mpt_deregister(mptsasTaskCtx);
5278 mpt_deregister(mptsasDoneCtx);
Kashyap, Desaie7deff32009-05-29 16:46:07 +05305279 mpt_deregister(mptsasDeviceResetCtx);
Christoph Hellwig0c33b272005-09-09 16:27:19 +02005280}
5281
5282module_init(mptsas_init);
5283module_exit(mptsas_exit);