1*31cf6336SKozlowski Mateusz /* SPDX-License-Identifier: BSD-3-Clause 2*31cf6336SKozlowski Mateusz * Copyright (c) Intel Corporation. 3*31cf6336SKozlowski Mateusz * All rights reserved. 4*31cf6336SKozlowski Mateusz */ 5*31cf6336SKozlowski Mateusz 6*31cf6336SKozlowski Mateusz #include "spdk/likely.h" 7*31cf6336SKozlowski Mateusz 8*31cf6336SKozlowski Mateusz #include "ftl_writer.h" 9*31cf6336SKozlowski Mateusz #include "ftl_band.h" 10*31cf6336SKozlowski Mateusz 11*31cf6336SKozlowski Mateusz void 12*31cf6336SKozlowski Mateusz ftl_writer_init(struct spdk_ftl_dev *dev, struct ftl_writer *writer, 13*31cf6336SKozlowski Mateusz uint64_t limit, enum ftl_band_type type) 14*31cf6336SKozlowski Mateusz { 15*31cf6336SKozlowski Mateusz memset(writer, 0, sizeof(*writer)); 16*31cf6336SKozlowski Mateusz writer->dev = dev; 17*31cf6336SKozlowski Mateusz TAILQ_INIT(&writer->rq_queue); 18*31cf6336SKozlowski Mateusz TAILQ_INIT(&writer->full_bands); 19*31cf6336SKozlowski Mateusz writer->limit = limit; 20*31cf6336SKozlowski Mateusz writer->halt = true; 21*31cf6336SKozlowski Mateusz writer->writer_type = type; 22*31cf6336SKozlowski Mateusz } 23*31cf6336SKozlowski Mateusz 24*31cf6336SKozlowski Mateusz static bool 25*31cf6336SKozlowski Mateusz can_write(struct ftl_writer *writer) 26*31cf6336SKozlowski Mateusz { 27*31cf6336SKozlowski Mateusz if (spdk_unlikely(writer->halt)) { 28*31cf6336SKozlowski Mateusz return false; 29*31cf6336SKozlowski Mateusz } 30*31cf6336SKozlowski Mateusz 31*31cf6336SKozlowski Mateusz return writer->band->md->state == FTL_BAND_STATE_OPEN; 32*31cf6336SKozlowski Mateusz } 33*31cf6336SKozlowski Mateusz 34*31cf6336SKozlowski Mateusz void 35*31cf6336SKozlowski Mateusz ftl_writer_band_state_change(struct ftl_band *band) 36*31cf6336SKozlowski Mateusz { 37*31cf6336SKozlowski Mateusz struct ftl_writer *writer = band->owner.priv; 38*31cf6336SKozlowski Mateusz 39*31cf6336SKozlowski Mateusz switch (band->md->state) { 40*31cf6336SKozlowski Mateusz case FTL_BAND_STATE_FULL: 41*31cf6336SKozlowski Mateusz assert(writer->band == band); 42*31cf6336SKozlowski Mateusz TAILQ_INSERT_TAIL(&writer->full_bands, band, queue_entry); 43*31cf6336SKozlowski Mateusz writer->band = NULL; 44*31cf6336SKozlowski Mateusz break; 45*31cf6336SKozlowski Mateusz 46*31cf6336SKozlowski Mateusz case FTL_BAND_STATE_CLOSED: 47*31cf6336SKozlowski Mateusz assert(writer->num_bands > 0); 48*31cf6336SKozlowski Mateusz writer->num_bands--; 49*31cf6336SKozlowski Mateusz ftl_band_clear_owner(band, ftl_writer_band_state_change, writer); 50*31cf6336SKozlowski Mateusz break; 51*31cf6336SKozlowski Mateusz 52*31cf6336SKozlowski Mateusz default: 53*31cf6336SKozlowski Mateusz break; 54*31cf6336SKozlowski Mateusz } 55*31cf6336SKozlowski Mateusz } 56*31cf6336SKozlowski Mateusz 57*31cf6336SKozlowski Mateusz static void 58*31cf6336SKozlowski Mateusz close_full_bands(struct ftl_writer *writer) 59*31cf6336SKozlowski Mateusz { 60*31cf6336SKozlowski Mateusz struct ftl_band *band, *next; 61*31cf6336SKozlowski Mateusz 62*31cf6336SKozlowski Mateusz TAILQ_FOREACH_SAFE(band, &writer->full_bands, queue_entry, next) { 63*31cf6336SKozlowski Mateusz if (band->queue_depth) { 64*31cf6336SKozlowski Mateusz continue; 65*31cf6336SKozlowski Mateusz } 66*31cf6336SKozlowski Mateusz 67*31cf6336SKozlowski Mateusz TAILQ_REMOVE(&writer->full_bands, band, queue_entry); 68*31cf6336SKozlowski Mateusz ftl_band_close(band); 69*31cf6336SKozlowski Mateusz } 70*31cf6336SKozlowski Mateusz } 71*31cf6336SKozlowski Mateusz 72*31cf6336SKozlowski Mateusz static bool 73*31cf6336SKozlowski Mateusz is_active(struct ftl_writer *writer) 74*31cf6336SKozlowski Mateusz { 75*31cf6336SKozlowski Mateusz if (writer->dev->limit < writer->limit) { 76*31cf6336SKozlowski Mateusz return false; 77*31cf6336SKozlowski Mateusz } 78*31cf6336SKozlowski Mateusz 79*31cf6336SKozlowski Mateusz return true; 80*31cf6336SKozlowski Mateusz } 81*31cf6336SKozlowski Mateusz 82*31cf6336SKozlowski Mateusz static struct ftl_band * 83*31cf6336SKozlowski Mateusz get_band(struct ftl_writer *writer) 84*31cf6336SKozlowski Mateusz { 85*31cf6336SKozlowski Mateusz if (spdk_unlikely(!writer->band)) { 86*31cf6336SKozlowski Mateusz if (!is_active(writer)) { 87*31cf6336SKozlowski Mateusz return NULL; 88*31cf6336SKozlowski Mateusz } 89*31cf6336SKozlowski Mateusz 90*31cf6336SKozlowski Mateusz if (spdk_unlikely(NULL != writer->next_band)) { 91*31cf6336SKozlowski Mateusz if (FTL_BAND_STATE_OPEN == writer->next_band->md->state) { 92*31cf6336SKozlowski Mateusz writer->band = writer->next_band; 93*31cf6336SKozlowski Mateusz writer->next_band = NULL; 94*31cf6336SKozlowski Mateusz 95*31cf6336SKozlowski Mateusz return writer->band; 96*31cf6336SKozlowski Mateusz } else { 97*31cf6336SKozlowski Mateusz assert(FTL_BAND_STATE_OPEN == writer->next_band->md->state); 98*31cf6336SKozlowski Mateusz ftl_abort(); 99*31cf6336SKozlowski Mateusz } 100*31cf6336SKozlowski Mateusz } 101*31cf6336SKozlowski Mateusz 102*31cf6336SKozlowski Mateusz writer->band = ftl_band_get_next_free(writer->dev); 103*31cf6336SKozlowski Mateusz if (writer->band) { 104*31cf6336SKozlowski Mateusz writer->num_bands++; 105*31cf6336SKozlowski Mateusz ftl_band_set_owner(writer->band, 106*31cf6336SKozlowski Mateusz ftl_writer_band_state_change, writer); 107*31cf6336SKozlowski Mateusz 108*31cf6336SKozlowski Mateusz if (ftl_band_write_prep(writer->band)) { 109*31cf6336SKozlowski Mateusz /* 110*31cf6336SKozlowski Mateusz * This error might happen due to allocation failure. However number 111*31cf6336SKozlowski Mateusz * of open bands is controlled and it should have enough resources 112*31cf6336SKozlowski Mateusz * to do it. So here is better to perform a crash and recover from 113*31cf6336SKozlowski Mateusz * shared memory to bring back stable state. 114*31cf6336SKozlowski Mateusz * */ 115*31cf6336SKozlowski Mateusz ftl_abort(); 116*31cf6336SKozlowski Mateusz } 117*31cf6336SKozlowski Mateusz } else { 118*31cf6336SKozlowski Mateusz return NULL; 119*31cf6336SKozlowski Mateusz } 120*31cf6336SKozlowski Mateusz } 121*31cf6336SKozlowski Mateusz 122*31cf6336SKozlowski Mateusz if (spdk_likely(writer->band->md->state == FTL_BAND_STATE_OPEN)) { 123*31cf6336SKozlowski Mateusz return writer->band; 124*31cf6336SKozlowski Mateusz } else { 125*31cf6336SKozlowski Mateusz if (spdk_unlikely(writer->band->md->state == FTL_BAND_STATE_PREP)) { 126*31cf6336SKozlowski Mateusz ftl_band_open(writer->band, writer->writer_type); 127*31cf6336SKozlowski Mateusz } 128*31cf6336SKozlowski Mateusz return NULL; 129*31cf6336SKozlowski Mateusz } 130*31cf6336SKozlowski Mateusz } 131*31cf6336SKozlowski Mateusz 132*31cf6336SKozlowski Mateusz void 133*31cf6336SKozlowski Mateusz ftl_writer_run(struct ftl_writer *writer) 134*31cf6336SKozlowski Mateusz { 135*31cf6336SKozlowski Mateusz struct ftl_band *band; 136*31cf6336SKozlowski Mateusz struct ftl_rq *rq; 137*31cf6336SKozlowski Mateusz 138*31cf6336SKozlowski Mateusz close_full_bands(writer); 139*31cf6336SKozlowski Mateusz 140*31cf6336SKozlowski Mateusz if (!TAILQ_EMPTY(&writer->rq_queue)) { 141*31cf6336SKozlowski Mateusz band = get_band(writer); 142*31cf6336SKozlowski Mateusz if (spdk_unlikely(!band)) { 143*31cf6336SKozlowski Mateusz return; 144*31cf6336SKozlowski Mateusz } 145*31cf6336SKozlowski Mateusz 146*31cf6336SKozlowski Mateusz if (!can_write(writer)) { 147*31cf6336SKozlowski Mateusz return; 148*31cf6336SKozlowski Mateusz } 149*31cf6336SKozlowski Mateusz 150*31cf6336SKozlowski Mateusz /* Finally we can write to band */ 151*31cf6336SKozlowski Mateusz rq = TAILQ_FIRST(&writer->rq_queue); 152*31cf6336SKozlowski Mateusz TAILQ_REMOVE(&writer->rq_queue, rq, qentry); 153*31cf6336SKozlowski Mateusz ftl_band_rq_write(writer->band, rq); 154*31cf6336SKozlowski Mateusz } 155*31cf6336SKozlowski Mateusz } 156*31cf6336SKozlowski Mateusz 157*31cf6336SKozlowski Mateusz bool 158*31cf6336SKozlowski Mateusz ftl_writer_is_halted(struct ftl_writer *writer) 159*31cf6336SKozlowski Mateusz { 160*31cf6336SKozlowski Mateusz if (spdk_unlikely(!TAILQ_EMPTY(&writer->full_bands))) { 161*31cf6336SKozlowski Mateusz return false; 162*31cf6336SKozlowski Mateusz } 163*31cf6336SKozlowski Mateusz 164*31cf6336SKozlowski Mateusz if (writer->band) { 165*31cf6336SKozlowski Mateusz if (writer->band->md->state != FTL_BAND_STATE_OPEN) { 166*31cf6336SKozlowski Mateusz return false; 167*31cf6336SKozlowski Mateusz } 168*31cf6336SKozlowski Mateusz 169*31cf6336SKozlowski Mateusz if (writer->band->queue_depth) { 170*31cf6336SKozlowski Mateusz return false; 171*31cf6336SKozlowski Mateusz } 172*31cf6336SKozlowski Mateusz } 173*31cf6336SKozlowski Mateusz 174*31cf6336SKozlowski Mateusz return writer->halt; 175*31cf6336SKozlowski Mateusz } 176*31cf6336SKozlowski Mateusz 177*31cf6336SKozlowski Mateusz uint64_t 178*31cf6336SKozlowski Mateusz ftl_writer_get_free_blocks(struct ftl_writer *writer) 179*31cf6336SKozlowski Mateusz { 180*31cf6336SKozlowski Mateusz uint64_t free_blocks = 0; 181*31cf6336SKozlowski Mateusz 182*31cf6336SKozlowski Mateusz if (writer->band) { 183*31cf6336SKozlowski Mateusz free_blocks += ftl_band_user_blocks_left(writer->band, 184*31cf6336SKozlowski Mateusz writer->band->md->iter.offset); 185*31cf6336SKozlowski Mateusz } 186*31cf6336SKozlowski Mateusz 187*31cf6336SKozlowski Mateusz if (writer->next_band) { 188*31cf6336SKozlowski Mateusz free_blocks += ftl_band_user_blocks_left(writer->next_band, 189*31cf6336SKozlowski Mateusz writer->next_band->md->iter.offset); 190*31cf6336SKozlowski Mateusz } 191*31cf6336SKozlowski Mateusz 192*31cf6336SKozlowski Mateusz return free_blocks; 193*31cf6336SKozlowski Mateusz } 194