mptsas_raid.c revision 9907:98086c85a8f7
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Copyright (c) 2000 to 2009, LSI Corporation.
29 * All rights reserved.
30 *
31 * Redistribution and use in source and binary forms of all code within
32 * this file that is exclusively owned by LSI, with or without
33 * modification, is permitted provided that, in addition to the CDDL 1.0
34 * License requirements, the following conditions are met:
35 *
36 *    Neither the name of the author nor the names of its contributors may be
37 *    used to endorse or promote products derived from this software without
38 *    specific prior written permission.
39 *
40 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
41 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
42 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
43 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
44 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
45 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
46 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
47 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
48 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
51 * DAMAGE.
52 */
53
54/*
55 * mptsas_raid - This file contains all the RAID related functions for the
56 * MPT interface.
57 */
58
59#if defined(lint) || defined(DEBUG)
60#define	MPTSAS_DEBUG
61#endif
62
63#define	MPI_RAID_VOL_PAGE_0_PHYSDISK_MAX	2
64
65/*
66 * standard header files
67 */
68#include <sys/note.h>
69#include <sys/scsi/scsi.h>
70#include <sys/byteorder.h>
71#include <sys/raidioctl.h>
72
73#pragma pack(1)
74
75#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_type.h>
76#include <sys/scsi/adapters/mpt_sas/mpi/mpi2.h>
77#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_cnfg.h>
78#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_init.h>
79#include <sys/scsi/adapters/mpt_sas/mpi/mpi2_ioc.h>
80
81#pragma pack()
82
83/*
84 * private header files.
85 */
86#include <sys/scsi/adapters/mpt_sas/mptsas_var.h>
87
88static int mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol);
89
90extern int mptsas_check_dma_handle(ddi_dma_handle_t handle);
91extern int mptsas_check_acc_handle(ddi_acc_handle_t handle);
92extern mptsas_target_t *mptsas_tgt_alloc(mptsas_hash_table_t *, uint16_t,
93    uint64_t, uint32_t, uint8_t, uint8_t);
94
95static int
96mptsas_raidconf_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
97    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
98    va_list ap)
99{
100#ifndef __lock_lint
101	_NOTE(ARGUNUSED(ap))
102#endif
103	pMpi2RaidConfigurationPage0_t	raidconfig_page0;
104	pMpi2RaidConfig0ConfigElement_t	element;
105	uint32_t *confignum;
106	int rval = DDI_SUCCESS, i;
107	uint8_t numelements, vol, disk;
108	uint16_t elementtype, voldevhandle;
109	uint16_t etype_vol, etype_pd, etype_hs;
110	uint16_t etype_oce;
111	mptsas_slots_t *slots = mpt->m_active;
112	m_raidconfig_t *raidconfig;
113	uint64_t raidwwn;
114	uint32_t native;
115	mptsas_target_t	*ptgt;
116	uint32_t configindex;
117
118	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE) {
119		return (DDI_FAILURE);
120	}
121
122	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
123		mptsas_log(mpt, CE_WARN, "mptsas_get_raid_conf_page0 "
124		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
125		    iocstatus, iocloginfo);
126		rval = DDI_FAILURE;
127		return (rval);
128	}
129	confignum = va_arg(ap,  uint32_t *);
130	configindex = va_arg(ap, uint32_t);
131	raidconfig_page0 = (pMpi2RaidConfigurationPage0_t)page_memp;
132	/*
133	 * Get all RAID configurations.
134	 */
135	etype_vol = MPI2_RAIDCONFIG0_EFLAGS_VOLUME_ELEMENT;
136	etype_pd = MPI2_RAIDCONFIG0_EFLAGS_VOL_PHYS_DISK_ELEMENT;
137	etype_hs = MPI2_RAIDCONFIG0_EFLAGS_HOT_SPARE_ELEMENT;
138	etype_oce = MPI2_RAIDCONFIG0_EFLAGS_OCE_ELEMENT;
139	/*
140	 * Set up page address for next time through.
141	 */
142	*confignum =  ddi_get8(accessp,
143	    &raidconfig_page0->ConfigNum);
144
145	/*
146	 * Point to the right config in the structure.
147	 * Increment the number of valid RAID configs.
148	 */
149	raidconfig = &slots->m_raidconfig[configindex];
150	slots->m_num_raid_configs++;
151
152	/*
153	 * Set the native flag if this is not a foreign
154	 * configuration.
155	 */
156	native = ddi_get32(accessp, &raidconfig_page0->Flags);
157	if (native & MPI2_RAIDCONFIG0_FLAG_FOREIGN_CONFIG) {
158		native = FALSE;
159	} else {
160		native = TRUE;
161	}
162	raidconfig->m_native = (uint8_t)native;
163
164	/*
165	 * Get volume information for the volumes in the
166	 * config.
167	 */
168	numelements = ddi_get8(accessp, &raidconfig_page0->NumElements);
169	vol = 0;
170	disk = 0;
171	element = (pMpi2RaidConfig0ConfigElement_t)
172	    &raidconfig_page0->ConfigElement;
173
174	for (i = 0; i < numelements; i++, element++) {
175		/*
176		 * Get the element type.  Could be Volume,
177		 * PhysDisk, Hot Spare, or Online Capacity
178		 * Expansion PhysDisk.
179		 */
180		elementtype = ddi_get16(accessp, &element->ElementFlags);
181		elementtype &= MPI2_RAIDCONFIG0_EFLAGS_MASK_ELEMENT_TYPE;
182
183		/*
184		 * For volumes, get the RAID settings and the
185		 * WWID.
186		 */
187		if (elementtype == etype_vol) {
188			voldevhandle = ddi_get16(accessp,
189			    &element->VolDevHandle);
190			raidconfig->m_raidvol[vol].m_israid = 1;
191			raidconfig->m_raidvol[vol].
192			    m_raidhandle = voldevhandle;
193			/*
194			 * Get the settings for the raid
195			 * volume.  This includes the
196			 * DevHandles for the disks making up
197			 * the raid volume.
198			 */
199			if (mptsas_get_raid_settings(mpt,
200			    &raidconfig->m_raidvol[vol]))
201				continue;
202
203			/*
204			 * Get the WWID of the RAID volume for
205			 * SAS HBA
206			 */
207			if (mptsas_get_raid_wwid(mpt,
208			    &raidconfig->m_raidvol[vol]))
209				continue;
210
211			raidwwn = raidconfig->m_raidvol[vol].
212			    m_raidwwid;
213
214			/*
215			 * RAID uses phymask of 0.
216			 */
217			ptgt = mptsas_tgt_alloc(&slots->m_tgttbl,
218			    voldevhandle, raidwwn, 0, 0, 0);
219
220			raidconfig->m_raidvol[vol].m_raidtgt =
221			    ptgt;
222
223			/*
224			 * Increment volume index within this
225			 * raid config.
226			 */
227			vol++;
228		} else if ((elementtype == etype_pd) ||
229		    (elementtype == etype_hs) ||
230		    (elementtype == etype_oce)) {
231			/*
232			 * For all other element types, put
233			 * their DevHandles in the phys disk
234			 * list of the config.  These are all
235			 * some variation of a Phys Disk and
236			 * this list is used to keep these
237			 * disks from going online.
238			 */
239			raidconfig->m_physdisk_devhdl[disk] = ddi_get16(accessp,
240			    &element->PhysDiskDevHandle);
241
242			/*
243			 * Increment disk index within this
244			 * raid config.
245			 */
246			disk++;
247		}
248	}
249
250	return (rval);
251}
252
253int
254mptsas_get_raid_info(mptsas_t *mpt)
255{
256	int rval = DDI_SUCCESS;
257	uint32_t confignum, pageaddress;
258	uint8_t configindex;
259	mptsas_slots_t *slots = mpt->m_active;
260
261	ASSERT(mutex_owned(&mpt->m_mutex));
262
263	/*
264	 * Clear all RAID info before starting.
265	 */
266	bzero(slots->m_raidconfig, sizeof (slots->m_raidconfig));
267	slots->m_num_raid_configs = 0;
268
269	configindex = 0;
270	confignum = 0xff;
271	pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM | confignum;
272	while (rval == DDI_SUCCESS) {
273		/*
274		 * Get the header and config page.  reply contains the reply
275		 * frame, which holds status info for the request.
276		 */
277		rval = mptsas_access_config_page(mpt,
278		    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
279		    MPI2_CONFIG_EXTPAGETYPE_RAID_CONFIG, 0, pageaddress,
280		    mptsas_raidconf_page_0_cb, &confignum, configindex);
281		configindex++;
282		pageaddress = MPI2_RAID_PGAD_FORM_GET_NEXT_CONFIGNUM |
283		    confignum;
284	}
285
286	return (rval);
287}
288
289static int
290mptsas_raidvol_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
291    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
292    va_list ap)
293{
294#ifndef __lock_lint
295	_NOTE(ARGUNUSED(ap))
296#endif
297	pMpi2RaidVolPage0_t raidpage;
298	int rval = DDI_SUCCESS, i;
299	mptsas_raidvol_t *raidvol;
300	uint8_t	numdisks, volstate, voltype, physdisknum;
301	uint32_t volsetting;
302	uint32_t statusflags, resync_flag;
303
304	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
305		return (DDI_FAILURE);
306
307	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
308		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page0_cb "
309		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
310		    iocstatus, iocloginfo);
311		rval = DDI_FAILURE;
312		return (rval);
313	}
314
315	raidvol = va_arg(ap,  mptsas_raidvol_t *);
316
317	raidpage = (pMpi2RaidVolPage0_t)page_memp;
318	volstate = ddi_get8(accessp, &raidpage->VolumeState);
319	volsetting = ddi_get32(accessp,
320	    (uint32_t *)(void *)&raidpage->VolumeSettings);
321	statusflags = ddi_get32(accessp, &raidpage->VolumeStatusFlags);
322	voltype = ddi_get8(accessp, &raidpage->VolumeType);
323
324	raidvol->m_state = volstate;
325	raidvol->m_statusflags = statusflags;
326	/*
327	 * Volume size is not used right now. Set to 0.
328	 */
329	raidvol->m_raidsize = 0;
330	raidvol->m_settings = volsetting;
331	raidvol->m_raidlevel = voltype;
332
333	if (statusflags & MPI2_RAIDVOL0_STATUS_FLAG_QUIESCED) {
334		mptsas_log(mpt, CE_NOTE, "?Volume %d is quiesced\n",
335		    raidvol->m_raidhandle);
336	}
337
338	if (statusflags &
339	    MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS) {
340		mptsas_log(mpt, CE_NOTE, "?Volume %d is resyncing\n",
341		    raidvol->m_raidhandle);
342	}
343
344	resync_flag = MPI2_RAIDVOL0_STATUS_FLAG_RESYNC_IN_PROGRESS;
345	switch (volstate) {
346	case MPI2_RAID_VOL_STATE_OPTIMAL:
347		mptsas_log(mpt, CE_NOTE, "?Volume %d is "
348		    "optimal\n", raidvol->m_raidhandle);
349		break;
350	case MPI2_RAID_VOL_STATE_DEGRADED:
351		if ((statusflags & resync_flag) == 0) {
352			mptsas_log(mpt, CE_WARN, "Volume %d "
353			    "is degraded\n",
354			    raidvol->m_raidhandle);
355		}
356		break;
357	case MPI2_RAID_VOL_STATE_FAILED:
358		mptsas_log(mpt, CE_WARN, "Volume %d is "
359		    "failed\n", raidvol->m_raidhandle);
360		break;
361	case MPI2_RAID_VOL_STATE_MISSING:
362		mptsas_log(mpt, CE_WARN, "Volume %d is "
363		    "missing\n", raidvol->m_raidhandle);
364		break;
365	default:
366		break;
367	}
368	numdisks = raidpage->NumPhysDisks;
369	raidvol->m_ndisks = numdisks;
370	for (i = 0; i < numdisks; i++) {
371		physdisknum = raidpage->PhysDisk[i].PhysDiskNum;
372		raidvol->m_disknum[i] = physdisknum;
373		if (mptsas_get_physdisk_settings(mpt, raidvol,
374		    physdisknum))
375			break;
376	}
377	return (rval);
378}
379
380int
381mptsas_get_raid_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
382{
383	int rval = DDI_SUCCESS;
384	uint32_t page_address;
385
386	ASSERT(mutex_owned(&mpt->m_mutex));
387
388	/*
389	 * Get the header and config page.  reply contains the reply frame,
390	 * which holds status info for the request.
391	 */
392	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
393	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
394	rval = mptsas_access_config_page(mpt,
395	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
396	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 0, page_address,
397	    mptsas_raidvol_page_0_cb, raidvol);
398
399	return (rval);
400}
401
402static int
403mptsas_raidvol_page_1_cb(mptsas_t *mpt, caddr_t page_memp,
404    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
405    va_list ap)
406{
407#ifndef __lock_lint
408	_NOTE(ARGUNUSED(ap))
409#endif
410	pMpi2RaidVolPage1_t	raidpage;
411	int			rval = DDI_SUCCESS, i;
412	uint8_t			*sas_addr = NULL;
413	uint8_t			tmp_sas_wwn[SAS_WWN_BYTE_SIZE];
414	uint64_t		*sas_wwn;
415
416	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
417		mptsas_log(mpt, CE_WARN, "mptsas_raidvol_page_1_cb "
418		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
419		    iocstatus, iocloginfo);
420		rval = DDI_FAILURE;
421		return (rval);
422	}
423	sas_wwn = va_arg(ap, uint64_t *);
424
425	raidpage = (pMpi2RaidVolPage1_t)page_memp;
426	sas_addr = (uint8_t *)(&raidpage->WWID);
427	for (i = 0; i < SAS_WWN_BYTE_SIZE; i++) {
428		tmp_sas_wwn[i] = ddi_get8(accessp, sas_addr + i);
429	}
430	bcopy(tmp_sas_wwn, sas_wwn, SAS_WWN_BYTE_SIZE);
431	*sas_wwn = LE_64(*sas_wwn);
432	return (rval);
433}
434
435static int
436mptsas_get_raid_wwid(mptsas_t *mpt, mptsas_raidvol_t *raidvol)
437{
438	int rval = DDI_SUCCESS;
439	uint32_t page_address;
440	uint64_t sas_wwn;
441
442	ASSERT(mutex_owned(&mpt->m_mutex));
443
444	/*
445	 * Get the header and config page.  reply contains the reply frame,
446	 * which holds status info for the request.
447	 */
448	page_address = (MPI2_RAID_VOLUME_PGAD_FORM_MASK &
449	    MPI2_RAID_VOLUME_PGAD_FORM_HANDLE) | raidvol->m_raidhandle;
450	rval = mptsas_access_config_page(mpt,
451	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
452	    MPI2_CONFIG_PAGETYPE_RAID_VOLUME, 1, page_address,
453	    mptsas_raidvol_page_1_cb, &sas_wwn);
454
455	/*
456	 * Get the required information from the page.
457	 */
458	if (rval == DDI_SUCCESS) {
459
460		/*
461		 * replace top nibble of WWID of RAID to '3' for OBP
462		 */
463		sas_wwn = MPTSAS_RAID_WWID(sas_wwn);
464		raidvol->m_raidwwid = sas_wwn;
465	}
466
467done:
468	return (rval);
469}
470
471static int
472mptsas_raidphydsk_page_0_cb(mptsas_t *mpt, caddr_t page_memp,
473    ddi_acc_handle_t accessp, uint16_t iocstatus, uint32_t iocloginfo,
474    va_list ap)
475{
476#ifndef __lock_lint
477	_NOTE(ARGUNUSED(ap))
478#endif
479	pMpi2RaidPhysDiskPage0_t	diskpage;
480	int			rval = DDI_SUCCESS;
481	uint16_t		*devhdl;
482	uint8_t			*state;
483
484	if (iocstatus == MPI2_IOCSTATUS_CONFIG_INVALID_PAGE)
485		return (DDI_FAILURE);
486
487	if (iocstatus != MPI2_IOCSTATUS_SUCCESS) {
488		mptsas_log(mpt, CE_WARN, "mptsas_raidphydsk_page0_cb "
489		    "config: IOCStatus=0x%x, IOCLogInfo=0x%x",
490		    iocstatus, iocloginfo);
491		rval = DDI_FAILURE;
492		return (rval);
493	}
494	devhdl = va_arg(ap, uint16_t *);
495	state = va_arg(ap, uint8_t *);
496	diskpage = (pMpi2RaidPhysDiskPage0_t)page_memp;
497	*devhdl = ddi_get16(accessp, &diskpage->DevHandle);
498	*state = ddi_get8(accessp, &diskpage->PhysDiskState);
499	return (rval);
500}
501
502int
503mptsas_get_physdisk_settings(mptsas_t *mpt, mptsas_raidvol_t *raidvol,
504    uint8_t physdisknum)
505{
506	int			rval = DDI_SUCCESS, i;
507	uint8_t			state;
508	uint16_t		devhdl;
509	uint32_t		page_address;
510
511	ASSERT(mutex_owned(&mpt->m_mutex));
512
513	/*
514	 * Get the header and config page.  reply contains the reply frame,
515	 * which holds status info for the request.
516	 */
517	page_address = (MPI2_PHYSDISK_PGAD_FORM_MASK &
518	    MPI2_PHYSDISK_PGAD_FORM_PHYSDISKNUM) | physdisknum;
519	rval = mptsas_access_config_page(mpt,
520	    MPI2_CONFIG_ACTION_PAGE_READ_CURRENT,
521	    MPI2_CONFIG_PAGETYPE_RAID_PHYSDISK, 0, page_address,
522	    mptsas_raidphydsk_page_0_cb, &devhdl, &state);
523
524	/*
525	 * Get the required information from the page.
526	 */
527	if (rval == DDI_SUCCESS) {
528		for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
529			/* find the correct position in the arrays */
530			if (raidvol->m_disknum[i] == physdisknum)
531				break;
532		}
533		raidvol->m_devhdl[i] = devhdl;
534
535		switch (state) {
536			case MPI2_RAID_PD_STATE_OFFLINE:
537				raidvol->m_diskstatus[i] =
538				    RAID_DISKSTATUS_FAILED;
539				break;
540
541			case MPI2_RAID_PD_STATE_HOT_SPARE:
542			case MPI2_RAID_PD_STATE_NOT_CONFIGURED:
543			case MPI2_RAID_PD_STATE_NOT_COMPATIBLE:
544				break;
545
546			case MPI2_RAID_PD_STATE_DEGRADED:
547			case MPI2_RAID_PD_STATE_OPTIMAL:
548			case MPI2_RAID_PD_STATE_REBUILDING:
549			case MPI2_RAID_PD_STATE_ONLINE:
550			default:
551				raidvol->m_diskstatus[i] =
552				    RAID_DISKSTATUS_GOOD;
553				break;
554		}
555	}
556
557	return (rval);
558}
559
560int
561mptsas_delete_volume(mptsas_t *mpt, uint16_t volid)
562{
563	int		config, i, vol = (-1);
564	mptsas_slots_t	*slots = mpt->m_active;
565
566	for (config = 0; config < slots->m_num_raid_configs; config++) {
567		for (i = 0; i < MPTSAS_MAX_RAIDVOLS; i++) {
568			if (slots->m_raidconfig[config].m_raidvol[i].
569			    m_raidhandle == volid) {
570				vol = i;
571				break;
572			}
573		}
574	}
575
576	if (vol < 0) {
577		mptsas_log(mpt, CE_WARN, "raid doesn't exist at specified "
578		    "target.");
579		return (-1);
580	}
581
582	slots->m_raidconfig[config].m_raidvol[vol].m_israid = 0;
583	slots->m_raidconfig[config].m_raidvol[vol].m_ndisks = 0;
584	for (i = 0; i < MPTSAS_MAX_DISKS_IN_VOL; i++) {
585		slots->m_raidconfig[config].m_raidvol[vol].m_disknum[i] = 0;
586		slots->m_raidconfig[config].m_raidvol[vol].m_devhdl[i] = 0;
587	}
588
589	return (0);
590}
591