#include <sys/param.h>
#include <sys/malloc.h>
#include <cpu/atomic.h>
#include <dev/disk/dm/dm.h>
static int
dm_table_busy(dm_table_head_t *head, uint8_t table_id)
{
uint8_t id;
id = 0;
lockmgr(&head->table_mtx, LK_SHARED);
if (table_id == DM_TABLE_ACTIVE)
id = head->cur_active_table;
else
id = 1 - head->cur_active_table;
atomic_add_int(&head->io_cnt, 1);
return id;
}
static void
dm_table_unbusy(dm_table_head_t *head)
{
KKASSERT(head->io_cnt != 0);
atomic_subtract_int(&head->io_cnt, 1);
lockmgr(&head->table_mtx, LK_RELEASE);
}
dm_table_t *
dm_table_get_entry(dm_table_head_t *head, uint8_t table_id)
{
uint8_t id;
id = dm_table_busy(head, table_id);
return &head->tables[id];
}
void
dm_table_release(dm_table_head_t *head, uint8_t table_id)
{
dm_table_unbusy(head);
}
void
dm_table_switch_tables(dm_table_head_t *head)
{
lockmgr(&head->table_mtx, LK_EXCLUSIVE);
head->cur_active_table = 1 - head->cur_active_table;
lockmgr(&head->table_mtx, LK_RELEASE);
}
int
dm_table_destroy(dm_table_head_t *head, uint8_t table_id)
{
dm_table_t *tbl;
dm_table_entry_t *table_en;
uint8_t id;
lockmgr(&head->table_mtx, LK_EXCLUSIVE);
dmdebug("table_id=%d io_cnt=%d\n", table_id, head->io_cnt);
if (table_id == DM_TABLE_ACTIVE)
id = head->cur_active_table;
else
id = 1 - head->cur_active_table;
tbl = &head->tables[id];
while ((table_en = TAILQ_FIRST(tbl)) != NULL) {
TAILQ_REMOVE(tbl, table_en, next);
if (table_en->target->destroy)
table_en->target->destroy(table_en);
table_en->target_config = NULL;
dm_table_free_deps(table_en);
dm_target_unbusy(table_en->target);
kfree(table_en, M_DM);
}
KKASSERT(TAILQ_EMPTY(tbl));
lockmgr(&head->table_mtx, LK_RELEASE);
return 0;
}
static uint64_t
_dm_table_size(dm_table_head_t *head, int table)
{
dm_table_t *tbl;
dm_table_entry_t *table_en;
uint64_t length;
length = 0;
tbl = dm_table_get_entry(head, table);
TAILQ_FOREACH(table_en, tbl, next) {
length += table_en->length;
}
dm_table_unbusy(head);
return length;
}
uint64_t
dm_table_size(dm_table_head_t *head)
{
return _dm_table_size(head, DM_TABLE_ACTIVE);
}
uint64_t
dm_inactive_table_size(dm_table_head_t *head)
{
return _dm_table_size(head, DM_TABLE_INACTIVE);
}
int
dm_table_get_target_count(dm_table_head_t *head, uint8_t table_id)
{
dm_table_entry_t *table_en;
dm_table_t *tbl;
uint32_t target_count;
target_count = 0;
tbl = dm_table_get_entry(head, table_id);
TAILQ_FOREACH(table_en, tbl, next)
target_count++;
dm_table_unbusy(head);
return target_count;
}
void
dm_table_head_init(dm_table_head_t *head)
{
head->cur_active_table = 0;
head->io_cnt = 0;
TAILQ_INIT(&head->tables[0]);
TAILQ_INIT(&head->tables[1]);
lockinit(&head->table_mtx, "dmtbl", 0, LK_CANRECURSE);
}
void
dm_table_head_destroy(dm_table_head_t *head)
{
KKASSERT(!lockinuse(&head->table_mtx));
KKASSERT(head->io_cnt == 0);
lockuninit(&head->table_mtx);
}
void
dm_table_init_target(dm_table_entry_t *table_en, void *cfg)
{
table_en->target_config = cfg;
}
int
dm_table_add_deps(dm_table_entry_t *table_en, dm_pdev_t *pdev)
{
dm_table_head_t *head;
dm_mapping_t *map;
KKASSERT(pdev);
head = &table_en->dev->table_head;
lockmgr(&head->table_mtx, LK_SHARED);
TAILQ_FOREACH(map, &table_en->pdev_maps, next) {
if (map->data.pdev->udev == pdev->udev) {
lockmgr(&head->table_mtx, LK_RELEASE);
return -1;
}
}
map = kmalloc(sizeof(*map), M_DM, M_WAITOK | M_ZERO);
map->data.pdev = pdev;
TAILQ_INSERT_TAIL(&table_en->pdev_maps, map, next);
lockmgr(&head->table_mtx, LK_RELEASE);
return 0;
}
void
dm_table_free_deps(dm_table_entry_t *table_en)
{
dm_table_head_t *head;
dm_mapping_t *map;
head = &table_en->dev->table_head;
lockmgr(&head->table_mtx, LK_SHARED);
while ((map = TAILQ_FIRST(&table_en->pdev_maps)) != NULL) {
TAILQ_REMOVE(&table_en->pdev_maps, map, next);
kfree(map, M_DM);
}
KKASSERT(TAILQ_EMPTY(&table_en->pdev_maps));
lockmgr(&head->table_mtx, LK_RELEASE);
}