1 /* 2 * Copyright 2013, Jérôme Duval, korli@users.berlios.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "VirtioSCSIPrivate.h" 8 9 #include <new> 10 #include <stdlib.h> 11 #include <string.h> 12 13 14 #define VIRTIO_SCSI_ID_GENERATOR "virtio_scsi/id" 15 #define VIRTIO_SCSI_ID_ITEM "virtio_scsi/id" 16 #define VIRTIO_SCSI_BRIDGE_PRETTY_NAME "Virtio SCSI Bridge" 17 #define VIRTIO_SCSI_CONTROLLER_PRETTY_NAME "Virtio SCSI Controller" 18 19 #define VIRTIO_SCSI_DEVICE_MODULE_NAME "busses/scsi/virtio_scsi/driver_v1" 20 #define VIRTIO_SCSI_SIM_MODULE_NAME "busses/scsi/virtio_scsi/sim/driver_v1" 21 22 23 device_manager_info *gDeviceManager; 24 scsi_for_sim_interface *gSCSI; 25 26 27 // #pragma mark - SIM module interface 28 29 30 static void 31 set_scsi_bus(scsi_sim_cookie cookie, scsi_bus bus) 32 { 33 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 34 sim->SetBus(bus); 35 } 36 37 38 static void 39 scsi_io(scsi_sim_cookie cookie, scsi_ccb *request) 40 { 41 CALLED(); 42 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 43 if (sim->ExecuteRequest(request) == B_BUSY) 44 gSCSI->requeue(request, true); 45 } 46 47 48 static uchar 49 abort_io(scsi_sim_cookie cookie, scsi_ccb *request) 50 { 51 CALLED(); 52 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 53 return sim->AbortRequest(request); 54 } 55 56 57 static uchar 58 reset_device(scsi_sim_cookie cookie, uchar targetID, uchar targetLUN) 59 { 60 CALLED(); 61 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 62 return sim->ResetDevice(targetID, targetLUN); 63 } 64 65 66 static uchar 67 terminate_io(scsi_sim_cookie cookie, scsi_ccb *request) 68 { 69 CALLED(); 70 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 71 return sim->TerminateRequest(request); 72 } 73 74 75 static uchar 76 path_inquiry(scsi_sim_cookie cookie, scsi_path_inquiry *info) 77 { 78 CALLED(); 79 80 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 81 if (sim->Bus() == NULL) 82 return SCSI_NO_HBA; 83 84 sim->PathInquiry(info); 85 return SCSI_REQ_CMP; 86 } 87 88 89 //! this is called immediately before the SCSI bus manager scans the bus 90 static uchar 91 scan_bus(scsi_sim_cookie cookie) 92 { 93 CALLED(); 94 95 return SCSI_REQ_CMP; 96 } 97 98 99 static uchar 100 reset_bus(scsi_sim_cookie cookie) 101 { 102 CALLED(); 103 104 return SCSI_REQ_CMP; 105 } 106 107 108 /*! Get restrictions of one device 109 (used for non-SCSI transport protocols and bug fixes) 110 */ 111 static void 112 get_restrictions(scsi_sim_cookie cookie, uchar targetID, bool *isATAPI, 113 bool *noAutoSense, uint32 *maxBlocks) 114 { 115 CALLED(); 116 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 117 sim->GetRestrictions(targetID, isATAPI, noAutoSense, maxBlocks); 118 } 119 120 121 static status_t 122 ioctl(scsi_sim_cookie cookie, uint8 targetID, uint32 op, void *buffer, 123 size_t length) 124 { 125 CALLED(); 126 VirtioSCSIController *sim = (VirtioSCSIController *)cookie; 127 return sim->Control(targetID, op, buffer, length); 128 } 129 130 131 // #pragma mark - 132 133 134 static status_t 135 sim_init_bus(device_node *node, void **_cookie) 136 { 137 CALLED(); 138 139 VirtioSCSIController *controller = new(std::nothrow) 140 VirtioSCSIController(node); 141 if (controller == NULL) 142 return B_NO_MEMORY; 143 status_t status = controller->InitCheck(); 144 if (status < B_OK) { 145 delete controller; 146 return status; 147 } 148 149 *_cookie = controller; 150 return B_OK; 151 } 152 153 154 static void 155 sim_uninit_bus(void *cookie) 156 { 157 CALLED(); 158 VirtioSCSIController *controller = (VirtioSCSIController*)cookie; 159 160 delete controller; 161 } 162 163 164 // #pragma mark - 165 166 167 static float 168 virtio_scsi_supports_device(device_node *parent) 169 { 170 const char *bus; 171 uint16 deviceType; 172 173 // make sure parent is really the Virtio bus manager 174 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)) 175 return -1; 176 177 if (strcmp(bus, "virtio")) 178 return 0.0; 179 180 // check whether it's really a Virtio SCSI Device 181 if (gDeviceManager->get_attr_uint16(parent, VIRTIO_DEVICE_TYPE_ITEM, 182 &deviceType, true) != B_OK || deviceType != VIRTIO_DEVICE_ID_SCSI) 183 return 0.0; 184 185 TRACE("Virtio SCSI device found!\n"); 186 187 return 0.6f; 188 } 189 190 191 static status_t 192 virtio_scsi_register_device(device_node *parent) 193 { 194 CALLED(); 195 virtio_device_interface* virtio = NULL; 196 virtio_device* virtioDevice = NULL; 197 struct virtio_scsi_config config; 198 199 gDeviceManager->get_driver(parent, (driver_module_info **)&virtio, 200 (void **)&virtioDevice); 201 202 status_t status = virtio->read_device_config(virtioDevice, 0, &config, 203 sizeof(struct virtio_scsi_config)); 204 if (status != B_OK) 205 return status; 206 207 uint32 max_targets = config.max_target + 1; 208 uint32 max_luns = config.max_lun + 1; 209 uint32 max_blocks = 0x10000; 210 if (config.max_sectors != 0) 211 max_blocks = config.max_sectors; 212 213 device_attr attrs[] = { 214 { SCSI_DEVICE_MAX_TARGET_COUNT, B_UINT32_TYPE, 215 { .ui32 = max_targets }}, 216 { SCSI_DEVICE_MAX_LUN_COUNT, B_UINT32_TYPE, 217 { .ui32 = max_luns }}, 218 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 219 { .string = VIRTIO_SCSI_BRIDGE_PRETTY_NAME }}, 220 221 // DMA properties 222 { B_DMA_MAX_SEGMENT_BLOCKS, B_UINT32_TYPE, { .ui32 = max_blocks }}, 223 { B_DMA_MAX_SEGMENT_COUNT, B_UINT32_TYPE, 224 { .ui32 = config.seg_max }}, 225 { NULL } 226 }; 227 228 return gDeviceManager->register_node(parent, VIRTIO_SCSI_DEVICE_MODULE_NAME, 229 attrs, NULL, NULL); 230 } 231 232 233 static status_t 234 virtio_scsi_init_driver(device_node *node, void **_cookie) 235 { 236 CALLED(); 237 *_cookie = node; 238 return B_OK; 239 } 240 241 242 static status_t 243 virtio_scsi_register_child_devices(void *cookie) 244 { 245 CALLED(); 246 device_node *node = (device_node *)cookie; 247 248 int32 id = gDeviceManager->create_id(VIRTIO_SCSI_ID_GENERATOR); 249 if (id < 0) 250 return id; 251 252 device_attr attrs[] = { 253 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE, 254 { .string = SCSI_FOR_SIM_MODULE_NAME }}, 255 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE, 256 { .string = VIRTIO_SCSI_CONTROLLER_PRETTY_NAME }}, 257 { SCSI_DESCRIPTION_CONTROLLER_NAME, B_STRING_TYPE, 258 { .string = VIRTIO_SCSI_DEVICE_MODULE_NAME }}, 259 { B_DMA_MAX_TRANSFER_BLOCKS, B_UINT32_TYPE, { .ui32 = 255 }}, 260 { VIRTIO_SCSI_ID_ITEM, B_UINT32_TYPE, { .ui32 = (uint32)id }}, 261 { NULL } 262 }; 263 264 status_t status = gDeviceManager->register_node(node, 265 VIRTIO_SCSI_SIM_MODULE_NAME, attrs, NULL, NULL); 266 if (status < B_OK) 267 gDeviceManager->free_id(VIRTIO_SCSI_ID_GENERATOR, id); 268 269 return status; 270 } 271 272 273 static status_t 274 std_ops(int32 op, ...) 275 { 276 switch (op) { 277 case B_MODULE_INIT: 278 case B_MODULE_UNINIT: 279 return B_OK; 280 281 default: 282 return B_ERROR; 283 } 284 } 285 286 287 static scsi_sim_interface sVirtioSCSISimInterface = { 288 { 289 { 290 VIRTIO_SCSI_SIM_MODULE_NAME, 291 0, 292 std_ops 293 }, 294 NULL, // supported devices 295 NULL, // register node 296 sim_init_bus, 297 sim_uninit_bus, 298 NULL, // register child devices 299 NULL, // rescan 300 NULL // bus_removed 301 }, 302 set_scsi_bus, 303 scsi_io, 304 abort_io, 305 reset_device, 306 terminate_io, 307 path_inquiry, 308 scan_bus, 309 reset_bus, 310 get_restrictions, 311 ioctl 312 }; 313 314 315 static driver_module_info sVirtioSCSIDevice = { 316 { 317 VIRTIO_SCSI_DEVICE_MODULE_NAME, 318 0, 319 std_ops 320 }, 321 virtio_scsi_supports_device, 322 virtio_scsi_register_device, 323 virtio_scsi_init_driver, 324 NULL, // uninit_driver, 325 virtio_scsi_register_child_devices, 326 NULL, // rescan 327 NULL, // device_removed 328 }; 329 330 331 module_dependency module_dependencies[] = { 332 { B_DEVICE_MANAGER_MODULE_NAME, (module_info **)&gDeviceManager }, 333 { SCSI_FOR_SIM_MODULE_NAME, (module_info **)&gSCSI }, 334 {} 335 }; 336 337 338 module_info *modules[] = { 339 (module_info *)&sVirtioSCSIDevice, 340 (module_info *)&sVirtioSCSISimInterface, 341 NULL 342 }; 343