1beacf11bSopenharmony_ci/****************************************************************************
2beacf11bSopenharmony_ci * drivers/bch/bchlib_write.c
3beacf11bSopenharmony_ci *
4beacf11bSopenharmony_ci * Licensed to the Apache Software Foundation (ASF) under one or more
5beacf11bSopenharmony_ci * contributor license agreements.  See the NOTICE file distributed with
6beacf11bSopenharmony_ci * this work for additional information regarding copyright ownership.  The
7beacf11bSopenharmony_ci * ASF licenses this file to you under the Apache License, Version 2.0 (the
8beacf11bSopenharmony_ci * "License"); you may not use this file except in compliance with the
9beacf11bSopenharmony_ci * License.  You may obtain a copy of the License at
10beacf11bSopenharmony_ci *
11beacf11bSopenharmony_ci *   http://www.apache.org/licenses/LICENSE-2.0
12beacf11bSopenharmony_ci *
13beacf11bSopenharmony_ci * Unless required by applicable law or agreed to in writing, software
14beacf11bSopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15beacf11bSopenharmony_ci * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
16beacf11bSopenharmony_ci * License for the specific language governing permissions and limitations
17beacf11bSopenharmony_ci * under the License.
18beacf11bSopenharmony_ci *
19beacf11bSopenharmony_ci ****************************************************************************/
20beacf11bSopenharmony_ci
21beacf11bSopenharmony_ci/****************************************************************************
22beacf11bSopenharmony_ci * Included Files
23beacf11bSopenharmony_ci ****************************************************************************/
24beacf11bSopenharmony_ci#include <sys/types.h>
25beacf11bSopenharmony_ci#include <stdint.h>
26beacf11bSopenharmony_ci#include <stdbool.h>
27beacf11bSopenharmony_ci#include <string.h>
28beacf11bSopenharmony_ci#include <errno.h>
29beacf11bSopenharmony_ci#include <assert.h>
30beacf11bSopenharmony_ci#include "bch.h"
31beacf11bSopenharmony_ci
32beacf11bSopenharmony_ci/****************************************************************************
33beacf11bSopenharmony_ci * Public Functions
34beacf11bSopenharmony_ci ****************************************************************************/
35beacf11bSopenharmony_ci
36beacf11bSopenharmony_ci/****************************************************************************
37beacf11bSopenharmony_ci * Name: bchlib_write
38beacf11bSopenharmony_ci *
39beacf11bSopenharmony_ci * Description:
40beacf11bSopenharmony_ci *   Write to the block device set-up by bchlib_setup as if it were a character
41beacf11bSopenharmony_ci *   device.
42beacf11bSopenharmony_ci *
43beacf11bSopenharmony_ci ****************************************************************************/
44beacf11bSopenharmony_ci
45beacf11bSopenharmony_cissize_t bchlib_write(void *handle, const char *buffer, loff_t offset, size_t len)
46beacf11bSopenharmony_ci{
47beacf11bSopenharmony_ci  struct bchlib_s *bch = (struct bchlib_s *)handle;
48beacf11bSopenharmony_ci  size_t   nsectors;
49beacf11bSopenharmony_ci  unsigned long long   sector;
50beacf11bSopenharmony_ci  uint16_t sectoffset;
51beacf11bSopenharmony_ci  size_t   nbytes;
52beacf11bSopenharmony_ci  size_t   byteswritten;
53beacf11bSopenharmony_ci  int      ret;
54beacf11bSopenharmony_ci
55beacf11bSopenharmony_ci  /* Get rid of this special case right away */
56beacf11bSopenharmony_ci
57beacf11bSopenharmony_ci  if (len < 1)
58beacf11bSopenharmony_ci    {
59beacf11bSopenharmony_ci      return 0;
60beacf11bSopenharmony_ci    }
61beacf11bSopenharmony_ci
62beacf11bSopenharmony_ci  /* Convert the file position into a sector number and offset. */
63beacf11bSopenharmony_ci
64beacf11bSopenharmony_ci  sector     = offset / bch->sectsize;
65beacf11bSopenharmony_ci  sectoffset = offset - sector * bch->sectsize;
66beacf11bSopenharmony_ci
67beacf11bSopenharmony_ci  if (sector >= bch->nsectors)
68beacf11bSopenharmony_ci    {
69beacf11bSopenharmony_ci      return 0;
70beacf11bSopenharmony_ci    }
71beacf11bSopenharmony_ci
72beacf11bSopenharmony_ci  /* Write the initial partial sector */
73beacf11bSopenharmony_ci
74beacf11bSopenharmony_ci  byteswritten = 0;
75beacf11bSopenharmony_ci  if (sectoffset > 0)
76beacf11bSopenharmony_ci    {
77beacf11bSopenharmony_ci      /* Read the full sector into the sector buffer */
78beacf11bSopenharmony_ci
79beacf11bSopenharmony_ci      ret = bchlib_readsector(bch, sector + bch->sectstart);
80beacf11bSopenharmony_ci      if (ret < 0)
81beacf11bSopenharmony_ci        {
82beacf11bSopenharmony_ci          return byteswritten;
83beacf11bSopenharmony_ci        }
84beacf11bSopenharmony_ci
85beacf11bSopenharmony_ci      /* Copy the tail end of the sector from the user buffer */
86beacf11bSopenharmony_ci
87beacf11bSopenharmony_ci      if (sectoffset + len > bch->sectsize)
88beacf11bSopenharmony_ci        {
89beacf11bSopenharmony_ci          nbytes = bch->sectsize - sectoffset;
90beacf11bSopenharmony_ci        }
91beacf11bSopenharmony_ci      else
92beacf11bSopenharmony_ci        {
93beacf11bSopenharmony_ci          nbytes = len;
94beacf11bSopenharmony_ci        }
95beacf11bSopenharmony_ci
96beacf11bSopenharmony_ci      ret = LOS_CopyToKernel(&bch->buffer[sectoffset], nbytes, buffer, nbytes);
97beacf11bSopenharmony_ci      if (ret != EOK)
98beacf11bSopenharmony_ci        {
99beacf11bSopenharmony_ci          PRINTK("ERROR: bchlib_write failed: %d\n", ret);
100beacf11bSopenharmony_ci          return byteswritten;
101beacf11bSopenharmony_ci        }
102beacf11bSopenharmony_ci      bch->dirty = true;
103beacf11bSopenharmony_ci
104beacf11bSopenharmony_ci      /* Adjust pointers and counts */
105beacf11bSopenharmony_ci
106beacf11bSopenharmony_ci      sector++;
107beacf11bSopenharmony_ci
108beacf11bSopenharmony_ci      if (sector >= bch->nsectors)
109beacf11bSopenharmony_ci        {
110beacf11bSopenharmony_ci          return nbytes;
111beacf11bSopenharmony_ci        }
112beacf11bSopenharmony_ci
113beacf11bSopenharmony_ci      byteswritten  = nbytes;
114beacf11bSopenharmony_ci      buffer       += nbytes;
115beacf11bSopenharmony_ci      len          -= nbytes;
116beacf11bSopenharmony_ci    }
117beacf11bSopenharmony_ci
118beacf11bSopenharmony_ci  /* Then write all of the full sectors following the partial sector
119beacf11bSopenharmony_ci   * directly from the user buffer.
120beacf11bSopenharmony_ci   */
121beacf11bSopenharmony_ci
122beacf11bSopenharmony_ci  if (len >= bch->sectsize)
123beacf11bSopenharmony_ci    {
124beacf11bSopenharmony_ci      nsectors = len / bch->sectsize;
125beacf11bSopenharmony_ci      if (sector + nsectors > bch->nsectors)
126beacf11bSopenharmony_ci        {
127beacf11bSopenharmony_ci          nsectors = bch->nsectors - sector;
128beacf11bSopenharmony_ci        }
129beacf11bSopenharmony_ci
130beacf11bSopenharmony_ci      /* Flush the dirty sector to keep the sector sequence */
131beacf11bSopenharmony_ci
132beacf11bSopenharmony_ci      ret = bchlib_flushsector(bch);
133beacf11bSopenharmony_ci      if (ret < 0)
134beacf11bSopenharmony_ci        {
135beacf11bSopenharmony_ci          PRINTK("ERROR: Flush failed: %d\n", ret);
136beacf11bSopenharmony_ci          return ret;
137beacf11bSopenharmony_ci        }
138beacf11bSopenharmony_ci
139beacf11bSopenharmony_ci      /* Write the contiguous sectors */
140beacf11bSopenharmony_ci
141beacf11bSopenharmony_ci      ret = los_disk_write(bch->disk->disk_id, (const void *)buffer,
142beacf11bSopenharmony_ci                           sector + bch->sectstart, nsectors);
143beacf11bSopenharmony_ci      if (ret < 0)
144beacf11bSopenharmony_ci        {
145beacf11bSopenharmony_ci          PRINTK("ERROR: Write failed: %d\n", ret);
146beacf11bSopenharmony_ci          return byteswritten;
147beacf11bSopenharmony_ci        }
148beacf11bSopenharmony_ci
149beacf11bSopenharmony_ci      /* Adjust pointers and counts */
150beacf11bSopenharmony_ci
151beacf11bSopenharmony_ci      sector       += nsectors;
152beacf11bSopenharmony_ci      nbytes        = nsectors * bch->sectsize;
153beacf11bSopenharmony_ci      byteswritten += nbytes;
154beacf11bSopenharmony_ci
155beacf11bSopenharmony_ci      if (sector >= bch->nsectors)
156beacf11bSopenharmony_ci        {
157beacf11bSopenharmony_ci          return byteswritten;
158beacf11bSopenharmony_ci        }
159beacf11bSopenharmony_ci
160beacf11bSopenharmony_ci      buffer    += nbytes;
161beacf11bSopenharmony_ci      len       -= nbytes;
162beacf11bSopenharmony_ci    }
163beacf11bSopenharmony_ci
164beacf11bSopenharmony_ci  /* Then write any partial final sector */
165beacf11bSopenharmony_ci
166beacf11bSopenharmony_ci  if (len > 0)
167beacf11bSopenharmony_ci    {
168beacf11bSopenharmony_ci      /* Read the sector into the sector buffer */
169beacf11bSopenharmony_ci
170beacf11bSopenharmony_ci      ret = bchlib_readsector(bch, sector + bch->sectstart);
171beacf11bSopenharmony_ci      if (ret < 0)
172beacf11bSopenharmony_ci        {
173beacf11bSopenharmony_ci          return byteswritten;
174beacf11bSopenharmony_ci        }
175beacf11bSopenharmony_ci
176beacf11bSopenharmony_ci      /* Copy the head end of the sector from the user buffer */
177beacf11bSopenharmony_ci
178beacf11bSopenharmony_ci      ret = LOS_CopyToKernel(bch->buffer, len, buffer, len);
179beacf11bSopenharmony_ci      if (ret != EOK)
180beacf11bSopenharmony_ci        {
181beacf11bSopenharmony_ci          PRINTK("ERROR: bchlib_write failed: %d\n", ret);
182beacf11bSopenharmony_ci          return byteswritten;
183beacf11bSopenharmony_ci        }
184beacf11bSopenharmony_ci      bch->dirty = true;
185beacf11bSopenharmony_ci
186beacf11bSopenharmony_ci      /* Adjust counts */
187beacf11bSopenharmony_ci
188beacf11bSopenharmony_ci      byteswritten += len;
189beacf11bSopenharmony_ci    }
190beacf11bSopenharmony_ci
191beacf11bSopenharmony_ci  return byteswritten;
192beacf11bSopenharmony_ci}
193beacf11bSopenharmony_ci
194