Plumb device physical path reporting from CAM devices, through GEOM and
DEVFS, and make it accessible via the diskinfo utility. Extend GEOM's generic attribute query mechanism into generic disk consumers. sys/geom/geom_disk.c: sys/geom/geom_disk.h: sys/cam/scsi/scsi_da.c: sys/cam/ata/ata_da.c: - Allow disk providers to implement a new method which can override the default BIO_GETATTR response, d_getattr(struct bio *). This function returns -1 if not handled, otherwise it returns 0 or an errno to be passed to g_io_deliver(). sys/cam/scsi/scsi_da.c: sys/cam/ata/ata_da.c: - Don't copy the serial number to dp->d_ident anymore, as the CAM XPT is now responsible for returning this information via d_getattr()->(a)dagetattr()->xpt_getatr(). sys/geom/geom_dev.c: - Implement a new ioctl, DIOCGPHYSPATH, which returns the GEOM attribute "GEOM::physpath", if possible. If the attribute request returns a zero-length string, ENOENT is returned. usr.sbin/diskinfo/diskinfo.c: - If the DIOCGPHYSPATH ioctl is successful, report physical path data when diskinfo is executed with the '-v' option. Submitted by: will Reviewed by: gibbs Sponsored by: Spectra Logic Corporation Add generic attribute change notification support to GEOM. sys/sys/geom/geom.h: Add a new attrchanged method field to both g_class and g_geom. sys/sys/geom/geom.h: sys/geom/geom_event.c: - Provide the g_attr_changed() function that providers can use to advertise attribute changes. - Perform delivery of attribute change notifications from a thread context via the standard GEOM event mechanism. sys/geom/geom_subr.c: Inherit the attrchanged method from class to geom (class instance). sys/geom/geom_disk.c: Provide disk_attr_changed() to provide g_attr_changed() access to consumers of the disk API. sys/cam/scsi/scsi_pass.c: sys/cam/scsi/scsi_da.c: sys/geom/geom_dev.c: sys/geom/geom_disk.c: Use attribute changed events to track updates to physical path information. sys/cam/scsi/scsi_da.c: Add AC_ADVINFO_CHANGED to the registered asynchronous CAM events for this driver. When this event occurs, and the updated buffer type references our physical path attribute, emit a GEOM attribute changed event via the disk_attr_changed() API. sys/cam/scsi/scsi_pass.c: Add AC_ADVINFO_CHANGED to the registered asynchronous CAM events for this driver. When this event occurs, update the physical patch devfs alias for this pass instance. Submitted by: gibbs Sponsored by: Spectra Logic Corporation
This commit is contained in:
parent
f528c3fdbc
commit
416494d7c9
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=223089
@ -812,6 +812,25 @@ adasysctlinit(void *context, int pending)
|
|||||||
cam_periph_release(periph);
|
cam_periph_release(periph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
adagetattr(struct bio *bp)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
struct cam_periph *periph;
|
||||||
|
|
||||||
|
if (bp->bio_disk == NULL || bp->bio_disk->d_drv1)
|
||||||
|
return ENXIO;
|
||||||
|
periph = (struct cam_periph *)bp->bio_disk->d_drv1;
|
||||||
|
if (periph->path == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
|
||||||
|
periph->path);
|
||||||
|
if (ret == 0)
|
||||||
|
bp->bio_completed = bp->bio_length;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static cam_status
|
static cam_status
|
||||||
adaregister(struct cam_periph *periph, void *arg)
|
adaregister(struct cam_periph *periph, void *arg)
|
||||||
{
|
{
|
||||||
@ -917,6 +936,7 @@ adaregister(struct cam_periph *periph, void *arg)
|
|||||||
softc->disk->d_open = adaopen;
|
softc->disk->d_open = adaopen;
|
||||||
softc->disk->d_close = adaclose;
|
softc->disk->d_close = adaclose;
|
||||||
softc->disk->d_strategy = adastrategy;
|
softc->disk->d_strategy = adastrategy;
|
||||||
|
softc->disk->d_getattr = adagetattr;
|
||||||
softc->disk->d_dump = adadump;
|
softc->disk->d_dump = adadump;
|
||||||
softc->disk->d_name = "ada";
|
softc->disk->d_name = "ada";
|
||||||
softc->disk->d_drv1 = periph;
|
softc->disk->d_drv1 = periph;
|
||||||
@ -938,8 +958,6 @@ adaregister(struct cam_periph *periph, void *arg)
|
|||||||
((softc->flags & ADA_FLAG_CAN_CFA) &&
|
((softc->flags & ADA_FLAG_CAN_CFA) &&
|
||||||
!(softc->flags & ADA_FLAG_CAN_48BIT)))
|
!(softc->flags & ADA_FLAG_CAN_48BIT)))
|
||||||
softc->disk->d_flags |= DISKFLAG_CANDELETE;
|
softc->disk->d_flags |= DISKFLAG_CANDELETE;
|
||||||
strlcpy(softc->disk->d_ident, cgd->serial_num,
|
|
||||||
MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1));
|
|
||||||
strlcpy(softc->disk->d_descr, cgd->ident_data.model,
|
strlcpy(softc->disk->d_descr, cgd->ident_data.model,
|
||||||
MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
|
MIN(sizeof(softc->disk->d_descr), sizeof(cgd->ident_data.model)));
|
||||||
softc->disk->d_hba_vendor = cpi.hba_vendor;
|
softc->disk->d_hba_vendor = cpi.hba_vendor;
|
||||||
|
@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/eventhandler.h>
|
#include <sys/eventhandler.h>
|
||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/cons.h>
|
#include <sys/cons.h>
|
||||||
|
#include <geom/geom.h>
|
||||||
#include <geom/geom_disk.h>
|
#include <geom/geom_disk.h>
|
||||||
#endif /* _KERNEL */
|
#endif /* _KERNEL */
|
||||||
|
|
||||||
@ -933,6 +934,25 @@ dadump(void *arg, void *virtual, vm_offset_t physical, off_t offset, size_t leng
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dagetattr(struct bio *bp)
|
||||||
|
{
|
||||||
|
int ret = -1;
|
||||||
|
struct cam_periph *periph;
|
||||||
|
|
||||||
|
if (bp->bio_disk == NULL || bp->bio_disk->d_drv1 == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
periph = (struct cam_periph *)bp->bio_disk->d_drv1;
|
||||||
|
if (periph->path == NULL)
|
||||||
|
return ENXIO;
|
||||||
|
|
||||||
|
ret = xpt_getattr(bp->bio_data, bp->bio_length, bp->bio_attribute,
|
||||||
|
periph->path);
|
||||||
|
if (ret == 0)
|
||||||
|
bp->bio_completed = bp->bio_length;
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dainit(void)
|
dainit(void)
|
||||||
{
|
{
|
||||||
@ -1046,6 +1066,20 @@ daasync(void *callback_arg, u_int32_t code,
|
|||||||
&& status != CAM_REQ_INPROG)
|
&& status != CAM_REQ_INPROG)
|
||||||
printf("daasync: Unable to attach to new device "
|
printf("daasync: Unable to attach to new device "
|
||||||
"due to status 0x%x\n", status);
|
"due to status 0x%x\n", status);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case AC_ADVINFO_CHANGED:
|
||||||
|
{
|
||||||
|
uintptr_t buftype;
|
||||||
|
|
||||||
|
buftype = (uintptr_t)arg;
|
||||||
|
if (buftype == CDAI_TYPE_PHYS_PATH) {
|
||||||
|
struct da_softc *softc;
|
||||||
|
|
||||||
|
softc = periph->softc;
|
||||||
|
disk_attr_changed(softc->disk, "GEOM::physpath",
|
||||||
|
M_NOWAIT);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case AC_SENT_BDR:
|
case AC_SENT_BDR:
|
||||||
@ -1232,17 +1266,6 @@ daregister(struct cam_periph *periph, void *arg)
|
|||||||
|
|
||||||
TASK_INIT(&softc->sysctl_task, 0, dasysctlinit, periph);
|
TASK_INIT(&softc->sysctl_task, 0, dasysctlinit, periph);
|
||||||
|
|
||||||
/*
|
|
||||||
* Add async callbacks for bus reset and
|
|
||||||
* bus device reset calls. I don't bother
|
|
||||||
* checking if this fails as, in most cases,
|
|
||||||
* the system will function just fine without
|
|
||||||
* them and the only alternative would be to
|
|
||||||
* not attach the device on failure.
|
|
||||||
*/
|
|
||||||
xpt_register_async(AC_SENT_BDR | AC_BUS_RESET | AC_LOST_DEVICE,
|
|
||||||
daasync, periph, periph->path);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Take an exclusive refcount on the periph while dastart is called
|
* Take an exclusive refcount on the periph while dastart is called
|
||||||
* to finish the probe. The reference will be dropped in dadone at
|
* to finish the probe. The reference will be dropped in dadone at
|
||||||
@ -1303,6 +1326,7 @@ daregister(struct cam_periph *periph, void *arg)
|
|||||||
softc->disk->d_close = daclose;
|
softc->disk->d_close = daclose;
|
||||||
softc->disk->d_strategy = dastrategy;
|
softc->disk->d_strategy = dastrategy;
|
||||||
softc->disk->d_dump = dadump;
|
softc->disk->d_dump = dadump;
|
||||||
|
softc->disk->d_getattr = dagetattr;
|
||||||
softc->disk->d_name = "da";
|
softc->disk->d_name = "da";
|
||||||
softc->disk->d_drv1 = periph;
|
softc->disk->d_drv1 = periph;
|
||||||
if (cpi.maxio == 0)
|
if (cpi.maxio == 0)
|
||||||
@ -1315,8 +1339,6 @@ daregister(struct cam_periph *periph, void *arg)
|
|||||||
softc->disk->d_flags = 0;
|
softc->disk->d_flags = 0;
|
||||||
if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0)
|
if ((softc->quirks & DA_Q_NO_SYNC_CACHE) == 0)
|
||||||
softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
|
softc->disk->d_flags |= DISKFLAG_CANFLUSHCACHE;
|
||||||
strlcpy(softc->disk->d_ident, cgd->serial_num,
|
|
||||||
MIN(sizeof(softc->disk->d_ident), cgd->serial_num_len + 1));
|
|
||||||
cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor,
|
cam_strvis(softc->disk->d_descr, cgd->inq_data.vendor,
|
||||||
sizeof(cgd->inq_data.vendor), sizeof(softc->disk->d_descr));
|
sizeof(cgd->inq_data.vendor), sizeof(softc->disk->d_descr));
|
||||||
strlcat(softc->disk->d_descr, " ", sizeof(softc->disk->d_descr));
|
strlcat(softc->disk->d_descr, " ", sizeof(softc->disk->d_descr));
|
||||||
@ -1330,6 +1352,25 @@ daregister(struct cam_periph *periph, void *arg)
|
|||||||
disk_create(softc->disk, DISK_VERSION);
|
disk_create(softc->disk, DISK_VERSION);
|
||||||
mtx_lock(periph->sim->mtx);
|
mtx_lock(periph->sim->mtx);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add async callbacks for events of interest.
|
||||||
|
* I don't bother checking if this fails as,
|
||||||
|
* in most cases, the system will function just
|
||||||
|
* fine without them and the only alternative
|
||||||
|
* would be to not attach the device on failure.
|
||||||
|
*/
|
||||||
|
xpt_register_async(AC_SENT_BDR | AC_BUS_RESET
|
||||||
|
| AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
|
||||||
|
daasync, periph, periph->path);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Emit an attribute changed notification just in case
|
||||||
|
* physical path information arrived before our async
|
||||||
|
* event handler was registered, but after anyone attaching
|
||||||
|
* to our disk device polled it.
|
||||||
|
*/
|
||||||
|
disk_attr_changed(softc->disk, "GEOM::physpath", M_NOWAIT);
|
||||||
|
|
||||||
xpt_schedule(periph, CAM_PRIORITY_DEV);
|
xpt_schedule(periph, CAM_PRIORITY_DEV);
|
||||||
|
|
||||||
return(CAM_REQ_CMP);
|
return(CAM_REQ_CMP);
|
||||||
|
@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/errno.h>
|
#include <sys/errno.h>
|
||||||
#include <sys/devicestat.h>
|
#include <sys/devicestat.h>
|
||||||
#include <sys/proc.h>
|
#include <sys/proc.h>
|
||||||
|
#include <sys/taskqueue.h>
|
||||||
|
|
||||||
#include <cam/cam.h>
|
#include <cam/cam.h>
|
||||||
#include <cam/cam_ccb.h>
|
#include <cam/cam_ccb.h>
|
||||||
@ -70,12 +71,14 @@ typedef enum {
|
|||||||
#define ccb_bp ppriv_ptr1
|
#define ccb_bp ppriv_ptr1
|
||||||
|
|
||||||
struct pass_softc {
|
struct pass_softc {
|
||||||
pass_state state;
|
pass_state state;
|
||||||
pass_flags flags;
|
pass_flags flags;
|
||||||
u_int8_t pd_type;
|
u_int8_t pd_type;
|
||||||
union ccb saved_ccb;
|
union ccb saved_ccb;
|
||||||
struct devstat *device_stats;
|
struct devstat *device_stats;
|
||||||
struct cdev *dev;
|
struct cdev *dev;
|
||||||
|
struct cdev *alias_dev;
|
||||||
|
struct task add_physpath_task;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -88,6 +91,7 @@ static periph_ctor_t passregister;
|
|||||||
static periph_oninv_t passoninvalidate;
|
static periph_oninv_t passoninvalidate;
|
||||||
static periph_dtor_t passcleanup;
|
static periph_dtor_t passcleanup;
|
||||||
static periph_start_t passstart;
|
static periph_start_t passstart;
|
||||||
|
static void pass_add_physpath(void *context, int pending);
|
||||||
static void passasync(void *callback_arg, u_int32_t code,
|
static void passasync(void *callback_arg, u_int32_t code,
|
||||||
struct cam_path *path, void *arg);
|
struct cam_path *path, void *arg);
|
||||||
static void passdone(struct cam_periph *periph,
|
static void passdone(struct cam_periph *periph,
|
||||||
@ -168,16 +172,44 @@ passcleanup(struct cam_periph *periph)
|
|||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
xpt_print(periph->path, "removing device entry\n");
|
xpt_print(periph->path, "removing device entry\n");
|
||||||
devstat_remove_entry(softc->device_stats);
|
devstat_remove_entry(softc->device_stats);
|
||||||
|
|
||||||
cam_periph_unlock(periph);
|
cam_periph_unlock(periph);
|
||||||
|
taskqueue_drain(taskqueue_thread, &softc->add_physpath_task);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* passcleanup() is indirectly a d_close method via passclose,
|
* passcleanup() is indirectly a d_close method via passclose,
|
||||||
* so using destroy_dev(9) directly can result in deadlock.
|
* so using destroy_dev(9) directly can result in deadlock.
|
||||||
*/
|
*/
|
||||||
destroy_dev_sched(softc->dev);
|
destroy_dev_sched(softc->dev);
|
||||||
cam_periph_lock(periph);
|
cam_periph_lock(periph);
|
||||||
|
|
||||||
free(softc, M_DEVBUF);
|
free(softc, M_DEVBUF);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pass_add_physpath(void *context, int pending)
|
||||||
|
{
|
||||||
|
struct cam_periph *periph;
|
||||||
|
struct pass_softc *softc;
|
||||||
|
char *physpath;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If we have one, create a devfs alias for our
|
||||||
|
* physical path.
|
||||||
|
*/
|
||||||
|
periph = context;
|
||||||
|
softc = periph->softc;
|
||||||
|
physpath = malloc(MAXPATHLEN, M_DEVBUF, M_WAITOK);
|
||||||
|
if (xpt_getattr(physpath, MAXPATHLEN,
|
||||||
|
"GEOM::physpath", periph->path) == 0
|
||||||
|
&& strlen(physpath) != 0) {
|
||||||
|
|
||||||
|
make_dev_physpath_alias(MAKEDEV_WAITOK, &softc->alias_dev,
|
||||||
|
softc->dev, softc->alias_dev, physpath);
|
||||||
|
}
|
||||||
|
free(physpath, M_DEVBUF);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
passasync(void *callback_arg, u_int32_t code,
|
passasync(void *callback_arg, u_int32_t code,
|
||||||
struct cam_path *path, void *arg)
|
struct cam_path *path, void *arg)
|
||||||
@ -219,6 +251,20 @@ passasync(void *callback_arg, u_int32_t code,
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case AC_ADVINFO_CHANGED:
|
||||||
|
{
|
||||||
|
uintptr_t buftype;
|
||||||
|
|
||||||
|
buftype = (uintptr_t)arg;
|
||||||
|
if (buftype == CDAI_TYPE_PHYS_PATH) {
|
||||||
|
struct pass_softc *softc;
|
||||||
|
|
||||||
|
softc = (struct pass_softc *)periph->softc;
|
||||||
|
taskqueue_enqueue(taskqueue_thread,
|
||||||
|
&softc->add_physpath_task);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
cam_periph_async(periph, code, path, arg);
|
cam_periph_async(periph, code, path, arg);
|
||||||
break;
|
break;
|
||||||
@ -292,11 +338,22 @@ passregister(struct cam_periph *periph, void *arg)
|
|||||||
mtx_lock(periph->sim->mtx);
|
mtx_lock(periph->sim->mtx);
|
||||||
softc->dev->si_drv1 = periph;
|
softc->dev->si_drv1 = periph;
|
||||||
|
|
||||||
|
TASK_INIT(&softc->add_physpath_task, /*priority*/0,
|
||||||
|
pass_add_physpath, periph);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Add an async callback so that we get
|
* See if physical path information is already available.
|
||||||
* notified if this device goes away.
|
|
||||||
*/
|
*/
|
||||||
xpt_register_async(AC_LOST_DEVICE, passasync, periph, periph->path);
|
taskqueue_enqueue(taskqueue_thread, &softc->add_physpath_task);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add an async callback so that we get notified if
|
||||||
|
* this device goes away or its physical path
|
||||||
|
* (stored in the advanced info data of the EDT) has
|
||||||
|
* changed.
|
||||||
|
*/
|
||||||
|
xpt_register_async(AC_LOST_DEVICE | AC_ADVINFO_CHANGED,
|
||||||
|
passasync, periph, periph->path);
|
||||||
|
|
||||||
if (bootverbose)
|
if (bootverbose)
|
||||||
xpt_announce_periph(periph, NULL);
|
xpt_announce_periph(periph, NULL);
|
||||||
|
@ -76,6 +76,7 @@ typedef void g_orphan_t (struct g_consumer *);
|
|||||||
|
|
||||||
typedef void g_start_t (struct bio *);
|
typedef void g_start_t (struct bio *);
|
||||||
typedef void g_spoiled_t (struct g_consumer *);
|
typedef void g_spoiled_t (struct g_consumer *);
|
||||||
|
typedef void g_attrchanged_t (struct g_consumer *, const char *attr);
|
||||||
typedef void g_dumpconf_t (struct sbuf *, const char *indent, struct g_geom *,
|
typedef void g_dumpconf_t (struct sbuf *, const char *indent, struct g_geom *,
|
||||||
struct g_consumer *, struct g_provider *);
|
struct g_consumer *, struct g_provider *);
|
||||||
|
|
||||||
@ -100,6 +101,7 @@ struct g_class {
|
|||||||
*/
|
*/
|
||||||
g_start_t *start;
|
g_start_t *start;
|
||||||
g_spoiled_t *spoiled;
|
g_spoiled_t *spoiled;
|
||||||
|
g_attrchanged_t *attrchanged;
|
||||||
g_dumpconf_t *dumpconf;
|
g_dumpconf_t *dumpconf;
|
||||||
g_access_t *access;
|
g_access_t *access;
|
||||||
g_orphan_t *orphan;
|
g_orphan_t *orphan;
|
||||||
@ -128,6 +130,7 @@ struct g_geom {
|
|||||||
int rank;
|
int rank;
|
||||||
g_start_t *start;
|
g_start_t *start;
|
||||||
g_spoiled_t *spoiled;
|
g_spoiled_t *spoiled;
|
||||||
|
g_attrchanged_t *attrchanged;
|
||||||
g_dumpconf_t *dumpconf;
|
g_dumpconf_t *dumpconf;
|
||||||
g_access_t *access;
|
g_access_t *access;
|
||||||
g_orphan_t *orphan;
|
g_orphan_t *orphan;
|
||||||
@ -217,6 +220,7 @@ struct g_classifier_hook {
|
|||||||
/* geom_dev.c */
|
/* geom_dev.c */
|
||||||
struct cdev;
|
struct cdev;
|
||||||
void g_dev_print(void);
|
void g_dev_print(void);
|
||||||
|
void g_dev_physpath_changed(void);
|
||||||
struct g_provider *g_dev_getprovider(struct cdev *dev);
|
struct g_provider *g_dev_getprovider(struct cdev *dev);
|
||||||
|
|
||||||
/* geom_dump.c */
|
/* geom_dump.c */
|
||||||
@ -232,6 +236,7 @@ typedef void g_event_t(void *, int flag);
|
|||||||
int g_post_event(g_event_t *func, void *arg, int flag, ...);
|
int g_post_event(g_event_t *func, void *arg, int flag, ...);
|
||||||
int g_waitfor_event(g_event_t *func, void *arg, int flag, ...);
|
int g_waitfor_event(g_event_t *func, void *arg, int flag, ...);
|
||||||
void g_cancel_event(void *ref);
|
void g_cancel_event(void *ref);
|
||||||
|
int g_attr_changed(struct g_provider *pp, const char *attr, int flag);
|
||||||
void g_orphan_provider(struct g_provider *pp, int error);
|
void g_orphan_provider(struct g_provider *pp, int error);
|
||||||
void g_waitidlelock(void);
|
void g_waitidlelock(void);
|
||||||
|
|
||||||
|
@ -41,6 +41,7 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/malloc.h>
|
#include <sys/malloc.h>
|
||||||
#include <sys/kernel.h>
|
#include <sys/kernel.h>
|
||||||
#include <sys/conf.h>
|
#include <sys/conf.h>
|
||||||
|
#include <sys/ctype.h>
|
||||||
#include <sys/bio.h>
|
#include <sys/bio.h>
|
||||||
#include <sys/lock.h>
|
#include <sys/lock.h>
|
||||||
#include <sys/mutex.h>
|
#include <sys/mutex.h>
|
||||||
@ -52,6 +53,12 @@ __FBSDID("$FreeBSD$");
|
|||||||
#include <sys/limits.h>
|
#include <sys/limits.h>
|
||||||
#include <geom/geom.h>
|
#include <geom/geom.h>
|
||||||
#include <geom/geom_int.h>
|
#include <geom/geom_int.h>
|
||||||
|
#include <machine/stdarg.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Use the consumer private field to reference a physdev alias (if any).
|
||||||
|
*/
|
||||||
|
#define cp_alias_dev private
|
||||||
|
|
||||||
static d_open_t g_dev_open;
|
static d_open_t g_dev_open;
|
||||||
static d_close_t g_dev_close;
|
static d_close_t g_dev_close;
|
||||||
@ -72,12 +79,14 @@ static struct cdevsw g_dev_cdevsw = {
|
|||||||
|
|
||||||
static g_taste_t g_dev_taste;
|
static g_taste_t g_dev_taste;
|
||||||
static g_orphan_t g_dev_orphan;
|
static g_orphan_t g_dev_orphan;
|
||||||
|
static g_attrchanged_t g_dev_attrchanged;
|
||||||
|
|
||||||
static struct g_class g_dev_class = {
|
static struct g_class g_dev_class = {
|
||||||
.name = "DEV",
|
.name = "DEV",
|
||||||
.version = G_VERSION,
|
.version = G_VERSION,
|
||||||
.taste = g_dev_taste,
|
.taste = g_dev_taste,
|
||||||
.orphan = g_dev_orphan,
|
.orphan = g_dev_orphan,
|
||||||
|
.attrchanged = g_dev_attrchanged
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -93,6 +102,40 @@ g_dev_print(void)
|
|||||||
printf("\n");
|
printf("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_dev_attrchanged(struct g_consumer *cp, const char *attr)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (strcmp(attr, "GEOM::physpath") != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (g_access(cp, 1, 0, 0) == 0) {
|
||||||
|
char *physpath;
|
||||||
|
int error, physpath_len;
|
||||||
|
|
||||||
|
physpath_len = MAXPATHLEN;
|
||||||
|
physpath = g_malloc(physpath_len, M_WAITOK|M_ZERO);
|
||||||
|
error =
|
||||||
|
g_io_getattr("GEOM::physpath", cp, &physpath_len, physpath);
|
||||||
|
g_access(cp, -1, 0, 0);
|
||||||
|
if (error == 0 && strlen(physpath) != 0) {
|
||||||
|
struct cdev *dev;
|
||||||
|
struct cdev *old_alias_dev;
|
||||||
|
struct cdev **alias_devp;
|
||||||
|
|
||||||
|
dev = cp->geom->softc;
|
||||||
|
old_alias_dev = cp->cp_alias_dev;
|
||||||
|
alias_devp = (struct cdev **)&cp->cp_alias_dev;
|
||||||
|
make_dev_physpath_alias(MAKEDEV_WAITOK, alias_devp,
|
||||||
|
dev, old_alias_dev, physpath);
|
||||||
|
} else if (cp->cp_alias_dev) {
|
||||||
|
destroy_dev((struct cdev *)cp->cp_alias_dev);
|
||||||
|
cp->cp_alias_dev = NULL;
|
||||||
|
}
|
||||||
|
g_free(physpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct g_provider *
|
struct g_provider *
|
||||||
g_dev_getprovider(struct cdev *dev)
|
g_dev_getprovider(struct cdev *dev)
|
||||||
{
|
{
|
||||||
@ -107,7 +150,6 @@ g_dev_getprovider(struct cdev *dev)
|
|||||||
return (cp->provider);
|
return (cp->provider);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static struct g_geom *
|
static struct g_geom *
|
||||||
g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
|
g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
|
||||||
{
|
{
|
||||||
@ -167,6 +209,9 @@ g_dev_taste(struct g_class *mp, struct g_provider *pp, int insist __unused)
|
|||||||
adev->si_drv1 = gp;
|
adev->si_drv1 = gp;
|
||||||
adev->si_drv2 = cp;
|
adev->si_drv2 = cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_dev_attrchanged(cp, "GEOM::physpath");
|
||||||
|
|
||||||
return (gp);
|
return (gp);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,6 +410,11 @@ g_dev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag, struct thread
|
|||||||
case DIOCGSTRIPEOFFSET:
|
case DIOCGSTRIPEOFFSET:
|
||||||
*(off_t *)data = cp->provider->stripeoffset;
|
*(off_t *)data = cp->provider->stripeoffset;
|
||||||
break;
|
break;
|
||||||
|
case DIOCGPHYSPATH:
|
||||||
|
error = g_io_getattr("GEOM::physpath", cp, &i, data);
|
||||||
|
if (error == 0 && *(char *)data == '\0')
|
||||||
|
error = ENOENT;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (cp->provider->geom->ioctl != NULL) {
|
if (cp->provider->geom->ioctl != NULL) {
|
||||||
error = cp->provider->geom->ioctl(cp->provider, cmd, data, fflag, td);
|
error = cp->provider->geom->ioctl(cp->provider, cmd, data, fflag, td);
|
||||||
|
@ -347,6 +347,15 @@ g_disk_start(struct bio *bp)
|
|||||||
} while (bp2 != NULL);
|
} while (bp2 != NULL);
|
||||||
break;
|
break;
|
||||||
case BIO_GETATTR:
|
case BIO_GETATTR:
|
||||||
|
/* Give the driver a chance to override */
|
||||||
|
if (dp->d_getattr != NULL) {
|
||||||
|
if (bp->bio_disk == NULL)
|
||||||
|
bp->bio_disk = dp;
|
||||||
|
error = dp->d_getattr(bp);
|
||||||
|
if (error != -1)
|
||||||
|
break;
|
||||||
|
error = EJUSTRETURN;
|
||||||
|
}
|
||||||
if (g_handleattr_int(bp, "GEOM::candelete",
|
if (g_handleattr_int(bp, "GEOM::candelete",
|
||||||
(dp->d_flags & DISKFLAG_CANDELETE) != 0))
|
(dp->d_flags & DISKFLAG_CANDELETE) != 0))
|
||||||
break;
|
break;
|
||||||
@ -582,6 +591,18 @@ disk_gone(struct disk *dp)
|
|||||||
g_wither_provider(pp, ENXIO);
|
g_wither_provider(pp, ENXIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
disk_attr_changed(struct disk *dp, const char *attr, int flag)
|
||||||
|
{
|
||||||
|
struct g_geom *gp;
|
||||||
|
struct g_provider *pp;
|
||||||
|
|
||||||
|
gp = dp->d_geom;
|
||||||
|
if (gp != NULL)
|
||||||
|
LIST_FOREACH(pp, &gp->provider, provider)
|
||||||
|
(void)g_attr_changed(pp, attr, flag);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
g_kern_disks(void *p, int flag __unused)
|
g_kern_disks(void *p, int flag __unused)
|
||||||
{
|
{
|
||||||
|
@ -49,6 +49,7 @@ struct disk;
|
|||||||
typedef int disk_open_t(struct disk *);
|
typedef int disk_open_t(struct disk *);
|
||||||
typedef int disk_close_t(struct disk *);
|
typedef int disk_close_t(struct disk *);
|
||||||
typedef void disk_strategy_t(struct bio *bp);
|
typedef void disk_strategy_t(struct bio *bp);
|
||||||
|
typedef int disk_getattr_t(struct bio *bp);
|
||||||
typedef int disk_ioctl_t(struct disk *, u_long cmd, void *data,
|
typedef int disk_ioctl_t(struct disk *, u_long cmd, void *data,
|
||||||
int fflag, struct thread *td);
|
int fflag, struct thread *td);
|
||||||
/* NB: disk_ioctl_t SHALL be cast'able to d_ioctl_t */
|
/* NB: disk_ioctl_t SHALL be cast'able to d_ioctl_t */
|
||||||
@ -75,6 +76,7 @@ struct disk {
|
|||||||
disk_strategy_t *d_strategy;
|
disk_strategy_t *d_strategy;
|
||||||
disk_ioctl_t *d_ioctl;
|
disk_ioctl_t *d_ioctl;
|
||||||
dumper_t *d_dump;
|
dumper_t *d_dump;
|
||||||
|
disk_getattr_t *d_getattr;
|
||||||
|
|
||||||
/* Info fields from driver to geom_disk.c. Valid when open */
|
/* Info fields from driver to geom_disk.c. Valid when open */
|
||||||
u_int d_sectorsize;
|
u_int d_sectorsize;
|
||||||
@ -104,6 +106,7 @@ struct disk *disk_alloc(void);
|
|||||||
void disk_create(struct disk *disk, int version);
|
void disk_create(struct disk *disk, int version);
|
||||||
void disk_destroy(struct disk *disk);
|
void disk_destroy(struct disk *disk);
|
||||||
void disk_gone(struct disk *disk);
|
void disk_gone(struct disk *disk);
|
||||||
|
void disk_attr_changed(struct disk *dp, const char *attr, int flag);
|
||||||
|
|
||||||
#define DISK_VERSION_00 0x58561059
|
#define DISK_VERSION_00 0x58561059
|
||||||
#define DISK_VERSION_01 0x5856105a
|
#define DISK_VERSION_01 0x5856105a
|
||||||
|
@ -110,6 +110,53 @@ g_waitidlelock(void)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
struct g_attrchanged_args {
|
||||||
|
struct g_provider *pp;
|
||||||
|
const char *attr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
g_attr_changed_event(void *arg, int flag)
|
||||||
|
{
|
||||||
|
struct g_attrchanged_args *args;
|
||||||
|
struct g_provider *pp;
|
||||||
|
struct g_consumer *cp;
|
||||||
|
struct g_consumer *next_cp;
|
||||||
|
|
||||||
|
args = arg;
|
||||||
|
pp = args->pp;
|
||||||
|
|
||||||
|
g_topology_assert();
|
||||||
|
if (flag != EV_CANCEL && g_shutdown == 0) {
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Tell all consumers of the change.
|
||||||
|
*/
|
||||||
|
LIST_FOREACH_SAFE(cp, &pp->consumers, consumers, next_cp) {
|
||||||
|
if (cp->geom->attrchanged != NULL)
|
||||||
|
cp->geom->attrchanged(cp, args->attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
g_free(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
g_attr_changed(struct g_provider *pp, const char *attr, int flag)
|
||||||
|
{
|
||||||
|
struct g_attrchanged_args *args;
|
||||||
|
int error;
|
||||||
|
|
||||||
|
args = g_malloc(sizeof *args, flag);
|
||||||
|
if (args == NULL)
|
||||||
|
return (ENOMEM);
|
||||||
|
args->pp = pp;
|
||||||
|
args->attr = attr;
|
||||||
|
error = g_post_event(g_attr_changed_event, args, flag, pp, NULL);
|
||||||
|
if (error != 0)
|
||||||
|
g_free(args);
|
||||||
|
return (error);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
g_orphan_provider(struct g_provider *pp, int error)
|
g_orphan_provider(struct g_provider *pp, int error)
|
||||||
{
|
{
|
||||||
|
@ -350,6 +350,7 @@ g_new_geomf(struct g_class *mp, const char *fmt, ...)
|
|||||||
/* Fill in defaults from class */
|
/* Fill in defaults from class */
|
||||||
gp->start = mp->start;
|
gp->start = mp->start;
|
||||||
gp->spoiled = mp->spoiled;
|
gp->spoiled = mp->spoiled;
|
||||||
|
gp->attrchanged = mp->attrchanged;
|
||||||
gp->dumpconf = mp->dumpconf;
|
gp->dumpconf = mp->dumpconf;
|
||||||
gp->access = mp->access;
|
gp->access = mp->access;
|
||||||
gp->orphan = mp->orphan;
|
gp->orphan = mp->orphan;
|
||||||
|
@ -116,4 +116,12 @@ void disk_err(struct bio *bp, const char *what, int blkdone, int nl);
|
|||||||
* This should be a multiple of the sector size.
|
* This should be a multiple of the sector size.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define DIOCGPHYSPATH _IOR('d', 141, char[MAXPATHLEN])
|
||||||
|
/*
|
||||||
|
* Get a string defining the physical path for a given provider.
|
||||||
|
* This has similar rules to ident, but is intended to uniquely
|
||||||
|
* identify the physical location of the device, not the current
|
||||||
|
* occupant of that location.
|
||||||
|
*/
|
||||||
|
|
||||||
#endif /* _SYS_DISK_H_ */
|
#endif /* _SYS_DISK_H_ */
|
||||||
|
@ -39,6 +39,7 @@
|
|||||||
#include <paths.h>
|
#include <paths.h>
|
||||||
#include <err.h>
|
#include <err.h>
|
||||||
#include <sys/disk.h>
|
#include <sys/disk.h>
|
||||||
|
#include <sys/param.h>
|
||||||
#include <sys/time.h>
|
#include <sys/time.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -57,7 +58,7 @@ int
|
|||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int i, ch, fd, error, exitval = 0;
|
int i, ch, fd, error, exitval = 0;
|
||||||
char buf[BUFSIZ], ident[DISK_IDENT_SIZE];
|
char buf[BUFSIZ], ident[DISK_IDENT_SIZE], physpath[MAXPATHLEN];
|
||||||
off_t mediasize, stripesize, stripeoffset;
|
off_t mediasize, stripesize, stripeoffset;
|
||||||
u_int sectorsize, fwsectors, fwheads;
|
u_int sectorsize, fwsectors, fwheads;
|
||||||
|
|
||||||
@ -151,6 +152,8 @@ main(int argc, char **argv)
|
|||||||
}
|
}
|
||||||
if (ioctl(fd, DIOCGIDENT, ident) == 0)
|
if (ioctl(fd, DIOCGIDENT, ident) == 0)
|
||||||
printf("\t%-12s\t# Disk ident.\n", ident);
|
printf("\t%-12s\t# Disk ident.\n", ident);
|
||||||
|
if (ioctl(fd, DIOCGPHYSPATH, physpath) == 0)
|
||||||
|
printf("\t%-12s\t# Physical path\n", physpath);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
if (opt_c)
|
if (opt_c)
|
||||||
|
Loading…
Reference in New Issue
Block a user