| 1 | /* | 
|---|
| 2 |  * blkio.c - provides per-page buffers I/O | 
|---|
| 3 |  *  | 
|---|
| 4 |  * Copyright (c) 2008,2009,2010,2011,2012 Ghassan Almaless | 
|---|
| 5 |  * Copyright (c) 2011,2012 UPMC Sorbonne Universites | 
|---|
| 6 |  * | 
|---|
| 7 |  * This file is part of ALMOS-kernel. | 
|---|
| 8 |  * | 
|---|
| 9 |  * ALMOS-kernel is free software; you can redistribute it and/or modify it | 
|---|
| 10 |  * under the terms of the GNU General Public License as published by | 
|---|
| 11 |  * the Free Software Foundation; version 2.0 of the License. | 
|---|
| 12 |  * | 
|---|
| 13 |  * ALMOS-kernel is distributed in the hope that it will be useful, but | 
|---|
| 14 |  * WITHOUT ANY WARRANTY; without even the implied warranty of | 
|---|
| 15 |  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | 
|---|
| 16 |  * General Public License for more details. | 
|---|
| 17 |  * | 
|---|
| 18 |  * You should have received a copy of the GNU General Public License | 
|---|
| 19 |  * along with ALMOS-kernel; if not, write to the Free Software Foundation, | 
|---|
| 20 |  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | 
|---|
| 21 |  */ | 
|---|
| 22 |  | 
|---|
| 23 | #include <cpu.h> | 
|---|
| 24 | #include <errno.h> | 
|---|
| 25 | #include <scheduler.h> | 
|---|
| 26 | #include <kmem.h> | 
|---|
| 27 | #include <thread.h> | 
|---|
| 28 | #include <device.h> | 
|---|
| 29 | #include <driver.h> | 
|---|
| 30 | #include <event.h> | 
|---|
| 31 | #include <atomic.h> | 
|---|
| 32 | #include <cluster.h> | 
|---|
| 33 | #include <page.h> | 
|---|
| 34 | #include <blkio.h> | 
|---|
| 35 |  | 
|---|
| 36 | static EVENT_HANDLER(blkio_async) | 
|---|
| 37 | { | 
|---|
| 38 |         struct blkio_s *blkio; | 
|---|
| 39 |         struct blkio_s *info; | 
|---|
| 40 |         struct page_s *page; | 
|---|
| 41 |         struct thread_s *thread; | 
|---|
| 42 |         error_t err; | 
|---|
| 43 |         uint_t irq_state; | 
|---|
| 44 |  | 
|---|
| 45 |         blkio = event_get_argument(event); | 
|---|
| 46 |         page  = blkio->b_page; | 
|---|
| 47 |         info  = list_head(&page->root, struct blkio_s, b_list); | 
|---|
| 48 |         err   = event_get_error(event); | 
|---|
| 49 |  | 
|---|
| 50 |         if(err) | 
|---|
| 51 |         { | 
|---|
| 52 |                 printk(WARNING, "WARNING: %s: Requested I/O is failed, blk %d\n",  | 
|---|
| 53 |                        __FUNCTION__,  | 
|---|
| 54 |                        blkio->b_dev_rq.src); | 
|---|
| 55 |         } | 
|---|
| 56 |  | 
|---|
| 57 |         err = (err) ? 1 : 0; | 
|---|
| 58 |  | 
|---|
| 59 |         spinlock_lock_noirq(&info->b_ctrl.lock, &irq_state); | 
|---|
| 60 |  | 
|---|
| 61 |         info->b_ctrl.cntr ++; | 
|---|
| 62 |         info->b_ctrl.error = (info->b_ctrl.error) ? 1 : err; | 
|---|
| 63 |  | 
|---|
| 64 |         if(info->b_ctrl.cntr == info->b_ctrl.count)  | 
|---|
| 65 |         { | 
|---|
| 66 |                 thread = wakeup_one(&info->b_ctrl.wait, WAIT_ANY); | 
|---|
| 67 |  | 
|---|
| 68 | #if CONFIG_BLKIO_DEBUG     | 
|---|
| 69 |                 if(thread != NULL) | 
|---|
| 70 |                 { | 
|---|
| 71 |                         printk(INFO, "%s: cpu %d, wakeup tid %d on cpu %d [%u]\n", | 
|---|
| 72 |                                __FUNCTION__, | 
|---|
| 73 |                                cpu_get_id(), | 
|---|
| 74 |                                thread->info.order, | 
|---|
| 75 |                                thread_current_cpu(thread)->gid, | 
|---|
| 76 |                                cpu_time_stamp()); | 
|---|
| 77 |                 } | 
|---|
| 78 | #endif | 
|---|
| 79 |         } | 
|---|
| 80 |  | 
|---|
| 81 |         spinlock_unlock_noirq(&info->b_ctrl.lock, irq_state); | 
|---|
| 82 |         return 0; | 
|---|
| 83 | } | 
|---|
| 84 |  | 
|---|
| 85 | static void blkio_ctor(struct kcm_s *kcm, void *ptr)  | 
|---|
| 86 | { | 
|---|
| 87 |         struct blkio_s *blkio = (struct blkio_s *)ptr; | 
|---|
| 88 |  | 
|---|
| 89 |         spinlock_init(&blkio->b_ctrl.lock, "BlkIO"); | 
|---|
| 90 |         event_set_handler(&blkio->b_dev_rq.event, blkio_async); | 
|---|
| 91 |         event_set_priority(&blkio->b_dev_rq.event, E_BLK); | 
|---|
| 92 |         event_set_argument(&blkio->b_dev_rq.event, blkio); | 
|---|
| 93 |         wait_queue_init(&blkio->b_ctrl.wait, "BLKIO Sync"); | 
|---|
| 94 | } | 
|---|
| 95 |  | 
|---|
| 96 | KMEM_OBJATTR_INIT(blkio_kmem_init) | 
|---|
| 97 | { | 
|---|
| 98 |         attr->type = KMEM_BLKIO; | 
|---|
| 99 |         attr->name = "KCM BLKIO"; | 
|---|
| 100 |         attr->size = sizeof(struct blkio_s); | 
|---|
| 101 |         attr->aligne = 0; | 
|---|
| 102 |         attr->min = CONFIG_BLKIO_MIN; | 
|---|
| 103 |         attr->max = CONFIG_BLKIO_MAX; | 
|---|
| 104 |         attr->ctor = blkio_ctor; | 
|---|
| 105 |         attr->dtor = NULL; | 
|---|
| 106 |         return 0; | 
|---|
| 107 | } | 
|---|
| 108 |  | 
|---|
| 109 | /////////////////////////////////// | 
|---|
| 110 | error_t blkio_init( device_t * dev, | 
|---|
| 111 |                     page_t   * page, | 
|---|
| 112 |                     uint32_t   count )  | 
|---|
| 113 | { | 
|---|
| 114 |         kmem_req_t req; | 
|---|
| 115 |         struct blkio_s *blkio; | 
|---|
| 116 |         uint_t blkio_nr; | 
|---|
| 117 |  | 
|---|
| 118 |         req.type  = KMEM_BLKIO; | 
|---|
| 119 |         req.size  = sizeof(*blkio); | 
|---|
| 120 |         req.flags = AF_KERNEL; | 
|---|
| 121 |    | 
|---|
| 122 |         slist_root_init(&page->root); | 
|---|
| 123 |         blkio_nr = count; | 
|---|
| 124 |  | 
|---|
| 125 | #if CONFIG_BLKIO_DEBUG     | 
|---|
| 126 |         printk(INFO, "%s: cpu %d, count %d, pg @0x%x, index %d [%d]\n", | 
|---|
| 127 |                __FUNCTION__,  | 
|---|
| 128 |                cpu_get_id(), | 
|---|
| 129 |                count,  | 
|---|
| 130 |                page,  | 
|---|
| 131 |                page->index, | 
|---|
| 132 |                cpu_time_stamp()); | 
|---|
| 133 | #endif | 
|---|
| 134 |  | 
|---|
| 135 |         while(count) | 
|---|
| 136 |         { | 
|---|
| 137 |                 if((blkio = kmem_alloc(&req)) == NULL)  | 
|---|
| 138 |                 { | 
|---|
| 139 |                         blkio_destroy(page); | 
|---|
| 140 |                         return ENOMEM; | 
|---|
| 141 |                 } | 
|---|
| 142 |      | 
|---|
| 143 |                 blkio->b_flags = 0; | 
|---|
| 144 |                 blkio->b_page  = page; | 
|---|
| 145 |                 blkio->b_dev   = dev; | 
|---|
| 146 |  | 
|---|
| 147 |                 list_push(&page->root, &blkio->b_list); | 
|---|
| 148 |                 count -= 1; | 
|---|
| 149 |         } | 
|---|
| 150 |  | 
|---|
| 151 |         blkio = list_head(&page->root, struct blkio_s, b_list); | 
|---|
| 152 |  | 
|---|
| 153 |         blkio->b_ctrl.count = blkio_nr; | 
|---|
| 154 |         blkio->b_ctrl.cntr  = 0; | 
|---|
| 155 |         blkio->b_ctrl.error = 0; | 
|---|
| 156 |  | 
|---|
| 157 |         PAGE_SET(page, PG_BUFFER); | 
|---|
| 158 |         return 0; | 
|---|
| 159 | }  // end blkio_init() | 
|---|
| 160 |  | 
|---|
| 161 |  | 
|---|
| 162 | //////////////////////////////////// | 
|---|
| 163 | error_t blkio_sync( page_t   * page, | 
|---|
| 164 |                     uint32_t   flags )  | 
|---|
| 165 | { | 
|---|
| 166 |         slist_entry_t    * iter; | 
|---|
| 167 |         blkio_t          * blkio; | 
|---|
| 168 |         blkio_t          * info; | 
|---|
| 169 |         device_request_t * handler; | 
|---|
| 170 |         error_t            err; | 
|---|
| 171 |         uint32_t           irq_state; | 
|---|
| 172 |         uint32_t           cntr; | 
|---|
| 173 |  | 
|---|
| 174 |         info = list_head(&page->root, struct blkio_s, b_list); | 
|---|
| 175 |         handler = (flags & BLKIO_RD) ? info->b_dev->op.dev.read : info->b_dev->op.dev.write; | 
|---|
| 176 |         cntr =  0; | 
|---|
| 177 |         err =  0; | 
|---|
| 178 |  | 
|---|
| 179 |         list_foreach(&page->root, iter)  | 
|---|
| 180 |         { | 
|---|
| 181 |                 blkio = list_element(iter, struct blkio_s, b_list); | 
|---|
| 182 |  | 
|---|
| 183 |                 if(blkio->b_flags & BLKIO_INIT) | 
|---|
| 184 |                 { | 
|---|
| 185 |                         blkio->b_flags &= ~BLKIO_INIT; | 
|---|
| 186 |                         continue; | 
|---|
| 187 |                 } | 
|---|
| 188 |  | 
|---|
| 189 |                 blkio->b_dev_rq.flags = DEV_RQ_NOBLOCK; | 
|---|
| 190 |  | 
|---|
| 191 | #if CONFIG_BLKIO_DEBUG   | 
|---|
| 192 |                 printk(INFO, "%s: cpu %d, Submitting blkio #%d, src %d, dst %x [%d]\n", | 
|---|
| 193 |                        __FUNCTION__,  | 
|---|
| 194 |                        cpu_get_id(), | 
|---|
| 195 |                        cntr,  | 
|---|
| 196 |                        blkio->b_dev_rq.src,  | 
|---|
| 197 |                        blkio->b_dev_rq.dst,  | 
|---|
| 198 |                        cpu_time_stamp()); | 
|---|
| 199 | #endif | 
|---|
| 200 |  | 
|---|
| 201 |                 err = handler(blkio->b_dev, &blkio->b_dev_rq); | 
|---|
| 202 |      | 
|---|
| 203 |                 if(err < 0)  | 
|---|
| 204 |                 { | 
|---|
| 205 |                         err = EIO; | 
|---|
| 206 |                         break; | 
|---|
| 207 |                 } | 
|---|
| 208 |  | 
|---|
| 209 |                 cntr ++; | 
|---|
| 210 |         } | 
|---|
| 211 |  | 
|---|
| 212 |         if(flags & BLKIO_SYNC)  | 
|---|
| 213 |         { | 
|---|
| 214 |                 spinlock_lock_noirq(&info->b_ctrl.lock, &irq_state); | 
|---|
| 215 |      | 
|---|
| 216 |                 info->b_ctrl.cntr += (info->b_ctrl.count - cntr); | 
|---|
| 217 |  | 
|---|
| 218 |                 if(info->b_ctrl.cntr < info->b_ctrl.count)  | 
|---|
| 219 |                 { | 
|---|
| 220 |                         wait_on(&info->b_ctrl.wait, WAIT_ANY); | 
|---|
| 221 |                         spinlock_unlock_noirq(&info->b_ctrl.lock, irq_state); | 
|---|
| 222 |                         sched_sleep(CURRENT_THREAD); | 
|---|
| 223 |  | 
|---|
| 224 | #if CONFIG_BLKIO_DEBUG | 
|---|
| 225 |                         printk(INFO, "%s: cpu %d, tid %d, blkio ended, err %d\n", | 
|---|
| 226 |                                __FUNCTION__,  | 
|---|
| 227 |                                cpu_get_id(),  | 
|---|
| 228 |                                CURRENT_THREAD->info.order,  | 
|---|
| 229 |                                info->b_ctrl.error); | 
|---|
| 230 | #endif | 
|---|
| 231 |  | 
|---|
| 232 |                 } | 
|---|
| 233 |                 else | 
|---|
| 234 |                         spinlock_unlock_noirq(&info->b_ctrl.lock, irq_state); | 
|---|
| 235 |  | 
|---|
| 236 |                 return (info->b_ctrl.error) ? EIO : 0; | 
|---|
| 237 |         } | 
|---|
| 238 |  | 
|---|
| 239 |         return err; | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | ////////////////////////////////////////// | 
|---|
| 243 | error_t blkio_destroy(struct page_s *page)  | 
|---|
| 244 | { | 
|---|
| 245 |         kmem_req_t req; | 
|---|
| 246 |         struct slist_entry *iter; | 
|---|
| 247 |  | 
|---|
| 248 |         req.type = KMEM_BLKIO; | 
|---|
| 249 |  | 
|---|
| 250 |         list_foreach(&page->root, iter)  | 
|---|
| 251 |         { | 
|---|
| 252 |                 req.ptr = list_element(iter, struct blkio_s, b_list); | 
|---|
| 253 |                 kmem_free(&req); | 
|---|
| 254 |         } | 
|---|
| 255 |  | 
|---|
| 256 |         page->private = 0; | 
|---|
| 257 |         PAGE_CLEAR(page, PG_BUFFER); | 
|---|
| 258 |         return 0; | 
|---|
| 259 | } | 
|---|