1158115Sume/*- 2158115Sume * Copyright (c) 2008 Yahoo!, Inc. 3158115Sume * All rights reserved. 4158115Sume * Written by: John Baldwin <jhb@FreeBSD.org> 5158115Sume * 6158115Sume * Redistribution and use in source and binary forms, with or without 7158115Sume * modification, are permitted provided that the following conditions 8158115Sume * are met: 9158115Sume * 1. Redistributions of source code must retain the above copyright 10158115Sume * notice, this list of conditions and the following disclaimer. 11158115Sume * 2. Redistributions in binary form must reproduce the above copyright 12158115Sume * notice, this list of conditions and the following disclaimer in the 13158115Sume * documentation and/or other materials provided with the distribution. 14158115Sume * 3. Neither the name of the author nor the names of any co-contributors 15158115Sume * may be used to endorse or promote products derived from this software 16158115Sume * without specific prior written permission. 17158115Sume * 18158115Sume * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19158115Sume * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20158115Sume * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21158115Sume * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22158115Sume * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23158115Sume * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24158115Sume * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25158115Sume * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26158115Sume * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27158115Sume * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28158115Sume * SUCH DAMAGE. 29158115Sume */ 30158115Sume 31194089Sdes#include <sys/cdefs.h> 32194089Sdes__RCSID("$FreeBSD$"); 33158115Sume 34158115Sume#include <sys/param.h> 35194089Sdes#include <err.h> 36158115Sume#include <errno.h> 37194089Sdes#include <fcntl.h> 38158115Sume#include <stdio.h> 39158115Sume#include <stdlib.h> 40158115Sume#include <string.h> 41158115Sume 42158115Sume#include <camlib.h> 43158115Sume#include <cam/scsi/scsi_message.h> 44158115Sume#include <cam/scsi/scsi_pass.h> 45158115Sume 46158115Sume#include "mptutil.h" 47158115Sume 48158115Sumestatic int xptfd; 49158115Sume 50158115Sumestatic int 51158115Sumexpt_open(void) 52158115Sume{ 53158115Sume 54158115Sume if (xptfd == 0) 55158115Sume xptfd = open(XPT_DEVICE, O_RDWR); 56158115Sume return (xptfd); 57158115Sume} 58158115Sume 59158115Sume/* Fetch the path id of bus 0 for the opened mpt controller. */ 60158115Sumestatic int 61158115Sumefetch_path_id(path_id_t *path_id) 62158115Sume{ 63158115Sume struct bus_match_pattern *b; 64158115Sume union ccb ccb; 65158115Sume size_t bufsize; 66158115Sume int error; 67158115Sume 68158115Sume if (xpt_open() < 0) 69158115Sume return (ENXIO); 70158115Sume 71158115Sume /* First, find the path id of bus 0 for this mpt controller. */ 72158115Sume bzero(&ccb, sizeof(ccb)); 73158115Sume 74158115Sume ccb.ccb_h.func_code = XPT_DEV_MATCH; 75158115Sume 76158115Sume bufsize = sizeof(struct dev_match_result) * 1; 77158115Sume ccb.cdm.num_matches = 0; 78158115Sume ccb.cdm.match_buf_len = bufsize; 79158115Sume ccb.cdm.matches = calloc(1, bufsize); 80158115Sume 81158115Sume bufsize = sizeof(struct dev_match_pattern) * 1; 82158115Sume ccb.cdm.num_patterns = 1; 83158115Sume ccb.cdm.pattern_buf_len = bufsize; 84158115Sume ccb.cdm.patterns = calloc(1, bufsize); 85158115Sume 86158115Sume /* Match mptX bus 0. */ 87158115Sume ccb.cdm.patterns[0].type = DEV_MATCH_BUS; 88158115Sume b = &ccb.cdm.patterns[0].pattern.bus_pattern; 89158115Sume snprintf(b->dev_name, sizeof(b->dev_name), "mpt"); 90158115Sume b->unit_number = mpt_unit; 91158115Sume b->bus_id = 0; 92158115Sume b->flags = BUS_MATCH_NAME | BUS_MATCH_UNIT | BUS_MATCH_BUS_ID; 93158115Sume 94158115Sume if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) { 95158115Sume error = errno; 96158115Sume free(ccb.cdm.matches); 97158115Sume free(ccb.cdm.patterns); 98158115Sume return (error); 99158115Sume } 100158115Sume free(ccb.cdm.patterns); 101158115Sume 102158115Sume if (((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) || 103158115Sume (ccb.cdm.status != CAM_DEV_MATCH_LAST)) { 104158115Sume warnx("fetch_path_id got CAM error %#x, CDM error %d\n", 105158115Sume ccb.ccb_h.status, ccb.cdm.status); 106158115Sume free(ccb.cdm.matches); 107158115Sume return (EIO); 108158115Sume } 109158115Sume 110158115Sume /* We should have exactly 1 match for the bus. */ 111158115Sume if (ccb.cdm.num_matches != 1 || 112158115Sume ccb.cdm.matches[0].type != DEV_MATCH_BUS) { 113158115Sume free(ccb.cdm.matches); 114158115Sume return (ENOENT); 115158115Sume } 116158115Sume *path_id = ccb.cdm.matches[0].result.bus_result.path_id; 117158115Sume free(ccb.cdm.matches); 118158115Sume return (0); 119158115Sume} 120158115Sume 121158115Sumeint 122158115Sumempt_query_disk(U8 VolumeBus, U8 VolumeID, struct mpt_query_disk *qd) 123158115Sume{ 124158115Sume struct periph_match_pattern *p; 125158115Sume struct periph_match_result *r; 126158115Sume union ccb ccb; 127158115Sume path_id_t path_id; 128158115Sume size_t bufsize; 129158115Sume int error; 130158115Sume 131158115Sume /* mpt(4) only handles devices on bus 0. */ 132158115Sume if (VolumeBus != 0) 133158115Sume return (ENXIO); 134158115Sume 135158115Sume if (xpt_open() < 0) 136158115Sume return (ENXIO); 137158115Sume 138158115Sume /* Find the path ID of bus 0. */ 139158115Sume error = fetch_path_id(&path_id); 140158115Sume if (error) 141158115Sume return (error); 142158115Sume 143158115Sume bzero(&ccb, sizeof(ccb)); 144158115Sume 145158115Sume ccb.ccb_h.func_code = XPT_DEV_MATCH; 146158115Sume ccb.ccb_h.path_id = CAM_XPT_PATH_ID; 147158115Sume ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 148158115Sume ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 149158115Sume 150158115Sume bufsize = sizeof(struct dev_match_result) * 5; 151158115Sume ccb.cdm.num_matches = 0; 152158115Sume ccb.cdm.match_buf_len = bufsize; 153158115Sume ccb.cdm.matches = calloc(1, bufsize); 154158115Sume 155158115Sume bufsize = sizeof(struct dev_match_pattern) * 1; 156158115Sume ccb.cdm.num_patterns = 1; 157158115Sume ccb.cdm.pattern_buf_len = bufsize; 158158115Sume ccb.cdm.patterns = calloc(1, bufsize); 159158115Sume 160158115Sume /* Look for a "da" device at the specified target and lun. */ 161158115Sume ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH; 162158115Sume p = &ccb.cdm.patterns[0].pattern.periph_pattern; 163158115Sume p->path_id = path_id; 164158115Sume snprintf(p->periph_name, sizeof(p->periph_name), "da"); 165158115Sume p->target_id = VolumeID; 166158115Sume p->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_NAME | PERIPH_MATCH_TARGET; 167158115Sume 168158115Sume if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) { 169158115Sume error = errno; 170238094Sse free(ccb.cdm.matches); 171238094Sse free(ccb.cdm.patterns); 172238094Sse return (error); 173238094Sse } 174238094Sse free(ccb.cdm.patterns); 175238094Sse 176238094Sse if (((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) || 177238094Sse (ccb.cdm.status != CAM_DEV_MATCH_LAST)) { 178238094Sse warnx("mpt_query_disk got CAM error %#x, CDM error %d\n", 179238094Sse ccb.ccb_h.status, ccb.cdm.status); 180238094Sse free(ccb.cdm.matches); 181238094Sse return (EIO); 182238094Sse } 183238094Sse 184238094Sse /* 185238094Sse * We should have exactly 1 match for the peripheral. 186238094Sse * However, if we don't get a match, don't print an error 187238094Sse * message and return ENOENT. 188238094Sse */ 189238094Sse if (ccb.cdm.num_matches == 0) { 190238094Sse free(ccb.cdm.matches); 191238094Sse return (ENOENT); 192238094Sse } 193238094Sse if (ccb.cdm.num_matches != 1) { 194238094Sse warnx("mpt_query_disk got %d matches, expected 1", 195238094Sse ccb.cdm.num_matches); 196238094Sse free(ccb.cdm.matches); 197238094Sse return (EIO); 198238094Sse } 199238094Sse if (ccb.cdm.matches[0].type != DEV_MATCH_PERIPH) { 200238094Sse warnx("mpt_query_disk got wrong CAM match"); 201238094Sse free(ccb.cdm.matches); 202158115Sume return (EIO); 203158115Sume } 204158115Sume 205158115Sume /* Copy out the data. */ 206158115Sume r = &ccb.cdm.matches[1].result.periph_result; 207158115Sume snprintf(qd->devname, sizeof(qd->devname), "%s%d", r->periph_name, 208158115Sume r->unit_number); 209158115Sume free(ccb.cdm.matches); 210158115Sume 211158115Sume return (0); 212158115Sume} 213158115Sume 214158115Sumestatic int 215158115Sumeperiph_is_volume(CONFIG_PAGE_IOC_2 *ioc2, struct periph_match_result *r) 216158115Sume{ 217158115Sume CONFIG_PAGE_IOC_2_RAID_VOL *vol; 218158115Sume int i; 219158115Sume 220158115Sume if (ioc2 == NULL) 221158115Sume return (0); 222158115Sume vol = ioc2->RaidVolume; 223158115Sume for (i = 0; i < ioc2->NumActiveVolumes; vol++, i++) { 224158115Sume if (vol->VolumeBus == 0 && vol->VolumeID == r->target_id) 225158115Sume return (1); 226158115Sume } 227158115Sume return (0); 228158115Sume} 229158115Sume 230158115Sume/* Much borrowed from scsireadcapacity() in src/sbin/camcontrol/camcontrol.c. */ 231158115Sumestatic int 232158115Sumefetch_scsi_capacity(struct cam_device *dev, struct mpt_standalone_disk *disk) 233158115Sume{ 234158115Sume struct scsi_read_capacity_data rcap; 235158115Sume struct scsi_read_capacity_data_long rcaplong; 236158115Sume union ccb *ccb; 237158115Sume int error; 238158115Sume 239158115Sume ccb = cam_getccb(dev); 240158115Sume if (ccb == NULL) 241158115Sume return (ENOMEM); 242158115Sume 243158115Sume /* Zero the rest of the ccb. */ 244158115Sume bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - 245158115Sume sizeof(struct ccb_hdr)); 246158115Sume 247158115Sume scsi_read_capacity(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, &rcap, 248158115Sume SSD_FULL_SIZE, 5000); 249158115Sume 250158115Sume /* Disable freezing the device queue */ 251158115Sume ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 252158115Sume 253158115Sume if (cam_send_ccb(dev, ccb) < 0) { 254158115Sume error = errno; 255158115Sume cam_freeccb(ccb); 256158115Sume return (error); 257158115Sume } 258158115Sume 259158115Sume if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 260158115Sume cam_freeccb(ccb); 261158115Sume return (EIO); 262158115Sume } 263158115Sume cam_freeccb(ccb); 264158115Sume 265158115Sume /* 266158115Sume * A last block of 2^32-1 means that the true capacity is over 2TB, 267158115Sume * and we need to issue the long READ CAPACITY to get the real 268158115Sume * capacity. Otherwise, we're all set. 269158115Sume */ 270158115Sume if (scsi_4btoul(rcap.addr) != 0xffffffff) { 271158115Sume disk->maxlba = scsi_4btoul(rcap.addr); 272158115Sume return (0); 273158115Sume } 274158115Sume 275158115Sume /* Zero the rest of the ccb. */ 276158115Sume bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - 277158115Sume sizeof(struct ccb_hdr)); 278158115Sume 279158115Sume scsi_read_capacity_16(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, 0, 0, 0, 280158115Sume (uint8_t *)&rcaplong, sizeof(rcaplong), SSD_FULL_SIZE, 5000); 281158115Sume 282158115Sume /* Disable freezing the device queue */ 283158115Sume ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 284158115Sume 285158115Sume if (cam_send_ccb(dev, ccb) < 0) { 286158115Sume error = errno; 287158115Sume cam_freeccb(ccb); 288158115Sume return (error); 289158115Sume } 290158115Sume 291158115Sume if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 292158115Sume cam_freeccb(ccb); 293158115Sume return (EIO); 294158115Sume } 295158115Sume cam_freeccb(ccb); 296158115Sume 297158115Sume disk->maxlba = scsi_8btou64(rcaplong.addr); 298158115Sume return (0); 299158115Sume} 300158115Sume 301158115Sume/* Borrowed heavily from scsi_all.c:scsi_print_inquiry(). */ 302158115Sumestatic void 303158115Sumeformat_scsi_inquiry(struct mpt_standalone_disk *disk, 304158115Sume struct scsi_inquiry_data *inq_data) 305158115Sume{ 306158115Sume char vendor[16], product[48], revision[16], rstr[12]; 307158115Sume 308158115Sume if (SID_QUAL_IS_VENDOR_UNIQUE(inq_data)) 309158115Sume return; 310158115Sume if (SID_TYPE(inq_data) != T_DIRECT) 311158115Sume return; 312158115Sume if (SID_QUAL(inq_data) != SID_QUAL_LU_CONNECTED) 313158115Sume return; 314158115Sume 315158115Sume cam_strvis(vendor, inq_data->vendor, sizeof(inq_data->vendor), 316158115Sume sizeof(vendor)); 317158115Sume cam_strvis(product, inq_data->product, sizeof(inq_data->product), 318158115Sume sizeof(product)); 319158115Sume cam_strvis(revision, inq_data->revision, sizeof(inq_data->revision), 320158115Sume sizeof(revision)); 321158115Sume 322158115Sume /* Hack for SATA disks, no idea how to tell speed. */ 323158115Sume if (strcmp(vendor, "ATA") == 0) { 324158115Sume snprintf(disk->inqstring, sizeof(disk->inqstring), 325158115Sume "<%s %s> SATA", product, revision); 326158115Sume return; 327158115Sume } 328158115Sume 329158115Sume switch (SID_ANSI_REV(inq_data)) { 330158115Sume case SCSI_REV_CCS: 331158115Sume strcpy(rstr, "SCSI-CCS"); 332158115Sume break; 333158115Sume case 5: 334158115Sume strcpy(rstr, "SAS"); 335158115Sume break; 336158115Sume default: 337158115Sume snprintf(rstr, sizeof (rstr), "SCSI-%d", 338158115Sume SID_ANSI_REV(inq_data)); 339158115Sume break; 340158115Sume } 341158115Sume snprintf(disk->inqstring, sizeof(disk->inqstring), "<%s %s %s> %s", 342158115Sume vendor, product, revision, rstr); 343158115Sume} 344158115Sume 345158115Sume/* Much borrowed from scsiinquiry() in src/sbin/camcontrol/camcontrol.c. */ 346158115Sumestatic int 347158115Sumefetch_scsi_inquiry(struct cam_device *dev, struct mpt_standalone_disk *disk) 348158115Sume{ 349158115Sume struct scsi_inquiry_data *inq_buf; 350158115Sume union ccb *ccb; 351158115Sume int error; 352158115Sume 353158115Sume ccb = cam_getccb(dev); 354158115Sume if (ccb == NULL) 355158115Sume return (ENOMEM); 356158115Sume 357158115Sume /* Zero the rest of the ccb. */ 358158115Sume bzero(&(&ccb->ccb_h)[1], sizeof(struct ccb_scsiio) - 359158115Sume sizeof(struct ccb_hdr)); 360158115Sume 361158115Sume inq_buf = calloc(1, sizeof(*inq_buf)); 362158115Sume if (inq_buf == NULL) { 363158115Sume cam_freeccb(ccb); 364158115Sume return (ENOMEM); 365158115Sume } 366158115Sume scsi_inquiry(&ccb->csio, 1, NULL, MSG_SIMPLE_Q_TAG, (void *)inq_buf, 367158115Sume SHORT_INQUIRY_LENGTH, 0, 0, SSD_FULL_SIZE, 5000); 368158115Sume 369158115Sume /* Disable freezing the device queue */ 370158115Sume ccb->ccb_h.flags |= CAM_DEV_QFRZDIS; 371158115Sume 372158115Sume if (cam_send_ccb(dev, ccb) < 0) { 373158115Sume error = errno; 374158115Sume free(inq_buf); 375158115Sume cam_freeccb(ccb); 376158115Sume return (error); 377158115Sume } 378158115Sume 379158115Sume if ((ccb->ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 380158115Sume free(inq_buf); 381158115Sume cam_freeccb(ccb); 382158115Sume return (EIO); 383158115Sume } 384158115Sume 385158115Sume cam_freeccb(ccb); 386158115Sume format_scsi_inquiry(disk, inq_buf); 387158115Sume free(inq_buf); 388158115Sume return (0); 389158115Sume} 390158115Sume 391158115Sumeint 392158115Sumempt_fetch_disks(int fd, int *ndisks, struct mpt_standalone_disk **disksp) 393158115Sume{ 394158115Sume CONFIG_PAGE_IOC_2 *ioc2; 395158115Sume struct mpt_standalone_disk *disks; 396158115Sume struct periph_match_pattern *p; 397158115Sume struct periph_match_result *r; 398158115Sume struct cam_device *dev; 399158115Sume union ccb ccb; 400158115Sume path_id_t path_id; 401158115Sume size_t bufsize; 402158115Sume int count, error; 403158115Sume uint32_t i; 404158115Sume 405158115Sume if (xpt_open() < 0) 406158115Sume return (ENXIO); 407158115Sume 408158115Sume error = fetch_path_id(&path_id); 409158115Sume if (error) 410158115Sume return (error); 411158115Sume 412158115Sume for (count = 100;; count+= 100) { 413158115Sume /* Try to fetch 'count' disks in one go. */ 414158115Sume bzero(&ccb, sizeof(ccb)); 415158115Sume 416158115Sume ccb.ccb_h.func_code = XPT_DEV_MATCH; 417158115Sume 418158115Sume bufsize = sizeof(struct dev_match_result) * (count + 1); 419158115Sume ccb.cdm.num_matches = 0; 420158115Sume ccb.cdm.match_buf_len = bufsize; 421158115Sume ccb.cdm.matches = calloc(1, bufsize); 422158115Sume 423158115Sume bufsize = sizeof(struct dev_match_pattern) * 1; 424158115Sume ccb.cdm.num_patterns = 1; 425158115Sume ccb.cdm.pattern_buf_len = bufsize; 426158115Sume ccb.cdm.patterns = calloc(1, bufsize); 427158115Sume 428238094Sse /* Match any "da" peripherals. */ 429238094Sse ccb.cdm.patterns[0].type = DEV_MATCH_PERIPH; 430238094Sse p = &ccb.cdm.patterns[0].pattern.periph_pattern; 431238094Sse p->path_id = path_id; 432238094Sse snprintf(p->periph_name, sizeof(p->periph_name), "da"); 433238094Sse p->flags = PERIPH_MATCH_PATH | PERIPH_MATCH_NAME; 434158115Sume 435158115Sume if (ioctl(xptfd, CAMIOCOMMAND, &ccb) < 0) { 436158115Sume error = errno; 437158115Sume free(ccb.cdm.matches); 438158115Sume free(ccb.cdm.patterns); 439158115Sume return (error); 440158115Sume } 441158115Sume free(ccb.cdm.patterns); 442158115Sume 443158115Sume /* Check for CCB errors. */ 444158115Sume if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 445158115Sume free(ccb.cdm.matches); 446158115Sume return (EIO); 447158115Sume } 448158115Sume 449158115Sume /* If we need a longer list, try again. */ 450158115Sume if (ccb.cdm.status == CAM_DEV_MATCH_MORE) { 451158115Sume free(ccb.cdm.matches); 452158115Sume continue; 453158115Sume } 454158115Sume 455158115Sume /* If we got an error, abort. */ 456158115Sume if (ccb.cdm.status != CAM_DEV_MATCH_LAST) { 457238094Sse free(ccb.cdm.matches); 458238094Sse return (EIO); 459238094Sse } 460238094Sse break; 461238094Sse } 462238094Sse 463158115Sume /* Shortcut if we don't have any "da" devices. */ 464158115Sume if (ccb.cdm.num_matches == 0) { 465158115Sume free(ccb.cdm.matches); 466158115Sume *ndisks = 0; 467158115Sume *disksp = NULL; 468158115Sume return (0); 469158115Sume } 470158115Sume 471158115Sume /* We should have N matches, 1 for each "da" device. */ 472158115Sume for (i = 0; i < ccb.cdm.num_matches; i++) { 473158115Sume if (ccb.cdm.matches[i].type != DEV_MATCH_PERIPH) { 474158115Sume warnx("mpt_fetch_disks got wrong CAM matches"); 475158115Sume free(ccb.cdm.matches); 476158115Sume return (EIO); 477158115Sume } 478158115Sume } 479158115Sume 480158115Sume /* 481158115Sume * Some of the "da" peripherals may be for RAID volumes, so 482158115Sume * fetch the IOC 2 page (list of RAID volumes) so we can 483158115Sume * exclude them from the list. 484158115Sume */ 485158115Sume ioc2 = mpt_read_ioc_page(fd, 2, NULL); 486158115Sume if (ioc2 == NULL) 487158115Sume return (errno); 488158115Sume disks = calloc(ccb.cdm.num_matches, sizeof(*disks)); 489158115Sume count = 0; 490158115Sume for (i = 0; i < ccb.cdm.num_matches; i++) { 491158115Sume r = &ccb.cdm.matches[i].result.periph_result; 492158115Sume if (periph_is_volume(ioc2, r)) 493158115Sume continue; 494158115Sume disks[count].bus = 0; 495158115Sume disks[count].target = r->target_id; 496158115Sume snprintf(disks[count].devname, sizeof(disks[count].devname), 497158115Sume "%s%d", r->periph_name, r->unit_number); 498158115Sume 499158115Sume dev = cam_open_device(disks[count].devname, O_RDWR); 500158115Sume if (dev != NULL) { 501158115Sume fetch_scsi_capacity(dev, &disks[count]); 502158115Sume fetch_scsi_inquiry(dev, &disks[count]); 503158115Sume cam_close_device(dev); 504158115Sume } 505158115Sume count++; 506158115Sume } 507158115Sume free(ccb.cdm.matches); 508158115Sume free(ioc2); 509158115Sume 510158115Sume *ndisks = count; 511158115Sume *disksp = disks; 512158115Sume return (0); 513158115Sume} 514158115Sume 515158115Sume/* 516158115Sume * Instruct the mpt(4) device to rescan its busses to find new devices 517158115Sume * such as disks whose RAID physdisk page was removed or volumes that 518158115Sume * were created. If id is -1, the entire bus is rescanned. 519158115Sume * Otherwise, only devices at the specified ID are rescanned. If bus 520158115Sume * is -1, then all busses are scanned instead of the specified bus. 521158115Sume * Note that currently, only bus 0 is supported. 522158115Sume */ 523int 524mpt_rescan_bus(int bus, int id) 525{ 526 union ccb ccb; 527 path_id_t path_id; 528 int error; 529 530 /* mpt(4) only handles devices on bus 0. */ 531 if (bus != -1 && bus != 0) 532 return (EINVAL); 533 534 if (xpt_open() < 0) 535 return (ENXIO); 536 537 error = fetch_path_id(&path_id); 538 if (error) 539 return (error); 540 541 /* Perform the actual rescan. */ 542 bzero(&ccb, sizeof(ccb)); 543 ccb.ccb_h.path_id = path_id; 544 if (id == -1) { 545 ccb.ccb_h.func_code = XPT_SCAN_BUS; 546 ccb.ccb_h.target_id = CAM_TARGET_WILDCARD; 547 ccb.ccb_h.target_lun = CAM_LUN_WILDCARD; 548 ccb.ccb_h.timeout = 5000; 549 } else { 550 ccb.ccb_h.func_code = XPT_SCAN_LUN; 551 ccb.ccb_h.target_id = id; 552 ccb.ccb_h.target_lun = 0; 553 } 554 ccb.crcn.flags = CAM_FLAG_NONE; 555 556 /* Run this at a low priority. */ 557 ccb.ccb_h.pinfo.priority = 5; 558 559 if (ioctl(xptfd, CAMIOCOMMAND, &ccb) == -1) 560 return (errno); 561 562 if ((ccb.ccb_h.status & CAM_STATUS_MASK) != CAM_REQ_CMP) { 563 warnx("mpt_rescan_bus rescan got CAM error %#x\n", 564 ccb.ccb_h.status & CAM_STATUS_MASK); 565 return (EIO); 566 } 567 568 return (0); 569} 570